Compare commits

...

33 Commits

Author SHA1 Message Date
ec4fd08a7d Update package-lock.json, unsure why 2025-07-03 09:47:26 -04:00
40388b80e7 Remove circular dependency, avoid adding 2 new ones 2025-07-03 09:47:05 -04:00
4b00d00977 Update snapshots 2025-07-03 09:47:05 -04:00
fc574fa638 Tiny CSS fix 2025-07-03 09:47:05 -04:00
0bea2bcc98 Rework top bar to not include toolbar
Closes #7679 by creating a definite top bar, and moving the toolbar
below it. Still side-steps the E2E test issue by allowing the modeling
scene extend under this top bar. I will finally address this in the next
step, which is bringing back a proper sidebar that doesn't overlay the
modeling scene.

I have a fast-follow PR coming that adds visual undo and redo buttons to
this top bar, but I wanted to keep them separate.
2025-07-03 09:47:05 -04:00
a1059d547a Fix conflict 2025-07-03 09:47:05 -04:00
e4b40f6d36 Rework top bar to not include toolbar
Closes #7679 by creating a definite top bar, and moving the toolbar
below it. Still side-steps the E2E test issue by allowing the modeling
scene extend under this top bar. I will finally address this in the next
step, which is bringing back a proper sidebar that doesn't overlay the
modeling scene.

I have a fast-follow PR coming that adds visual undo and redo buttons to
this top bar, but I wanted to keep them separate.
2025-07-03 09:47:05 -04:00
e5d082f441 [Chore] Removing old confusing BASE_URL environment variable. (#7678)
chore: this is deprecated, we should be using the VITE_KC_*_BASE_URL workflows
2025-07-02 22:51:01 +00:00
d4d3e179b1 Update test data (#7674) 2025-07-02 15:04:03 -07:00
4f4c44e7c7 KCL: Getter for axes of planes (#7662)
## Goal

Currently, there's no way in KCL to get fields of a plane, e.g. the underlying X axis, Y axis or origin.

This would be useful for geometry calculations in KCL. It would help KCL users write transformations between planes for rotating geometry.

For example, this enables

```kcl
export fn crossProduct(@vectors) {
  a = vectors[0]
  b = vectors[1]
  x = a[1] * b[2] - (a[2] * b[1])
  y = a[2] * b[0] - (a[0] * b[2])
  z = a[0] * b[1] - (a[1] * b[0])
  return [x, y, z]
}

export fn normalOf(@plane) {
  return crossProduct([plane.xAxis, plane.yAxis])
}
```

## Implementation

My goal was just to enable a simple getter for planes, like `myPlane.xAxis` and yAxis and origins. That's nearly what happened, except I discovered that there's two ways to represent a plane: either `KclValue::Plane` or `KclValue::Object` with the right fields.

No matter which format your plane is represented as, it should behave consistently when you get its properties. Those properties should be returned as `[number; 3]` because that is how KCL represents points.

Unfortunately we actually require planes-as-objects to be defined with axes like `myPlane = { xAxis = { x = 1, y = 0, z = 0 }, ...}`, but that's a mistake in my opinion. So if you do use that representation of a plane, it should still return a [number; 3]. This required some futzing around so that we let you access object fields .x and .y as [0] and [1], which is weird, but whatever, I think it's good.

This PR is tested via planestuff.kcl which has a Rust unit test.

Part of the hole efforts, see https://github.com/KittyCAD/modeling-app/discussions/7543
2025-07-02 16:24:26 +00:00
1b75020686 Remove unused code to skip auth (#7280) 2025-07-02 14:49:34 +00:00
fba62dab98 Add parsing arrays and objects as binary operands (#7661)
* Add parsing arrays and objects as binary operands

* Add sim test showing the error message
2025-07-01 23:33:36 +00:00
a85a534d6b Release KCL 84 (#7653) 2025-07-01 15:15:35 -04:00
6ddbb7a31d Fix unknown property error message on sketches and solids (#7632)
* Fix unknown property error message on sketches and solids

* Add suggestion for common case

* Move test code in file to avoid conflict
2025-07-01 18:37:01 +00:00
051bb0589e KCL: rectangle function (#7616)
* KCL test for rectangle

* Rectangle function

* Rectangle helper tests

* Rectangle helper

* Fix clippy lints

* Update docs

* fmt

* Fix bug

* fmt

* Fix doc comments

* Update generated docs

---------

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-07-01 14:26:04 -04:00
7f9851ae28 [Chore]: Added url-checker, updated circular-deps, documented new static analysis .txt pattern (#7442)
* fix: ignoring url checker files

* fix: url checker

* fix: auto fmt and cleanup

* fix: moving the bash scripts and known files into the scripts repo

* fix: removed all url_results and made it be all in memory

* fix: fixed the newline issue

* fix: url checking as a step to the static analysis

* fix: removed old code

* chore: writing documentation on our static checker pattern

* fix: updating the docs more to be clearer

* fix: copy and paste without understanding requirements of ci cd dependencies? do i need all of these?

* fix: updating

* fix: I thought this got in?

* Update CONTRIBUTING.md

Co-authored-by: Jace Browning <jacebrowning@gmail.com>

---------

Co-authored-by: Jace Browning <jacebrowning@gmail.com>
2025-07-01 13:01:42 -05:00
fbcbb341e2 KCL: Add planeOf function to stdlib (#7643)
Gets the plane a face lies on, if any.

Closes #7642
2025-07-01 17:42:12 +00:00
4a080d1583 Bump @types/node from 22.15.32 to 24.0.3 in /packages/codemirror-lsp-client in the major group (#7490)
Bump @types/node in /packages/codemirror-lsp-client in the major group

Bumps the major group in /packages/codemirror-lsp-client with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


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

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.0.3
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-07-01 12:01:45 -04:00
85c721fb49 Add display of units for calculated KCL values (#7619)
* Add display of units in UI modals with calculated KCL values

* Fix command bar display to handle units

* Add display of units in the command bar

* Fix more cases of NaN from units

* Fix to support explicit plus for exponent in scientific notation

* Fix display in autocomplete

* Change to parseFloat to be more resilient

* Add e2e test for command bar

* Change an existing test to use explicit inline units

* Fix case when input string can't be parsed
2025-06-30 15:26:45 -04:00
27af2d08a3 Bump the patch group in /rust with 3 updates (#7575)
* Bump the patch group in /rust with 3 updates

Bumps the patch group in /rust with 3 updates: [toml_edit](https://github.com/toml-rs/toml), [syn](https://github.com/dtolnay/syn) and [toml](https://github.com/toml-rs/toml).


Updates `toml_edit` from 0.22.26 to 0.22.27
- [Commits](https://github.com/toml-rs/toml/compare/v0.22.26...v0.22.27)

Updates `syn` from 2.0.103 to 2.0.104
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.103...2.0.104)

Updates `toml` from 0.8.22 to 0.8.23
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.22...toml-v0.8.23)

---
updated-dependencies:
- dependency-name: toml_edit
  dependency-version: 0.22.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: syn
  dependency-version: 2.0.104
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: toml
  dependency-version: 0.8.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Trigger CI

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-06-30 12:09:43 -04:00
fb8b975b5e Bump esbuild from 0.25.2 to 0.25.3 in the security group across 1 directory (#6681)
Bump esbuild in the security group across 1 directory

Bumps the security group with 1 update in the / directory: [esbuild](https://github.com/evanw/esbuild).


Updates `esbuild` from 0.25.2 to 0.25.3
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.2...v0.25.3)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.25.3
  dependency-type: direct:development
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-30 15:40:33 +00:00
62d8d45a58 Bump the major group across 1 directory with 4 updates (#7572)
* Bump the major group across 1 directory with 4 updates

Bumps the major group with 4 updates in the / directory: [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact), [runs-on/action](https://github.com/runs-on/action), [actions/create-github-app-token](https://github.com/actions/create-github-app-token) and [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv).


Updates `dawidd6/action-download-artifact` from 7 to 11
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v7...v11)

Updates `runs-on/action` from 1 to 2
- [Release notes](https://github.com/runs-on/action/releases)
- [Commits](https://github.com/runs-on/action/compare/v1...v2)

Updates `actions/create-github-app-token` from 1 to 2
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](https://github.com/actions/create-github-app-token/compare/v1...v2)

Updates `astral-sh/setup-uv` from 5 to 6
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v5...v6)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major
- dependency-name: runs-on/action
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major
- dependency-name: actions/create-github-app-token
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major
- dependency-name: astral-sh/setup-uv
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major
...

Signed-off-by: dependabot[bot] <support@github.com>

* bump

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Ammann <max.ammann@zoo.dev>
2025-06-30 10:07:54 -04:00
ae3440df0a Use proper envs for Rust functions (#7623) 2025-06-29 07:03:36 -05:00
af658c909d Enterprise plans should not have the upgrade button (#7628)
* Enterprise plans should not have the upgrade button
Fixes #7627

* Move the check to BillingDialog

* Hide home box and change bool check

* Add component tests

* Clean up
2025-06-28 12:03:41 -04:00
7ec11d23c8 Capitalize labels in the native file menu (#7639) 2025-06-28 12:00:47 -04:00
30000a1eac Fix the vertical alignment on the temporary workspace label (#7638) 2025-06-28 13:23:47 +00:00
cb3b45747c Change AI to ML because cringe (#7636)
Change AI to ML
2025-06-27 19:44:05 +00:00
fe66310f2d Update output to match main (#7630) 2025-06-27 17:29:27 +00:00
fefb6cfe87 Rerun sim tests after #7608 (#7624) 2025-06-27 10:21:30 -04:00
0f8375cbb4 [BUG] offsetPlane back-side startSketchOn (#7622)
offset backPlane selection bug
2025-06-27 21:36:42 +10:00
107adc77b3 Allow the origin of rotation to be specified (#7608)
* pass axis origin to endpoint

* fmt

* fix lint errors

* update sim tests with new transform endpoint

* added missed files

* revert cargo.toml

* implement review requests

* fmt

* revert unnecessary custom origin
2025-06-27 00:38:18 +01:00
4356885aa2 Bump cargo to 1.88; 2024 edition for kcl-lib (#7618)
This is a big one because the edition changes a fair number of things.
2025-06-26 22:02:54 +00:00
6a2027cd51 Keep subtract solids selection to one until engine supports multiple (#7617)
Follow up to #7614
2025-06-26 21:36:05 +00:00
306 changed files with 9340 additions and 2180 deletions

View File

@ -7,7 +7,6 @@ VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000
#VITE_WASM_URL="optional way of overriding the wasm url, particular for unit tests which need this if you running not on the default 3000 port"
#VITE_KC_DEV_TOKEN="optional token to skip auth in the app"

View File

@ -3,5 +3,4 @@ VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.zoo.dev
VITE_KC_SITE_BASE_URL=https://zoo.dev
VITE_KC_SITE_APP_URL=https://app.zoo.dev
VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=15000

View File

@ -43,7 +43,7 @@ jobs:
- name: Download Wasm Cache
id: download-wasm
if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
uses: dawidd6/action-download-artifact@v11
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}

View File

@ -25,8 +25,8 @@ jobs:
- runner=8cpu-linux-x64
- extras=s3-cache
steps:
- uses: runs-on/action@v1
- uses: actions/create-github-app-token@v1
- uses: runs-on/action@v2
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -149,8 +149,8 @@ jobs:
partitionIndex: [1, 2, 3, 4, 5, 6]
partitionTotal: [6]
steps:
- uses: runs-on/action@v1
- uses: actions/create-github-app-token@v1
- uses: runs-on/action@v2
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -207,8 +207,8 @@ jobs:
- runner=32cpu-linux-x64
- extras=s3-cache
steps:
- uses: runs-on/action@v1
- uses: actions/create-github-app-token@v1
- uses: runs-on/action@v2
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}

View File

@ -46,7 +46,7 @@ jobs:
- name: Download Wasm cache
id: download-wasm
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
uses: dawidd6/action-download-artifact@v11
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
@ -110,7 +110,7 @@ jobs:
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -230,7 +230,7 @@ jobs:
steps:
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}

View File

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
# required

View File

@ -113,7 +113,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: taiki-e/install-action@just
- name: Run tests
@ -130,7 +130,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v6
- name: Install codespell
run: |
uv venv .venv
@ -161,7 +161,7 @@ jobs:
with:
path: rust/kcl-python-bindings
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v6
- name: do uv things
run: |
cd rust/kcl-python-bindings

View File

@ -120,6 +120,36 @@ jobs:
- run: npm run circular-deps:diff
npm-url-checker:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run url-checker:diff
python-codespell:
runs-on: ubuntu-22.04
steps:

View File

@ -235,6 +235,47 @@ To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log s
To enable memory metrics, build with `--features dhat-heap`.
## Running scripts
There are multiple scripts under the folder path `./scripts` which can be used in various settings.
### Pattern for a static file, npm run commands, and CI-CD checks
If you want to implement a static checker follow this pattern. Two static checkers we have are circular dependency checks in our typescript code and url checker to see if any hard coded URL is the typescript application 404s. We have a set of known files in `./scripts/known/*.txt` which is the baseline.
If you improve the baseline, run the overwrite command and commit the new smaller baseline. Try not to make the baseline bigger, the CI CD will complain.
These baselines are to hold us to higher standards and help implement automated testing against the repository
#### Output result to stdout
- `npm run circular-deps`
- `npm run url-checker`
- create a `<name>.sh` file that will run the static checker then output the result to `stdout`
#### Overwrite result to known .txt file on disk
If the application needs to overwrite the known file on disk use this pattern. This known .txt file will be source controlled as the baseline
- `npm run circular-deps:overwrite`
- `npm run url-checker:overwrite`
#### Diff baseline and current
These commands will write a /tmp/ file on disk and compare it to the known file in the repository. This command will also be used in the CI CD pipeline for automated checks
- create a `diff-<name>.sh` file that is the script to diff your tmp file to the baseline
e.g. `diff-url-checker.sh`
```bash
#!/bin/bash
set -euo pipefail
npm run url-checker > /tmp/urls.txt
diff --ignore-blank-lines -w /tmp/urls.txt ./scripts/known/urls.txt
```
- `npm run circular-deps:diff`
- `npm run url-checker:diff`
## Proposing changes
Before you submit a contribution PR to this repo, please ensure that:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -67,10 +67,12 @@ layout: manual
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
* [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d)
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
* [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf)
* [`polygon`](/docs/kcl-std/functions/std-sketch-polygon)
* [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart)
* [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX)
* [`profileStartY`](/docs/kcl-std/functions/std-sketch-profileStartY)
* [`rectangle`](/docs/kcl-std/functions/std-sketch-rectangle)
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
* [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
* [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)

View File

@ -32,10 +32,12 @@ This module contains functions for creating and manipulating sketches, and makin
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
* [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d)
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
* [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf)
* [`polygon`](/docs/kcl-std/functions/std-sketch-polygon)
* [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart)
* [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX)
* [`profileStartY`](/docs/kcl-std/functions/std-sketch-profileStartY)
* [`rectangle`](/docs/kcl-std/functions/std-sketch-rectangle)
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
* [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
* [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)

View File

@ -5,6 +5,7 @@ import { uuidv4 } from '@src/lib/utils'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
@ -14,13 +15,18 @@ test.describe('Can create sketches on all planes and their back sides', () => {
homePage: HomePageFixture,
scene: SceneFixture,
toolbar: ToolbarFixture,
cmdBar: CmdBarFixture,
plane: string,
clickCoords: { x: number; y: number }
) => {
const u = await getUtils(page)
// await page.addInitScript(() => {
// localStorage.setItem('persistCode', '@settings(defaultLengthUnit = in)')
// })
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// await scene.settled(cmdBar)
const XYPlanRed: [number, number, number] = [98, 50, 51]
await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15)
@ -119,12 +125,166 @@ test.describe('Can create sketches on all planes and their back sides', () => {
]
for (const config of planeConfigs) {
test(config.plane, async ({ page, homePage, scene, toolbar }) => {
test(config.plane, async ({ page, homePage, scene, toolbar, cmdBar }) => {
await sketchOnPlaneAndBackSideTest(
page,
homePage,
scene,
toolbar,
cmdBar,
config.plane,
config.coords
)
})
}
})
test.describe('Can create sketches on offset planes and their back sides', () => {
const sketchOnPlaneAndBackSideTest = async (
page: Page,
homePage: HomePageFixture,
scene: SceneFixture,
toolbar: ToolbarFixture,
cmdbar: CmdBarFixture,
plane: string,
clickCoords: { x: number; y: number }
) => {
const u = await getUtils(page)
await page.addInitScript(() => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
xyPlane = offsetPlane(XY, offset = 0.05)
xzPlane = offsetPlane(XZ, offset = 0.05)
yzPlane = offsetPlane(YZ, offset = 0.05)
`
)
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// await scene.settled(cmdbar)
const XYPlanRed: [number, number, number] = [74, 74, 74]
await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15)
await u.openDebugPanel()
const coord =
plane === '-XY' || plane === '-YZ' || plane === 'XZ' ? -100 : 100
const camCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
center: { x: 0, y: 0, z: 0 },
vantage: { x: coord, y: coord, z: coord },
up: { x: 0, y: 0, z: 1 },
},
}
const updateCamCommand: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
}
const prefix = plane.length === 3 ? '-' : ''
const planeName = plane
.slice(plane.length === 3 ? 1 : 0)
.toLocaleLowerCase()
const codeLine1 = `sketch001 = startSketchOn(${prefix}${planeName}Plane)`
const codeLine2 = `profile001 = startProfile(sketch001, at = [${0.91 + (plane[0] === '-' ? 0.01 : 0)}, -${1.21 + (plane[0] === '-' ? 0.01 : 0)}])`
await u.openDebugPanel()
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await u.sendCustomCmd(camCommand)
await page.waitForTimeout(100)
await u.sendCustomCmd(updateCamCommand)
await u.closeDebugPanel()
await toolbar.openFeatureTreePane()
await toolbar.getDefaultPlaneVisibilityButton('XY').click()
await toolbar.getDefaultPlaneVisibilityButton('XZ').click()
await toolbar.getDefaultPlaneVisibilityButton('YZ').click()
await expect(
toolbar
.getDefaultPlaneVisibilityButton('YZ')
.locator('[aria-label="eye crossed out"]')
).toBeVisible()
await page.mouse.click(clickCoords.x, clickCoords.y)
await page.waitForTimeout(600) // wait for animation
await toolbar.waitUntilSketchingReady()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).toBeVisible()
await u.closeDebugPanel()
await page.mouse.click(707, 393)
await expect(page.locator('.cm-content')).toContainText(codeLine1)
await expect(page.locator('.cm-content')).toContainText(codeLine2)
await page
.getByRole('button', { name: 'line Line', exact: true })
.first()
.click()
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearCommandLogs()
await u.removeCurrentCode()
}
const planeConfigs = [
{
plane: 'XY',
coords: { x: 600, y: 388 },
description: 'red plane',
},
{
plane: 'YZ',
coords: { x: 700, y: 250 },
description: 'green plane',
},
{
plane: 'XZ',
coords: { x: 684, y: 427 },
description: 'blue plane',
},
{
plane: '-XY',
coords: { x: 600, y: 118 },
description: 'back of red plane',
},
{
plane: '-YZ',
coords: { x: 700, y: 219 },
description: 'back of green plane',
},
{
plane: '-XZ',
coords: { x: 700, y: 80 },
description: 'back of blue plane',
},
]
for (const config of planeConfigs) {
test(config.plane, async ({ page, homePage, scene, toolbar, cmdBar }) => {
await sketchOnPlaneAndBackSideTest(
page,
homePage,
scene,
toolbar,
cmdBar,
config.plane,
config.coords
)

View File

@ -525,7 +525,9 @@ test.describe('Command bar tests', () => {
const projectName = 'test'
const beforeKclCode = `a = 5
b = a * a
c = 3 + a`
c = 3 + a
theta = 45deg
`
await context.folderSetupFn(async (dir) => {
const testProject = join(dir, projectName)
await fsp.mkdir(testProject, { recursive: true })
@ -615,9 +617,45 @@ c = 3 + a`
stage: 'commandBarClosed',
})
})
await test.step(`Edit a parameter with explicit units via command bar`, async () => {
await cmdBar.cmdBarOpenBtn.click()
await cmdBar.chooseCommand('edit parameter')
await cmdBar
.selectOption({
name: 'theta',
})
.click()
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Edit parameter',
currentArgKey: 'value',
currentArgValue: '45deg',
headerArguments: {
Name: 'theta',
Value: '',
},
highlightedHeaderArg: 'value',
})
await cmdBar.argumentInput
.locator('[contenteditable]')
.fill('45deg + 1deg')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
commandName: 'Edit parameter',
headerArguments: {
Name: 'theta',
Value: '46deg',
},
})
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'commandBarClosed',
})
})
await editor.expectEditor.toContain(
`a = 5b = a * amyParameter001 = ${newValue}c = 3 + a`
`a = 5b = a * amyParameter001 = ${newValue}c = 3 + atheta = 45deg + 1deg`
)
})

View File

@ -274,6 +274,13 @@ export class ToolbarFixture {
.nth(operationIndex)
}
getDefaultPlaneVisibilityButton(plane: 'XY' | 'XZ' | 'YZ' = 'XY') {
const index = plane === 'XZ' ? 0 : plane === 'XY' ? 1 : 2
return this.featureTreePane
.getByTestId('feature-tree-visibility-toggle')
.nth(index)
}
/**
* View source on a specific operation in the Feature Tree pane.
* @param operationName The name of the operation type

View File

@ -136,17 +136,17 @@ test.describe('Point-and-click tests', () => {
highlightedHeaderArg: 'length',
commandName: 'Extrude',
})
await page.keyboard.insertText('width - 0.001')
await page.keyboard.insertText('width - 0.001in')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Length: '4.999',
Length: '4.999in',
},
commandName: 'Extrude',
})
await cmdBar.progressCmdBar()
await editor.expectEditor.toContain('extrude(length = width - 0.001)')
await editor.expectEditor.toContain('extrude(length = width - 0.001in)')
})
await test.step(`Edit second extrude via feature tree`, async () => {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 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: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

18
flake.lock generated
View File

@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1745998881,
"narHash": "sha256-vonyYAKJSlsX4n9GCsS0pHxR6yCrfqBIuGvANlkwG6U=",
"lastModified": 1750865895,
"narHash": "sha256-p2dWAQcLVzquy9LxYCZPwyUdugw78Qv3ChvnX755qHA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "423d2df5b04b4ee7688c3d71396e872afa236a89",
"rev": "61c0f513911459945e2cb8bf333dc849f1b976ff",
"type": "github"
},
"original": {
@ -36,11 +36,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1745998881,
"narHash": "sha256-vonyYAKJSlsX4n9GCsS0pHxR6yCrfqBIuGvANlkwG6U=",
"lastModified": 1750865895,
"narHash": "sha256-p2dWAQcLVzquy9LxYCZPwyUdugw78Qv3ChvnX755qHA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "423d2df5b04b4ee7688c3d71396e872afa236a89",
"rev": "61c0f513911459945e2cb8bf333dc849f1b976ff",
"type": "github"
},
"original": {
@ -78,11 +78,11 @@
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1745980514,
"narHash": "sha256-CITAeiuXGjDvT5iZBXr6vKVWQwsUQLJUMFO91bfJFC4=",
"lastModified": 1750964660,
"narHash": "sha256-YQ6EyFetjH1uy5JhdhRdPe6cuNXlYpMAQePFfZj4W7M=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "7fbdae44b0f40ea432e46fd152ad8be0f8f41ad6",
"rev": "04f0fcfb1a50c63529805a798b4b5c21610ff390",
"type": "github"
},
"original": {

2
interface.d.ts vendored
View File

@ -72,14 +72,12 @@ export interface IElectronAPI {
}
process: {
env: {
BASE_URL: string
IS_PLAYWRIGHT: string
VITE_KC_DEV_TOKEN: string
VITE_KC_API_WS_MODELING_URL: string
VITE_KC_API_BASE_URL: string
VITE_KC_SITE_BASE_URL: string
VITE_KC_SITE_APP_URL: string
VITE_KC_SKIP_AUTH: string
VITE_KC_CONNECTION_TIMEOUT_MS: string
VITE_KC_DEV_TOKEN: string
NODE_ENV: string

View File

@ -125,18 +125,57 @@ test('Shows a loading spinner when uninitialized credit count', async () => {
await expect(queryByTestId('spinner')).toBeVisible()
})
test('Shows the total credits for Unknown subscription', async () => {
const data = {
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 25,
},
subscriptions: {
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "unknown",
}
const unKnownTierData = {
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 25,
},
subscriptions: {
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "unknown",
}
}
const freeTierData = {
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "free",
}
}
const proTierData = {
// These are all ignored
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
// This should be ignored because it's Pro tier.
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "pro",
}
}
const enterpriseTierData = {
// These are all ignored, user is part of an org.
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
// This should be ignored because it's Pro tier.
monthlyPayAsYouGoApiCreditsTotal: 20,
// This should be ignored because the user is part of an Org.
name: "free",
}
}
test('Shows the total credits for Unknown subscription', async () => {
const data = unKnownTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@ -166,17 +205,7 @@ test('Shows the total credits for Unknown subscription', async () => {
})
test('Progress bar reflects ratio left of Free subscription', async () => {
const data = {
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "free",
}
}
const data = freeTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@ -212,19 +241,7 @@ test('Progress bar reflects ratio left of Free subscription', async () => {
})
})
test('Shows infinite credits for Pro subscription', async () => {
const data = {
// These are all ignored
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
// This should be ignored because it's Pro tier.
monthlyPayAsYouGoApiCreditsTotal: 20,
name: "pro",
}
}
const data = proTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@ -255,19 +272,7 @@ test('Shows infinite credits for Pro subscription', async () => {
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
})
test('Shows infinite credits for Enterprise subscription', async () => {
const data = {
// These are all ignored, user is part of an org.
balance: {
monthlyApiCreditsRemaining: 10,
stableApiCreditsRemaining: 0,
},
subscriptions: {
// This should be ignored because it's Pro tier.
monthlyPayAsYouGoApiCreditsTotal: 20,
// This should be ignored because the user is part of an Org.
name: "free",
}
}
const data = enterpriseTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
@ -297,3 +302,58 @@ test('Shows infinite credits for Enterprise subscription', async () => {
await expect(queryByTestId('infinity')).toBeVisible()
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
})
test('Show upgrade button if credits are not infinite', async () => {
const data = freeTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
}),
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
}),
http.get('*/org', (req, res, ctx) => {
return new HttpResponse(403)
}),
)
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
const { queryByTestId } = render(<BillingDialog
billingActor={billingActor}
/>)
await act(() => {
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
})
await expect(queryByTestId('billing-upgrade-button')).toBeVisible()
})
test('Hide upgrade button if credits are infinite', async () => {
const data = enterpriseTierData
server.use(
http.get('*/user/payment/balance', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
}),
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
}),
// Ok finally the first use of an org lol
http.get('*/org', (req, res, ctx) => {
return HttpResponse.json(createOrgResponse())
}),
)
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
const { queryByTestId } = render(<BillingDialog
billingActor={billingActor}
/>)
await act(() => {
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
})
await expect(queryByTestId('billing-upgrade-button')).toBe(null)
})

1137
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -110,8 +110,11 @@
"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\"",
"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",
"url-checker":"./scripts/url-checker.sh",
"url-checker:overwrite":"npm run url-checker > scripts/known/urls.txt",
"url-checker:diff":"./scripts/diff-url-checker.sh",
"circular-deps": "dpdm --no-warning --no-tree -T --skip-dynamic-imports=circular src/index.tsx",
"circular-deps:overwrite": "npm run circular-deps | sed '$d' | grep -v '^npm run' > known-circular.txt",
"circular-deps:overwrite": "npm run circular-deps | sed '$d' | grep -v '^npm run' > scripts/known/circular.txt",
"circular-deps:diff": "./scripts/diff-circular-deps.sh",
"circular-deps:diff:nodejs": "npm run circular-deps:diff || node ./scripts/diff.js",
"files:set-version": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json",

View File

@ -29,7 +29,7 @@
"vscode-uri": "^3.1.0"
},
"devDependencies": {
"@types/node": "^22.14.1",
"@types/node": "^24.0.7",
"ts-node": "^10.9.2"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

144
rust/Cargo.lock generated
View File

@ -178,7 +178,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -189,7 +189,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -211,7 +211,7 @@ checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -514,7 +514,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -740,7 +740,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -751,7 +751,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -810,7 +810,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -831,7 +831,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -841,7 +841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -906,7 +906,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -944,7 +944,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -1119,7 +1119,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -1223,7 +1223,7 @@ dependencies = [
"inflections",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -1599,7 +1599,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -1814,7 +1814,7 @@ dependencies = [
[[package]]
name = "kcl-bumper"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anyhow",
"clap",
@ -1825,26 +1825,26 @@ dependencies = [
[[package]]
name = "kcl-derive-docs"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
name = "kcl-directory-test-macro"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
name = "kcl-language-server"
version = "0.2.83"
version = "0.2.84"
dependencies = [
"anyhow",
"clap",
@ -1865,7 +1865,7 @@ dependencies = [
[[package]]
name = "kcl-language-server-release"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anyhow",
"clap",
@ -1885,7 +1885,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.2.83"
version = "0.2.84"
dependencies = [
"anyhow",
"approx 0.5.1",
@ -1962,7 +1962,7 @@ dependencies = [
[[package]]
name = "kcl-python-bindings"
version = "0.3.83"
version = "0.3.84"
dependencies = [
"anyhow",
"kcl-lib",
@ -1977,7 +1977,7 @@ dependencies = [
[[package]]
name = "kcl-test-server"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anyhow",
"hyper 0.14.32",
@ -1990,7 +1990,7 @@ dependencies = [
[[package]]
name = "kcl-to-core"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anyhow",
"async-trait",
@ -2004,7 +2004,7 @@ dependencies = [
[[package]]
name = "kcl-wasm-lib"
version = "0.1.83"
version = "0.1.84"
dependencies = [
"anyhow",
"bson",
@ -2071,9 +2071,9 @@ dependencies = [
[[package]]
name = "kittycad-modeling-cmds"
version = "0.2.124"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221aa4670a7ad7dc8f1e4e0f9990bf3cff0a64417eb76493bafe5bbbc1f8350a"
checksum = "cfd09d95f8bbeb090d4d1137c9bf421eb75763f7a30e4a9e8eefa249ddf20bd3"
dependencies = [
"anyhow",
"chrono",
@ -2104,7 +2104,7 @@ dependencies = [
"kittycad-modeling-cmds-macros-impl",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2115,7 +2115,7 @@ checksum = "fdb4ee23cc996aa2dca7584d410e8826e08161e1ac4335bb646d5ede33f37cb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2311,7 +2311,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2640,7 +2640,7 @@ dependencies = [
"regex",
"regex-syntax 0.8.5",
"structmeta",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2654,7 +2654,7 @@ dependencies = [
"regex",
"regex-syntax 0.8.5",
"structmeta",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2710,7 +2710,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2754,7 +2754,7 @@ dependencies = [
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2809,7 +2809,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2921,7 +2921,7 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2981,7 +2981,7 @@ dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -2994,7 +2994,7 @@ dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3492,7 +3492,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3556,7 +3556,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3567,7 +3567,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3591,14 +3591,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
@ -3815,7 +3815,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3826,7 +3826,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3848,7 +3848,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3891,9 +3891,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.103"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@ -3917,7 +3917,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -3941,7 +3941,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4050,7 +4050,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4061,7 +4061,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4173,7 +4173,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4217,9 +4217,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.22"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
@ -4238,9 +4238,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.26"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap 2.9.0",
"serde",
@ -4341,7 +4341,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4369,7 +4369,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4449,7 +4449,7 @@ checksum = "e9d4ed7b4c18cc150a6a0a1e9ea1ecfa688791220781af6e119f9599a8502a0a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"termcolor",
]
@ -4635,7 +4635,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -4706,7 +4706,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"wasm-bindgen-shared",
]
@ -4742,7 +4742,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -4777,7 +4777,7 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -5067,7 +5067,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"synstructure",
]
@ -5112,7 +5112,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -5123,7 +5123,7 @@ checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -5143,7 +5143,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
"synstructure",
]
@ -5164,7 +5164,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]
@ -5186,7 +5186,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.103",
"syn 2.0.104",
]
[[package]]

View File

@ -36,7 +36,7 @@ dashmap = { version = "6.1.0" }
http = "1"
indexmap = "2.9.0"
kittycad = { version = "0.3.37", default-features = false, features = ["js", "requests"] }
kittycad-modeling-cmds = { version = "0.2.124", features = ["ts-rs", "websocket"] }
kittycad-modeling-cmds = { version = "0.2.125", features = ["ts-rs", "websocket"] }
lazy_static = "1.5.0"
miette = "7.6.0"
pyo3 = { version = "0.24.2" }
@ -60,6 +60,6 @@ lossy_float_literal = "warn"
result_large_err = "allow"
# Example: how to point modeling-app at a different repo (e.g. a branch or a local clone)
#[patch.crates-io]
#kittycad-modeling-cmds = { path = "../../../modeling-api/modeling-cmds" }
#kittycad-modeling-session = { path = "../../../modeling-api/modeling-session" }
# [patch.crates-io]
# kittycad-modeling-cmds = { path = "../../modeling-api/modeling-cmds/" }
# kittycad-modeling-session = { path = "../../modeling-api/modeling-session" }

View File

@ -8,6 +8,9 @@ lint:
# Ensure we can build without extra feature flags.
cargo clippy -p kcl-lib --all-targets -- -D warnings
lint-fix:
cargo clippy --workspace --all-targets --all-features --fix
# Run the stdlib docs generation
redo-kcl-stdlib-docs-no-imgs:
EXPECTORATE=overwrite {{cnr}} {{kcl_lib_flags}} docs::gen_std_tests::test_generate_stdlib

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-bumper"
version = "0.1.83"
version = "0.1.84"
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-api"
rust-version = "1.76"
@ -19,7 +19,7 @@ anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] }
semver = "1.0.25"
serde = { workspace = true }
toml_edit = "0.22.26"
toml_edit = "0.22.27"
[lints]
workspace = true

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-derive-docs"
description = "A tool for generating documentation from Rust derive macros"
version = "0.1.83"
version = "0.1.84"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
@ -14,7 +14,7 @@ bench = false
[dependencies]
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0.103", features = ["full"] }
syn = { version = "2.0.104", features = ["full"] }
[lints]
workspace = true

View File

@ -97,8 +97,11 @@ pub const TEST_NAMES: &[&str] = &[
"std-offsetPlane-2",
"std-offsetPlane-3",
"std-offsetPlane-4",
"std-sketch-planeOf-0",
"std-sketch-circle-0",
"std-sketch-circle-1",
"std-sketch-rectangle-0",
"std-sketch-rectangle-1",
"std-sketch-patternTransform2d-0",
"std-sketch-revolve-0",
"std-sketch-revolve-1",

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-directory-test-macro"
description = "A tool for generating tests from a directory of kcl files"
version = "0.1.83"
version = "0.1.84"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
@ -14,7 +14,7 @@ bench = false
convert_case = "0.8.0"
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0.103", features = ["full"] }
syn = { version = "2.0.104", features = ["full"] }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "kcl-language-server-release"
version = "0.1.83"
version = "0.1.84"
edition = "2021"
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
publish = false

View File

@ -42,7 +42,7 @@ impl Build {
.to_string();
if !stable {
version = format!("{}-nightly", version);
version = format!("{version}-nightly");
}
let release_tag = if stable {
@ -59,10 +59,7 @@ impl Build {
if stable && !release_tag.contains(&version) {
// bail early if the tag doesn't match the version
// TODO: error here when we use the tags with kcl
println!(
"Tag {} doesn't match version {}. Did you forget to update Cargo.toml?",
release_tag, version
);
println!("Tag {release_tag} doesn't match version {version}. Did you forget to update Cargo.toml?");
}
build_server(sh, &version, &target)?;

View File

@ -95,10 +95,10 @@ async fn main() -> Result<()> {
// Format fields using the provided closure.
// We want to make this very concise otherwise the logs are not able to be read by humans.
let format = tracing_subscriber::fmt::format::debug_fn(|writer, field, value| {
if format!("{}", field) == "message" {
write!(writer, "{}: {:?}", field, value)
if format!("{field}") == "message" {
write!(writer, "{field}: {value:?}")
} else {
write!(writer, "{}", field)
write!(writer, "{field}")
}
})
// Separate each field with a comma.

View File

@ -2,7 +2,7 @@
name = "kcl-language-server"
description = "A language server for KCL."
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
version = "0.2.83"
version = "0.2.84"
edition = "2021"
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -123,7 +123,7 @@
"@vscode/test-electron": "^2.4.1",
"@vscode/vsce": "^3.3.2",
"cross-env": "^7.0.3",
"esbuild": "^0.25.2",
"esbuild": "^0.25.3",
"glob": "^11.0.1",
"mocha": "^11.1.0",
"typescript": "^5.8.3"

View File

@ -87,10 +87,10 @@ async fn main() -> Result<()> {
// Format fields using the provided closure.
// We want to make this very concise otherwise the logs are not able to be read by humans.
let format = tracing_subscriber::fmt::format::debug_fn(|writer, field, value| {
if format!("{}", field) == "message" {
write!(writer, "{}: {:?}", field, value)
if format!("{field}") == "message" {
write!(writer, "{field}: {value:?}")
} else {
write!(writer, "{}", field)
write!(writer, "{field}")
}
})
// Separate each field with a comma.
@ -151,7 +151,7 @@ async fn run_cmd(opts: &Opts) -> Result<()> {
tokio::spawn(async move {
if let Some(sig) = signals.forever().next() {
log::info!("received signal: {:?}", sig);
log::info!("received signal: {sig:?}");
log::info!("triggering cleanup...");
// Exit the process.

View File

@ -1,11 +1,11 @@
[package]
name = "kcl-lib"
description = "KittyCAD Language implementation and tools"
version = "0.2.83"
edition = "2021"
version = "0.2.84"
edition = "2024"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"
rust-version = "1.83"
rust-version = "1.88"
authors = ["Jess Frazelle", "Adam Chalmers", "KittyCAD, Inc"]
keywords = ["kcl", "KittyCAD", "CAD"]
exclude = ["tests/*", "benches/*", "examples/*", "e2e/*", "bindings/*", "fuzz/*"]
@ -74,7 +74,7 @@ sha2 = "0.10.9"
tabled = { version = "0.20.0", optional = true }
tempfile = "3.20"
thiserror = "2.0.0"
toml = "0.8.22"
toml = "0.8.23"
ts-rs = { version = "11.0.1", features = [
"uuid-impl",
"url-impl",

View File

@ -4,7 +4,7 @@ use std::{
path::{Path, PathBuf},
};
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
const IGNORE_DIRS: [&str; 2] = ["step", "screenshots"];
@ -61,7 +61,7 @@ fn run_benchmarks(c: &mut Criterion) {
// Read the file content (panic on failure)
let input_content = fs::read_to_string(&input_file)
.unwrap_or_else(|e| panic!("Failed to read main.kcl in directory {}: {}", dir_name, e));
.unwrap_or_else(|e| panic!("Failed to read main.kcl in directory {dir_name}: {e}"));
// Create a benchmark group for this directory
let mut group = c.benchmark_group(&dir_name);
@ -72,12 +72,12 @@ fn run_benchmarks(c: &mut Criterion) {
#[cfg(feature = "benchmark-execution")]
let program = kcl_lib::Program::parse_no_errs(&input_content).unwrap();
group.bench_function(format!("parse_{}", dir_name), |b| {
group.bench_function(format!("parse_{dir_name}"), |b| {
b.iter(|| kcl_lib::Program::parse_no_errs(black_box(&input_content)).unwrap())
});
#[cfg(feature = "benchmark-execution")]
group.bench_function(format!("execute_{}", dir_name), |b| {
group.bench_function(format!("execute_{dir_name}"), |b| {
b.iter(|| {
if let Err(err) = rt.block_on(async {
let ctx = kcl_lib::ExecutorContext::new_with_default_client().await?;
@ -86,7 +86,7 @@ fn run_benchmarks(c: &mut Criterion) {
ctx.close().await;
Ok::<(), anyhow::Error>(())
}) {
panic!("Failed to execute program: {}", err);
panic!("Failed to execute program: {err}");
}
})
});

View File

@ -1,6 +1,6 @@
use std::hint::black_box;
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
pub fn bench_parse(c: &mut Criterion) {
for (name, file) in [

View File

@ -1,4 +1,4 @@
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
pub fn bench_digest(c: &mut Criterion) {
for (name, file) in [

View File

@ -1,6 +1,6 @@
use std::hint::black_box;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use kcl_lib::kcl_lsp_server;
use tokio::runtime::Runtime;
use tower_lsp::LanguageServer;

View File

@ -1,9 +1,9 @@
//! Cache testing framework.
use kcl_lib::{bust_cache, ExecError, ExecOutcome};
use kcl_lib::{ExecError, ExecOutcome, bust_cache};
#[cfg(feature = "artifact-graph")]
use kcl_lib::{exec::Operation, NodePathStep};
use kcmc::{each_cmd as mcmd, ModelingCmd};
use kcl_lib::{NodePathStep, exec::Operation};
use kcmc::{ModelingCmd, each_cmd as mcmd};
use kittycad_modeling_cmds as kcmc;
use pretty_assertions::assert_eq;
@ -38,7 +38,7 @@ async fn cache_test(
if !variation.other_files.is_empty() {
let tmp_dir = std::env::temp_dir();
let tmp_dir = tmp_dir
.join(format!("kcl_test_{}", test_name))
.join(format!("kcl_test_{test_name}"))
.join(uuid::Uuid::new_v4().to_string());
// Create a temporary file for each of the other files.
@ -56,7 +56,7 @@ async fn cache_test(
Err(error) => {
let report = error.clone().into_miette_report_with_outputs(variation.code).unwrap();
let report = miette::Report::new(report);
panic!("{:?}", report);
panic!("{report:?}");
}
};
@ -69,7 +69,7 @@ async fn cache_test(
.and_then(|x| x.decode().map_err(|e| ExecError::BadPng(e.to_string())))
.unwrap();
// Save the snapshot.
let path = crate::assert_out(&format!("cache_{}_{}", test_name, index), &img);
let path = crate::assert_out(&format!("cache_{test_name}_{index}"), &img);
img_results.push((path, img, outcome));
}
@ -337,8 +337,7 @@ extrude001 = extrude(profile001, length = 4)
// 0] as a more lenient check.
.map(|c| !c.range.is_synthetic() && c.node_path.is_empty())
.unwrap_or(false),
"artifact={:?}",
artifact
"artifact={artifact:?}"
);
}
}

View File

@ -1,8 +1,8 @@
mod cache;
use kcl_lib::{
test_server::{execute_and_export_step, execute_and_snapshot, execute_and_snapshot_no_auth},
BacktraceItem, ExecError, ModuleId, SourceRange,
test_server::{execute_and_export_step, execute_and_snapshot, execute_and_snapshot_no_auth},
};
/// The minimum permissible difference between asserted twenty-twenty images.
@ -869,11 +869,13 @@ async fn kcl_test_revolve_bad_angle_low() {
let result = execute_and_snapshot(code, None).await;
assert!(result.is_err());
assert!(result
.err()
.unwrap()
.to_string()
.contains("Expected angle to be between -360 and 360 and not 0, found `-455`"));
assert!(
result
.err()
.unwrap()
.to_string()
.contains("Expected angle to be between -360 and 360 and not 0, found `-455`")
);
}
#[tokio::test(flavor = "multi_thread")]
@ -895,11 +897,13 @@ async fn kcl_test_revolve_bad_angle_high() {
let result = execute_and_snapshot(code, None).await;
assert!(result.is_err());
assert!(result
.err()
.unwrap()
.to_string()
.contains("Expected angle to be between -360 and 360 and not 0, found `455`"));
assert!(
result
.err()
.unwrap()
.to_string()
.contains("Expected angle to be between -360 and 360 and not 0, found `455`")
);
}
#[tokio::test(flavor = "multi_thread")]
@ -2090,7 +2094,10 @@ async fn kcl_test_better_type_names() {
},
None => todo!(),
};
assert_eq!(err, "This function expected the input argument to be one or more Solids or ImportedGeometry 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 or ImportedGeometry 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,71 +10,76 @@ DATA;
NAMED_UNIT(*)
SI_UNIT($, .METRE.)
);
#2 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
#3 = (
#2 = (
NAMED_UNIT(*)
PLANE_ANGLE_UNIT()
SI_UNIT($, .RADIAN.)
);
#3 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
#4 = (
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#2))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1))
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1, #2))
REPRESENTATION_CONTEXT('', '3D')
);
#4 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#5 = VERTEX_POINT('NONE', #4);
#6 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
#7 = VERTEX_POINT('NONE', #6);
#8 = DIRECTION('NONE', (1, 0, -0));
#9 = DIRECTION('NONE', (0, 1, 0));
#10 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
#11 = AXIS2_PLACEMENT_3D('NONE', #10, #9, #8);
#12 = CIRCLE('NONE', #11, 0.01);
#13 = DIRECTION('NONE', (0, 1, 0));
#14 = VECTOR('NONE', #13, 1);
#15 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#16 = LINE('NONE', #15, #14);
#17 = DIRECTION('NONE', (1, 0, -0));
#18 = DIRECTION('NONE', (0, 1, 0));
#19 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
#20 = AXIS2_PLACEMENT_3D('NONE', #19, #18, #17);
#21 = CIRCLE('NONE', #20, 0.01);
#22 = EDGE_CURVE('NONE', #5, #5, #12, .T.);
#23 = EDGE_CURVE('NONE', #5, #7, #16, .T.);
#24 = EDGE_CURVE('NONE', #7, #7, #21, .T.);
#25 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
#26 = DIRECTION('NONE', (0, 1, 0));
#27 = DIRECTION('NONE', (1, 0, -0));
#28 = AXIS2_PLACEMENT_3D('NONE', #25, #26, #27);
#29 = CYLINDRICAL_SURFACE('NONE', #28, 0.01);
#30 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
#31 = DIRECTION('NONE', (0, 1, 0));
#32 = AXIS2_PLACEMENT_3D('NONE', #30, #31, $);
#33 = PLANE('NONE', #32);
#34 = CARTESIAN_POINT('NONE', (0, 0, -0));
#35 = DIRECTION('NONE', (0, 1, 0));
#36 = AXIS2_PLACEMENT_3D('NONE', #34, #35, $);
#37 = PLANE('NONE', #36);
#38 = ORIENTED_EDGE('NONE', *, *, #22, .T.);
#39 = ORIENTED_EDGE('NONE', *, *, #24, .F.);
#40 = EDGE_LOOP('NONE', (#38));
#41 = FACE_BOUND('NONE', #40, .T.);
#42 = EDGE_LOOP('NONE', (#39));
#43 = FACE_BOUND('NONE', #42, .T.);
#44 = ADVANCED_FACE('NONE', (#41, #43), #29, .T.);
#45 = ORIENTED_EDGE('NONE', *, *, #22, .F.);
#46 = EDGE_LOOP('NONE', (#45));
#47 = FACE_BOUND('NONE', #46, .T.);
#48 = ADVANCED_FACE('NONE', (#47), #33, .F.);
#49 = ORIENTED_EDGE('NONE', *, *, #24, .T.);
#50 = EDGE_LOOP('NONE', (#49));
#51 = FACE_BOUND('NONE', #50, .T.);
#52 = ADVANCED_FACE('NONE', (#51), #37, .T.);
#53 = CLOSED_SHELL('NONE', (#44, #48, #52));
#54 = MANIFOLD_SOLID_BREP('NONE', #53);
#55 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
#56 = PRODUCT_DEFINITION_CONTEXT('part definition', #55, 'design');
#57 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
#58 = PRODUCT_DEFINITION_FORMATION('', $, #57);
#59 = PRODUCT_DEFINITION('design', $, #58, #56);
#60 = PRODUCT_DEFINITION_SHAPE('NONE', $, #59);
#61 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#54), #3);
#62 = SHAPE_DEFINITION_REPRESENTATION(#60, #61);
#5 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#6 = VERTEX_POINT('NONE', #5);
#7 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
#8 = VERTEX_POINT('NONE', #7);
#9 = DIRECTION('NONE', (1, 0, -0));
#10 = DIRECTION('NONE', (0, 1, 0));
#11 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
#12 = AXIS2_PLACEMENT_3D('NONE', #11, #10, #9);
#13 = CIRCLE('NONE', #12, 0.01);
#14 = DIRECTION('NONE', (0, 1, 0));
#15 = VECTOR('NONE', #14, 1);
#16 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#17 = LINE('NONE', #16, #15);
#18 = DIRECTION('NONE', (1, 0, -0));
#19 = DIRECTION('NONE', (0, 1, 0));
#20 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
#21 = AXIS2_PLACEMENT_3D('NONE', #20, #19, #18);
#22 = CIRCLE('NONE', #21, 0.01);
#23 = EDGE_CURVE('NONE', #6, #6, #13, .T.);
#24 = EDGE_CURVE('NONE', #6, #8, #17, .T.);
#25 = EDGE_CURVE('NONE', #8, #8, #22, .T.);
#26 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
#27 = DIRECTION('NONE', (0, 1, 0));
#28 = DIRECTION('NONE', (1, 0, -0));
#29 = AXIS2_PLACEMENT_3D('NONE', #26, #27, #28);
#30 = CYLINDRICAL_SURFACE('NONE', #29, 0.01);
#31 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
#32 = DIRECTION('NONE', (0, 1, 0));
#33 = AXIS2_PLACEMENT_3D('NONE', #31, #32, $);
#34 = PLANE('NONE', #33);
#35 = CARTESIAN_POINT('NONE', (0, 0, -0));
#36 = DIRECTION('NONE', (0, 1, 0));
#37 = AXIS2_PLACEMENT_3D('NONE', #35, #36, $);
#38 = PLANE('NONE', #37);
#39 = ORIENTED_EDGE('NONE', *, *, #23, .T.);
#40 = ORIENTED_EDGE('NONE', *, *, #25, .F.);
#41 = EDGE_LOOP('NONE', (#39));
#42 = FACE_BOUND('NONE', #41, .T.);
#43 = EDGE_LOOP('NONE', (#40));
#44 = FACE_BOUND('NONE', #43, .T.);
#45 = ADVANCED_FACE('NONE', (#42, #44), #30, .T.);
#46 = ORIENTED_EDGE('NONE', *, *, #23, .F.);
#47 = EDGE_LOOP('NONE', (#46));
#48 = FACE_BOUND('NONE', #47, .T.);
#49 = ADVANCED_FACE('NONE', (#48), #34, .F.);
#50 = ORIENTED_EDGE('NONE', *, *, #25, .T.);
#51 = EDGE_LOOP('NONE', (#50));
#52 = FACE_BOUND('NONE', #51, .T.);
#53 = ADVANCED_FACE('NONE', (#52), #38, .T.);
#54 = CLOSED_SHELL('NONE', (#45, #49, #53));
#55 = MANIFOLD_SOLID_BREP('NONE', #54);
#56 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
#57 = PRODUCT_DEFINITION_CONTEXT('part definition', #56, 'design');
#58 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
#59 = PRODUCT_DEFINITION_FORMATION('', $, #58);
#60 = PRODUCT_DEFINITION('design', $, #59, #57);
#61 = PRODUCT_DEFINITION_SHAPE('NONE', $, #60);
#62 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#55), #4);
#63 = SHAPE_DEFINITION_REPRESENTATION(#61, #62);
ENDSEC;
END-ISO-10303-21;

View File

@ -101,7 +101,7 @@ pub trait CoreDump: Clone {
.meta()
.create_debug_uploads(vec![kittycad::types::multipart::Attachment {
name: "".to_string(),
filepath: Some(format!(r#"modeling-app/coredump-{}.json"#, coredump_id).into()),
filepath: Some(format!(r#"modeling-app/coredump-{coredump_id}.json"#).into()),
content_type: Some("application/json".to_string()),
data,
}])

View File

@ -189,7 +189,7 @@ fn generate_example(index: usize, src: &str, props: &ExampleProperties, file_nam
index
);
let image_data =
std::fs::read(&image_path).unwrap_or_else(|_| panic!("Failed to read image file: {}", image_path));
std::fs::read(&image_path).unwrap_or_else(|_| panic!("Failed to read image file: {image_path}"));
base64::engine::general_purpose::STANDARD.encode(&image_data)
};
@ -225,7 +225,7 @@ fn generate_type_from_kcl(ty: &TyData, file_name: String, example_name: String,
let output = hbs.render("kclType", &data)?;
let output = cleanup_types(&output, kcl_std);
expectorate::assert_contents(format!("../../docs/kcl-std/{}.md", file_name), &output);
expectorate::assert_contents(format!("../../docs/kcl-std/{file_name}.md"), &output);
Ok(())
}
@ -267,7 +267,7 @@ fn generate_mod_from_kcl(m: &ModData, file_name: String) -> Result<()> {
});
let output = hbs.render("module", &data)?;
expectorate::assert_contents(format!("../../docs/kcl-std/{}.md", file_name), &output);
expectorate::assert_contents(format!("../../docs/kcl-std/{file_name}.md"), &output);
Ok(())
}
@ -334,7 +334,7 @@ fn generate_function_from_kcl(
let output = hbs.render("function", &data)?;
let output = &cleanup_types(&output, kcl_std);
expectorate::assert_contents(format!("../../docs/kcl-std/{}.md", file_name), output);
expectorate::assert_contents(format!("../../docs/kcl-std/{file_name}.md"), output);
Ok(())
}
@ -378,7 +378,7 @@ fn generate_const_from_kcl(cnst: &ConstData, file_name: String, example_name: St
let output = hbs.render("const", &data)?;
let output = cleanup_types(&output, kcl_std);
expectorate::assert_contents(format!("../../docs/kcl-std/{}.md", file_name), &output);
expectorate::assert_contents(format!("../../docs/kcl-std/{file_name}.md"), &output);
Ok(())
}

View File

@ -8,6 +8,7 @@ use tower_lsp::lsp_types::{
};
use crate::{
ModuleId,
execution::annotations,
parsing::{
ast::types::{
@ -15,7 +16,6 @@ use crate::{
},
token::NumericSuffix,
},
ModuleId,
};
pub fn walk_prelude() -> ModData {
@ -97,7 +97,7 @@ fn visit_module(name: &str, preferred_prefix: &str, names: WalkForNames) -> Resu
ImportSelector::None { .. } => {
let name = import.module_name().unwrap();
if names.contains(&name) {
Some(visit_module(&path[1], &format!("{}::", name), WalkForNames::All)?)
Some(visit_module(&path[1], &format!("{name}::"), WalkForNames::All)?)
} else {
None
}
@ -451,7 +451,7 @@ impl ModData {
let (name, qual_name, module_name) = if name == "prelude" {
("std", "std".to_owned(), String::new())
} else {
(name, format!("std::{}", name), "std".to_owned())
(name, format!("std::{name}"), "std".to_owned())
};
Self {
preferred_name: format!("{preferred_prefix}{name}"),
@ -767,14 +767,12 @@ impl ArgData {
for s in &arr.elements {
let Expr::Literal(lit) = s else {
panic!(
"Invalid value in `snippetArray`, all items must be string literals but found {:?}",
s
"Invalid value in `snippetArray`, all items must be string literals but found {s:?}"
);
};
let LiteralValue::String(litstr) = &lit.inner.value else {
panic!(
"Invalid value in `snippetArray`, all items must be string literals but found {:?}",
s
"Invalid value in `snippetArray`, all items must be string literals but found {s:?}"
);
};
items.push(litstr.to_owned());
@ -816,7 +814,7 @@ impl ArgData {
}
match self.ty.as_deref() {
Some("Sketch") if self.kind == ArgKind::Special => None,
Some(s) if s.starts_with("number") => Some((index, format!(r#"{label}${{{}:10}}"#, index))),
Some(s) if s.starts_with("number") => Some((index, format!(r#"{label}${{{index}:10}}"#))),
Some("Point2d") => Some((index + 1, format!(r#"{label}[${{{}:0}}, ${{{}:0}}]"#, index, index + 1))),
Some("Point3d") => Some((
index + 2,
@ -831,7 +829,7 @@ impl ArgData {
Some("Sketch") | Some("Sketch | Helix") => Some((index, format!(r#"{label}${{{index}:sketch000}}"#))),
Some("Edge") => Some((index, format!(r#"{label}${{{index}:tag_or_edge_fn}}"#))),
Some("[Edge; 1+]") => Some((index, format!(r#"{label}[${{{index}:tag_or_edge_fn}}]"#))),
Some("Plane") | Some("Solid | Plane") => Some((index, format!(r#"{label}${{{}:XY}}"#, index))),
Some("Plane") | Some("Solid | Plane") => Some((index, format!(r#"{label}${{{index}:XY}}"#))),
Some("[TaggedFace; 2]") => Some((
index + 1,
format!(r#"{label}[${{{}:tag}}, ${{{}:tag}}]"#, index, index + 1),
@ -841,10 +839,10 @@ impl ArgData {
if self.name == "color" {
Some((index, format!(r"{label}${{{}:{}}}", index, "\"#ff0000\"")))
} else {
Some((index, format!(r#"{label}${{{}:"string"}}"#, index)))
Some((index, format!(r#"{label}${{{index}:"string"}}"#)))
}
}
Some("bool") => Some((index, format!(r#"{label}${{{}:false}}"#, index))),
Some("bool") => Some((index, format!(r#"{label}${{{index}:false}}"#))),
_ => None,
}
}
@ -1298,7 +1296,10 @@ mod test {
continue;
}
let name = format!("{}-{i}", f.qual_name.replace("::", "-"));
assert!(TEST_NAMES.contains(&&*name), "Missing test for example \"{name}\", maybe need to update kcl-derive-docs/src/example_tests.rs?")
assert!(
TEST_NAMES.contains(&&*name),
"Missing test for example \"{name}\", maybe need to update kcl-derive-docs/src/example_tests.rs?"
)
}
}
}
@ -1334,7 +1335,9 @@ mod test {
};
let Some(DocData::Fn(d)) = data.children.get(&format!("I:{qualname}")) else {
panic!("Could not find data for {NAME} (missing a child entry for {qualname}), maybe need to update kcl-derive-docs/src/example_tests.rs?");
panic!(
"Could not find data for {NAME} (missing a child entry for {qualname}), maybe need to update kcl-derive-docs/src/example_tests.rs?"
);
};
for (i, eg) in d.examples.iter().enumerate() {
@ -1362,6 +1365,8 @@ mod test {
return;
}
panic!("Could not find data for {NAME} (no example {number}), maybe need to update kcl-derive-docs/src/example_tests.rs?");
panic!(
"Could not find data for {NAME} (no example {number}), maybe need to update kcl-derive-docs/src/example_tests.rs?"
);
}
}

View File

@ -2,11 +2,11 @@
//! tasks.
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
atomic::{AtomicUsize, Ordering},
};
use tokio::sync::{mpsc, Notify};
use tokio::sync::{Notify, mpsc};
use crate::errors::KclError;

View File

@ -3,26 +3,26 @@
use std::{collections::HashMap, sync::Arc};
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use futures::{SinkExt, StreamExt};
use indexmap::IndexMap;
use kcmc::{
ModelingCmd,
websocket::{
BatchResponse, FailureWebSocketResponse, ModelingCmdReq, ModelingSessionData, OkWebSocketResponseData,
SuccessWebSocketResponse, WebSocketRequest, WebSocketResponse,
},
ModelingCmd,
};
use kittycad_modeling_cmds::{self as kcmc};
use tokio::sync::{mpsc, oneshot, RwLock};
use tokio::sync::{RwLock, mpsc, oneshot};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use uuid::Uuid;
use crate::{
SourceRange,
engine::{AsyncTasks, EngineManager, EngineStats},
errors::{KclError, KclErrorDetails},
execution::{DefaultPlanes, IdGenerator},
SourceRange,
};
#[derive(Debug, PartialEq)]
@ -85,7 +85,7 @@ impl TcpRead {
let msg = match msg {
Ok(msg) => msg,
Err(e) if matches!(e, tokio_tungstenite::tungstenite::Error::Protocol(_)) => {
return Err(WebSocketReadError::Read(e))
return Err(WebSocketReadError::Read(e));
}
Err(e) => return Err(anyhow::anyhow!("Error reading from engine's WebSocket: {e}").into()),
};
@ -427,7 +427,7 @@ impl EngineManager for EngineConnection {
request_sent: tx,
})
.await
.map_err(|e| KclError::new_engine(KclErrorDetails::new(format!("Failed to send debug: {}", e), vec![])))?;
.map_err(|e| KclError::new_engine(KclErrorDetails::new(format!("Failed to send debug: {e}"), vec![])))?;
let _ = rx.await;
Ok(())
@ -463,7 +463,7 @@ impl EngineManager for EngineConnection {
.await
.map_err(|e| {
KclError::new_engine(KclErrorDetails::new(
format!("Failed to send modeling command: {}", e),
format!("Failed to send modeling command: {e}"),
vec![source_range],
))
})?;
@ -533,7 +533,7 @@ impl EngineManager for EngineConnection {
}
Err(KclError::new_engine(KclErrorDetails::new(
format!("Modeling command timed out `{}`", id),
format!("Modeling command timed out `{id}`"),
vec![source_range],
)))
}

View File

@ -12,16 +12,16 @@ use kcmc::{
WebSocketResponse,
},
};
use kittycad_modeling_cmds::{self as kcmc, websocket::ModelingCmdReq, ImportFiles, ModelingCmd};
use kittycad_modeling_cmds::{self as kcmc, ImportFiles, ModelingCmd, websocket::ModelingCmdReq};
use tokio::sync::RwLock;
use uuid::Uuid;
use crate::{
SourceRange,
engine::{AsyncTasks, EngineStats},
errors::KclError,
exec::DefaultPlanes,
execution::IdGenerator,
SourceRange,
};
#[derive(Debug, Clone)]

View File

@ -11,10 +11,10 @@ use uuid::Uuid;
use wasm_bindgen::prelude::*;
use crate::{
SourceRange,
engine::{AsyncTasks, EngineStats},
errors::{KclError, KclErrorDetails},
execution::{DefaultPlanes, IdGenerator},
SourceRange,
};
#[wasm_bindgen(module = "/../../src/lang/std/engineConnection.ts")]

View File

@ -12,15 +12,15 @@ pub mod conn_wasm;
use std::{
collections::HashMap,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
atomic::{AtomicUsize, Ordering},
},
};
pub use async_tasks::AsyncTasks;
use indexmap::IndexMap;
use kcmc::{
each_cmd as mcmd,
ModelingCmd, each_cmd as mcmd,
length_unit::LengthUnit,
ok_response::OkModelingCmdResponse,
shared::Color,
@ -28,7 +28,6 @@ use kcmc::{
BatchResponse, ModelingBatch, ModelingCmdReq, ModelingSessionData, OkWebSocketResponseData, WebSocketRequest,
WebSocketResponse,
},
ModelingCmd,
};
use kittycad_modeling_cmds as kcmc;
use parse_display::{Display, FromStr};
@ -39,9 +38,9 @@ use uuid::Uuid;
use web_time::Instant;
use crate::{
errors::{KclError, KclErrorDetails},
execution::{types::UnitLen, DefaultPlanes, IdGenerator, PlaneInfo, Point3d},
SourceRange,
errors::{KclError, KclErrorDetails},
execution::{DefaultPlanes, IdGenerator, PlaneInfo, Point3d, types::UnitLen},
};
lazy_static::lazy_static! {
@ -291,7 +290,10 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// the artifact graph won't care either if its gone since you can't select it
// anymore anyways.
if let Err(err) = self.async_tasks().join_all().await {
crate::log::logln!("Error waiting for async tasks (this is typically fine and just means that an edge became something else): {:?}", err);
crate::log::logln!(
"Error waiting for async tasks (this is typically fine and just means that an edge became something else): {:?}",
err
);
}
// Flush the batch to make sure nothing remains.
@ -499,7 +501,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
}
_ => {
return Err(KclError::new_engine(KclErrorDetails::new(
format!("The request is not a modeling command: {:?}", req),
format!("The request is not a modeling command: {req:?}"),
vec![*range],
)));
}
@ -529,7 +531,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
} else {
// We should never get here.
Err(KclError::new_engine(KclErrorDetails::new(
format!("Failed to get batch response: {:?}", response),
format!("Failed to get batch response: {response:?}"),
vec![source_range],
)))
}
@ -544,7 +546,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// an error.
let source_range = id_to_source_range.get(cmd_id.as_ref()).cloned().ok_or_else(|| {
KclError::new_engine(KclErrorDetails::new(
format!("Failed to get source range for command ID: {:?}", cmd_id),
format!("Failed to get source range for command ID: {cmd_id:?}"),
vec![],
))
})?;
@ -554,7 +556,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.parse_websocket_response(ws_resp, source_range)
}
_ => Err(KclError::new_engine(KclErrorDetails::new(
format!("The final request is not a modeling command: {:?}", final_req),
format!("The final request is not a modeling command: {final_req:?}"),
vec![source_range],
))),
}
@ -663,7 +665,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
// We should never get here.
KclError::new_engine(KclErrorDetails::new(
format!("Failed to get default plane info for: {:?}", name),
format!("Failed to get default plane info for: {name:?}"),
vec![source_range],
))
})?;
@ -739,7 +741,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Get the source range for the command.
let source_range = id_to_source_range.get(cmd_id).cloned().ok_or_else(|| {
KclError::new_engine(KclErrorDetails::new(
format!("Failed to get source range for command ID: {:?}", cmd_id),
format!("Failed to get source range for command ID: {cmd_id:?}"),
vec![],
))
})?;
@ -754,7 +756,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Return an error that we did not get an error or the response we wanted.
// This should never happen but who knows.
Err(KclError::new_engine(KclErrorDetails::new(
format!("Failed to find response for command ID: {:?}", id),
format!("Failed to find response for command ID: {id:?}"),
vec![],
)))
}

View File

@ -7,11 +7,11 @@ use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
#[cfg(feature = "artifact-graph")]
use crate::execution::{ArtifactCommand, ArtifactGraph, Operation};
use crate::{
ModuleId,
execution::DefaultPlanes,
lsp::IntoDiagnostic,
modules::{ModulePath, ModuleSource},
source_range::SourceRange,
ModuleId,
};
/// How did the KCL execution fail

View File

@ -2,13 +2,13 @@
use std::str::FromStr;
use kittycad_modeling_cmds::coord::{System, KITTYCAD, OPENGL, VULKAN};
use kittycad_modeling_cmds::coord::{KITTYCAD, OPENGL, System, VULKAN};
use crate::{
KclError, SourceRange,
errors::KclErrorDetails,
execution::types::{UnitAngle, UnitLen},
parsing::ast::types::{Annotation, Expr, LiteralValue, Node, ObjectProperty},
KclError, SourceRange,
};
/// Annotations which should cause re-execution if they change.

View File

@ -1,20 +1,19 @@
use fnv::FnvHashMap;
use indexmap::IndexMap;
use kittycad_modeling_cmds::{
self as kcmc,
self as kcmc, EnableSketchMode, ModelingCmd,
ok_response::OkModelingCmdResponse,
shared::ExtrusionFaceCapType,
websocket::{BatchResponse, OkWebSocketResponseData, WebSocketResponse},
EnableSketchMode, ModelingCmd,
};
use serde::{ser::SerializeSeq, Serialize};
use serde::{Serialize, ser::SerializeSeq};
use uuid::Uuid;
use crate::{
KclError, NodePath, SourceRange,
errors::KclErrorDetails,
execution::ArtifactId,
parsing::ast::types::{Node, Program},
KclError, NodePath, SourceRange,
};
#[cfg(test)]
@ -893,7 +892,10 @@ fn artifacts_to_update(
),
};
if original_path_ids.len() != face_edge_infos.len() {
internal_error!(range, "EntityMirror or EntityMirrorAcrossEdge response has different number face edge info than original mirrored paths: id={id:?}, cmd={cmd:?}, response={response:?}");
internal_error!(
range,
"EntityMirror or EntityMirrorAcrossEdge response has different number face edge info than original mirrored paths: id={id:?}, cmd={cmd:?}, response={response:?}"
);
}
let mut return_arr = Vec::new();
for (face_edge_info, original_path_id) in face_edge_infos.iter().zip(original_path_ids) {
@ -909,7 +911,10 @@ fn artifacts_to_update(
// of its info.
let Some(Artifact::Path(original_path)) = artifacts.get(&original_path_id) else {
// We couldn't find the original path. This is a bug.
internal_error!(range, "Couldn't find original path for mirror2d: original_path_id={original_path_id:?}, cmd={cmd:?}");
internal_error!(
range,
"Couldn't find original path for mirror2d: original_path_id={original_path_id:?}, cmd={cmd:?}"
);
};
Path {
id: path_id,

View File

@ -268,7 +268,7 @@ impl ArtifactGraph {
for (group_id, artifact_ids) in groups {
let group_id = *stable_id_map.get(&group_id).unwrap();
writeln!(output, "{prefix}subgraph path{group_id} [Path]")?;
let indented = format!("{} ", prefix);
let indented = format!("{prefix} ");
for artifact_id in artifact_ids {
let artifact = self.map.get(&artifact_id).unwrap();
let id = *stable_id_map.get(&artifact_id).unwrap();
@ -353,7 +353,7 @@ impl ArtifactGraph {
node_path_display(output, prefix, None, &segment.code_ref)?;
}
Artifact::Solid2d(_solid2d) => {
writeln!(output, "{prefix}{}[Solid2d]", id)?;
writeln!(output, "{prefix}{id}[Solid2d]")?;
}
Artifact::StartSketchOnFace(StartSketchOnFace { code_ref, .. }) => {
writeln!(
@ -494,24 +494,24 @@ impl ArtifactGraph {
match edge.flow {
EdgeFlow::SourceToTarget => match edge.direction {
EdgeDirection::Forward => {
writeln!(output, "{prefix}{source_id} x{}--> {}", extra, target_id)?;
writeln!(output, "{prefix}{source_id} x{extra}--> {target_id}")?;
}
EdgeDirection::Backward => {
writeln!(output, "{prefix}{source_id} <{}--x {}", extra, target_id)?;
writeln!(output, "{prefix}{source_id} <{extra}--x {target_id}")?;
}
EdgeDirection::Bidirectional => {
writeln!(output, "{prefix}{source_id} {}--- {}", extra, target_id)?;
writeln!(output, "{prefix}{source_id} {extra}--- {target_id}")?;
}
},
EdgeFlow::TargetToSource => match edge.direction {
EdgeDirection::Forward => {
writeln!(output, "{prefix}{target_id} x{}--> {}", extra, source_id)?;
writeln!(output, "{prefix}{target_id} x{extra}--> {source_id}")?;
}
EdgeDirection::Backward => {
writeln!(output, "{prefix}{target_id} <{}--x {}", extra, source_id)?;
writeln!(output, "{prefix}{target_id} <{extra}--x {source_id}")?;
}
EdgeDirection::Bidirectional => {
writeln!(output, "{prefix}{target_id} {}--- {}", extra, source_id)?;
writeln!(output, "{prefix}{target_id} {extra}--- {source_id}")?;
}
},
}

View File

@ -6,15 +6,14 @@ use itertools::{EitherOrBoth, Itertools};
use tokio::sync::RwLock;
use crate::{
ExecOutcome, ExecutorContext,
execution::{
annotations,
EnvironmentRef, ExecutorSettings, annotations,
memory::Stack,
state::{self as exec_state, ModuleInfoMap},
EnvironmentRef, ExecutorSettings,
},
parsing::ast::types::{Annotation, Node, Program},
walk::Node as WalkNode,
ExecOutcome, ExecutorContext,
};
lazy_static::lazy_static! {
@ -337,7 +336,7 @@ mod tests {
use pretty_assertions::assert_eq;
use super::*;
use crate::execution::{parse_execute, parse_execute_with_project_dir, ExecTestResults};
use crate::execution::{ExecTestResults, parse_execute, parse_execute_with_project_dir};
#[tokio::test(flavor = "multi_thread")]
async fn test_get_changed_program_same_code() {
@ -755,7 +754,7 @@ extrude(profile001, length = 100)"#
.await;
let CacheResult::CheckImportsOnly { reapply_settings, .. } = result else {
panic!("Expected CheckImportsOnly, got {:?}", result);
panic!("Expected CheckImportsOnly, got {result:?}");
};
assert_eq!(reapply_settings, false);
@ -839,7 +838,7 @@ extrude(profile001, length = 100)
.await;
let CacheResult::CheckImportsOnly { reapply_settings, .. } = result else {
panic!("Expected CheckImportsOnly, got {:?}", result);
panic!("Expected CheckImportsOnly, got {result:?}");
};
assert_eq!(reapply_settings, false);

View File

@ -1,10 +1,10 @@
use indexmap::IndexMap;
use serde::Serialize;
use super::{types::NumericType, ArtifactId, KclValue};
use super::{ArtifactId, KclValue, types::NumericType};
#[cfg(feature = "artifact-graph")]
use crate::parsing::ast::types::{Node, Program};
use crate::{parsing::ast::types::ItemVisibility, ModuleId, NodePath, SourceRange};
use crate::{ModuleId, NodePath, SourceRange, parsing::ast::types::ItemVisibility};
/// A CAD modeling operation for display in the feature tree, AKA operations
/// timeline.
@ -57,7 +57,7 @@ impl Operation {
/// If the variant is `StdLibCall`, set the `is_error` field.
pub(crate) fn set_std_lib_call_is_error(&mut self, is_err: bool) {
match self {
Self::StdLibCall { ref mut is_error, .. } => *is_error = is_err,
Self::StdLibCall { is_error, .. } => *is_error = is_err,
Self::VariableDeclaration { .. } | Self::GroupBegin { .. } | Self::GroupEnd => {}
}
}
@ -226,10 +226,7 @@ impl From<&KclValue> for OpKclValue {
match value {
KclValue::Uuid { value, .. } => Self::Uuid { value: *value },
KclValue::Bool { value, .. } => Self::Bool { value: *value },
KclValue::Number { value, ty, .. } => Self::Number {
value: *value,
ty: ty.clone(),
},
KclValue::Number { value, ty, .. } => Self::Number { value: *value, ty: *ty },
KclValue::String { value, .. } => Self::String { value: value.clone() },
KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => {
let value = value.iter().map(Self::from).collect();

View File

@ -3,17 +3,17 @@ use std::collections::HashMap;
use async_recursion::async_recursion;
use crate::{
CompilationError, NodePath,
errors::{KclError, KclErrorDetails},
execution::{
annotations,
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, ModelingCmdMeta, ModuleArtifactState,
Operation, PlaneType, StatementKind, TagIdentifier, annotations,
cad_op::OpKclValue,
fn_call::Args,
kcl_value::{FunctionSource, TypeDef},
memory,
state::ModuleState,
types::{NumericType, PrimitiveType, RuntimeType},
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, ModelingCmdMeta, ModuleArtifactState,
Operation, PlaneType, StatementKind, TagIdentifier,
},
fmt,
modules::{ModuleId, ModulePath, ModuleRepr},
@ -28,7 +28,6 @@ use crate::{
},
source_range::SourceRange,
std::args::TyF64,
CompilationError, NodePath,
};
impl<'a> StatementKind<'a> {
@ -198,19 +197,23 @@ impl ExecutorContext {
}
if ty.is_ok() && !module_exports.contains(&ty_name) {
ty = Err(KclError::new_semantic(KclErrorDetails::new(format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name
),
vec![SourceRange::from(&import_item.name)],)));
ty = Err(KclError::new_semantic(KclErrorDetails::new(
format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name
),
vec![SourceRange::from(&import_item.name)],
)));
}
if mod_value.is_ok() && !module_exports.contains(&mod_name) {
mod_value = Err(KclError::new_semantic(KclErrorDetails::new(format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name
),
vec![SourceRange::from(&import_item.name)],)));
mod_value = Err(KclError::new_semantic(KclErrorDetails::new(
format!(
"Cannot import \"{}\" from module because it is not exported. Add \"export\" before the definition to export it.",
import_item.name.name
),
vec![SourceRange::from(&import_item.name)],
)));
}
if value.is_err() && ty.is_err() && mod_value.is_err() {
@ -270,7 +273,7 @@ impl ExecutorContext {
.get_from(name, env_ref, source_range, 0)
.map_err(|_err| {
KclError::new_internal(KclErrorDetails::new(
format!("{} is not defined in module (but was exported?)", name),
format!("{name} is not defined in module (but was exported?)"),
vec![source_range],
))
})?
@ -431,7 +434,7 @@ impl ExecutorContext {
return Err(KclError::new_semantic(KclErrorDetails::new(
"User-defined types are not yet supported.".to_owned(),
vec![metadata.source_range],
)))
)));
}
},
}
@ -792,11 +795,12 @@ fn var_in_own_ref_err(e: KclError, being_declared: &Option<String>) -> KclError
// TODO after June 26th: replace this with a let-chain,
// which will be available in Rust 1.88
// https://rust-lang.github.io/rfcs/2497-if-let-chains.html
match (&being_declared, &name) {
(Some(name0), Some(name1)) if name0 == name1 => {
details.message = format!("You can't use `{name0}` because you're currently trying to define it. Use a different variable here instead.");
}
_ => {}
if let (Some(name0), Some(name1)) = (&being_declared, &name)
&& name0 == name1
{
details.message = format!(
"You can't use `{name0}` because you're currently trying to define it. Use a different variable here instead."
);
}
KclError::UndefinedValue { details, name }
}
@ -860,6 +864,9 @@ impl BinaryPart {
BinaryPart::CallExpressionKw(call_expression) => call_expression.execute(exec_state, ctx).await,
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state, ctx).await,
BinaryPart::ArrayExpression(e) => e.execute(exec_state, ctx).await,
BinaryPart::ArrayRangeExpression(e) => e.execute(exec_state, ctx).await,
BinaryPart::ObjectExpression(e) => e.execute(exec_state, ctx).await,
BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await,
BinaryPart::AscribedExpression(e) => e.get_result(exec_state, ctx).await,
}
@ -987,6 +994,39 @@ impl Node<MemberExpression> {
// Check the property and object match -- e.g. ints for arrays, strs for objects.
match (object, property, self.computed) {
(KclValue::Plane { value: plane }, Property::String(property), false) => match property.as_str() {
"yAxis" => {
let (p, u) = plane.info.y_axis.as_3_dims();
Ok(KclValue::array_from_point3d(
p,
NumericType::Known(crate::exec::UnitType::Length(u)),
vec![meta],
))
}
"xAxis" => {
let (p, u) = plane.info.x_axis.as_3_dims();
Ok(KclValue::array_from_point3d(
p,
NumericType::Known(crate::exec::UnitType::Length(u)),
vec![meta],
))
}
"origin" => {
let (p, u) = plane.info.origin.as_3_dims();
Ok(KclValue::array_from_point3d(
p,
NumericType::Known(crate::exec::UnitType::Length(u)),
vec![meta],
))
}
other => Err(KclError::new_undefined_value(
KclErrorDetails::new(
format!("Property '{other}' not found in plane"),
vec![self.clone().into()],
),
None,
)),
},
(KclValue::Object { value: map, meta: _ }, Property::String(property), false) => {
if let Some(value) = map.get(&property) {
Ok(value.to_owned())
@ -1006,7 +1046,22 @@ impl Node<MemberExpression> {
vec![self.clone().into()],
)))
}
(KclValue::Object { .. }, p, _) => {
(KclValue::Object { value: map, .. }, p @ Property::UInt(i), _) => {
if i == 0
&& let Some(value) = map.get("x")
{
return Ok(value.to_owned());
}
if i == 1
&& let Some(value) = map.get("y")
{
return Ok(value.to_owned());
}
if i == 2
&& let Some(value) = map.get("z")
{
return Ok(value.to_owned());
}
let t = p.type_name();
let article = article_for(t);
Err(KclError::new_semantic(KclErrorDetails::new(
@ -1042,6 +1097,16 @@ impl Node<MemberExpression> {
(KclValue::Solid { value }, Property::String(prop), false) if prop == "sketch" => Ok(KclValue::Sketch {
value: Box::new(value.sketch),
}),
(geometry @ KclValue::Solid { .. }, Property::String(prop), false) if prop == "tags" => {
// This is a common mistake.
Err(KclError::new_semantic(KclErrorDetails::new(
format!(
"Property `{prop}` not found on {}. You can get a solid's tags through its sketch, as in, `exampleSolid.sketch.tags`.",
geometry.human_friendly_type()
),
vec![self.clone().into()],
)))
}
(KclValue::Sketch { value: sk }, Property::String(prop), false) if prop == "tags" => Ok(KclValue::Object {
meta: vec![Metadata {
source_range: SourceRange::from(self.clone()),
@ -1052,6 +1117,12 @@ impl Node<MemberExpression> {
.map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
.collect(),
}),
(geometry @ (KclValue::Sketch { .. } | KclValue::Solid { .. }), Property::String(property), false) => {
Err(KclError::new_semantic(KclErrorDetails::new(
format!("Property `{property}` not found on {}", geometry.human_friendly_type()),
vec![self.clone().into()],
)))
}
(being_indexed, _, _) => Err(KclError::new_semantic(KclErrorDetails::new(
format!(
"Only arrays can be indexed, but you're trying to index {}",
@ -1077,7 +1148,7 @@ impl Node<BinaryExpression> {
(&left_value, &right_value)
{
return Ok(KclValue::String {
value: format!("{}{}", left, right),
value: format!("{left}{right}"),
meta,
});
}
@ -1237,7 +1308,9 @@ impl Node<BinaryExpression> {
exec_state.clear_units_warnings(&sr);
let mut err = CompilationError::err(
sr,
format!("{} numbers which have unknown or incompatible units.\nYou can probably fix this error by specifying the units using type ascription, e.g., `len: number(mm)` or `(a * b): number(deg)`.", verb),
format!(
"{verb} numbers which have unknown or incompatible units.\nYou can probably fix this error by specifying the units using type ascription, e.g., `len: number(mm)` or `(a * b): number(deg)`."
),
);
err.tag = crate::errors::Tag::UnknownNumericUnits;
exec_state.warn(err);
@ -1291,7 +1364,7 @@ impl Node<UnaryExpression> {
Ok(KclValue::Number {
value: -value,
meta,
ty: ty.clone(),
ty: *ty,
})
}
KclValue::Plane { value } => {
@ -1323,7 +1396,7 @@ impl Node<UnaryExpression> {
.map(|v| match v {
KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
value: *value * -1.0,
ty: ty.clone(),
ty: *ty,
meta: meta.clone(),
}),
_ => Err(err()),
@ -1344,7 +1417,7 @@ impl Node<UnaryExpression> {
.map(|v| match v {
KclValue::Number { value, ty, meta } => Ok(KclValue::Number {
value: *value * -1.0,
ty: ty.clone(),
ty: *ty,
meta: meta.clone(),
}),
_ => Err(err()),
@ -1417,7 +1490,7 @@ async fn inner_execute_pipe_body(
for expression in body {
if let Expr::TagDeclarator(_) = expression {
return Err(KclError::new_semantic(KclErrorDetails::new(
format!("This cannot be in a PipeExpression: {:?}", expression),
format!("This cannot be in a PipeExpression: {expression:?}"),
vec![expression.into()],
)));
}
@ -1538,7 +1611,7 @@ impl Node<ArrayRangeExpression> {
.into_iter()
.map(|num| KclValue::Number {
value: num as f64,
ty: start_ty.clone(),
ty: start_ty,
meta: meta.clone(),
})
.collect(),
@ -1699,9 +1772,15 @@ fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -
let make_err =
|message: String| Err::<Property, _>(KclError::new_semantic(KclErrorDetails::new(message, property_sr)));
match value {
n @ KclValue::Number{value: num, ty, .. } => {
if !matches!(ty, NumericType::Known(crate::exec::UnitType::Count) | NumericType::Default { .. } | NumericType::Any ) {
return make_err(format!("arrays can only be indexed by non-dimensioned numbers, found {}", n.human_friendly_type()));
n @ KclValue::Number { value: num, ty, .. } => {
if !matches!(
ty,
NumericType::Known(crate::exec::UnitType::Count) | NumericType::Default { .. } | NumericType::Any
) {
return make_err(format!(
"arrays can only be indexed by non-dimensioned numbers, found {}",
n.human_friendly_type()
));
}
let num = *num;
if num < 0.0 {
@ -1711,13 +1790,15 @@ fn jvalue_to_prop(value: &KclValue, property_sr: Vec<SourceRange>, name: &str) -
if let Some(nearest_int) = nearest_int {
Ok(Property::UInt(nearest_int))
} else {
make_err(format!("'{num}' is not an integer, so you can't index an array with it"))
make_err(format!(
"'{num}' is not an integer, so you can't index an array with it"
))
}
}
KclValue::String{value: x, meta:_} => Ok(Property::String(x.to_owned())),
_ => {
make_err(format!("{name} is not a valid property/index, you can only use a string to get the property of an object, or an int (>= 0) to get an item in an array"))
}
KclValue::String { value: x, meta: _ } => Ok(Property::String(x.to_owned())),
_ => make_err(format!(
"{name} is not a valid property/index, you can only use a string to get the property of an object, or an int (>= 0) to get an item in an array"
)),
}
}
@ -1745,9 +1826,9 @@ mod test {
use super::*;
use crate::{
exec::UnitType,
execution::{parse_execute, ContextType},
ExecutorSettings, UnitLen,
exec::UnitType,
execution::{ContextType, parse_execute},
};
#[tokio::test(flavor = "multi_thread")]
@ -1777,7 +1858,7 @@ arr1 = [42]: [number(cm)]
.get_from("arr1", result.mem_env, SourceRange::default(), 0)
.unwrap();
if let KclValue::HomArray { value, ty } = arr1 {
assert_eq!(value.len(), 1, "Expected Vec with specific length: found {:?}", value);
assert_eq!(value.len(), 1, "Expected Vec with specific length: found {value:?}");
assert_eq!(*ty, RuntimeType::known_length(UnitLen::Cm));
// Compare, ignoring meta.
if let KclValue::Number { value, ty, .. } = &value[0] {
@ -1946,7 +2027,7 @@ d = b + c
.await
.map_err(|err| {
KclError::new_internal(KclErrorDetails::new(
format!("Failed to create mock engine connection: {}", err),
format!("Failed to create mock engine connection: {err}"),
vec![SourceRange::default()],
))
})
@ -2172,4 +2253,12 @@ y = x[0mm + 1]
"#;
parse_execute(ast).await.unwrap_err();
}
#[tokio::test(flavor = "multi_thread")]
async fn getting_property_of_plane() {
// let ast = include_str!("../../tests/inputs/planestuff.kcl");
let ast = std::fs::read_to_string("tests/inputs/planestuff.kcl").unwrap();
parse_execute(&ast).await.unwrap();
}
}

View File

@ -2,19 +2,19 @@ use async_recursion::async_recursion;
use indexmap::IndexMap;
use crate::{
CompilationError, NodePath,
errors::{KclError, KclErrorDetails},
execution::{
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, StatementKind, TagEngineInfo,
TagIdentifier,
cad_op::{Group, OpArg, OpKclValue, Operation},
kcl_value::FunctionSource,
memory,
types::RuntimeType,
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, StatementKind, TagEngineInfo,
TagIdentifier,
},
parsing::ast::types::{CallExpressionKw, DefaultParamVal, FunctionExpression, Node, Program, Type},
source_range::SourceRange,
std::StdFn,
CompilationError, NodePath,
};
#[derive(Debug, Clone)]
@ -269,7 +269,7 @@ impl Node<CallExpressionKw> {
};
KclError::new_undefined_value(
KclErrorDetails::new(
format!("Result of user-defined function {} is undefined", fn_name),
format!("Result of user-defined function {fn_name} is undefined"),
source_ranges,
),
None,
@ -401,7 +401,7 @@ impl FunctionDefinition<'_> {
impl FunctionBody<'_> {
fn prep_mem(&self, exec_state: &mut ExecState) {
match self {
FunctionBody::Rust(_) => exec_state.mut_stack().push_new_env_for_rust_call(),
FunctionBody::Rust(_) => exec_state.mut_stack().push_new_root_env(true),
FunctionBody::Kcl(_, memory) => exec_state.mut_stack().push_new_env_for_call(*memory),
}
}
@ -445,7 +445,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
}
}
}
KclValue::Solid { ref mut value } => {
KclValue::Solid { value } => {
for v in &value.value {
if let Some(tag) = v.get_tag() {
// Get the past tag and update it.
@ -555,9 +555,9 @@ fn type_err_str(expected: &Type, found: &KclValue, source_range: &SourceRange, e
let found_human = found.human_friendly_type();
let found_ty = found.principal_type_string();
let found_str = if found_human == found_ty || found_human == format!("a {}", strip_backticks(&found_ty)) {
format!("a value with type {}", found_ty)
format!("a value with type {found_ty}")
} else {
format!("{found_human} (with type {})", found_ty)
format!("{found_human} (with type {found_ty})")
};
let mut result = format!("{expected_str}, but found {found_str}.");
@ -626,7 +626,7 @@ fn type_check_params_kw(
format!(
"`{label}` is not an argument of {}",
fn_name
.map(|n| format!("`{}`", n))
.map(|n| format!("`{n}`"))
.unwrap_or_else(|| "this function".to_owned()),
),
));
@ -676,7 +676,7 @@ fn type_check_params_kw(
format!(
"The input argument of {} requires {}",
fn_name
.map(|n| format!("`{}`", n))
.map(|n| format!("`{n}`"))
.unwrap_or_else(|| "this function".to_owned()),
type_err_str(ty, &arg.1.value, &arg.1.source_range, exec_state),
),
@ -691,7 +691,7 @@ fn type_check_params_kw(
format!(
"{} expects an unlabeled first argument (`@{name}`), but it is labelled in the call",
fn_name
.map(|n| format!("The function `{}`", n))
.map(|n| format!("The function `{n}`"))
.unwrap_or_else(|| "This function".to_owned()),
),
));
@ -721,7 +721,7 @@ fn assign_args_to_params_kw(
)?;
}
None => match default {
Some(ref default_val) => {
Some(default_val) => {
let value = KclValue::from_default_param(default_val.clone(), exec_state);
exec_state
.mut_stack()
@ -729,10 +729,7 @@ fn assign_args_to_params_kw(
}
None => {
return Err(KclError::new_semantic(KclErrorDetails::new(
format!(
"This function requires a parameter {}, but you haven't passed it one.",
name
),
format!("This function requires a parameter {name}, but you haven't passed it one."),
source_ranges,
)));
}
@ -746,7 +743,9 @@ fn assign_args_to_params_kw(
let Some(unlabeled) = unlabelled else {
return Err(if args.kw_args.labeled.contains_key(param_name) {
KclError::new_semantic(KclErrorDetails::new(
format!("The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"),
format!(
"The function does declare a parameter named '{param_name}', but this parameter doesn't use a label. Try removing the `{param_name}:`"
),
source_ranges,
))
} else {
@ -799,7 +798,7 @@ mod test {
use super::*;
use crate::{
execution::{memory::Stack, parse_execute, types::NumericType, ContextType},
execution::{ContextType, memory::Stack, parse_execute, types::NumericType},
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
};

View File

@ -3,16 +3,16 @@ use std::ops::{Add, AddAssign, Mul};
use anyhow::Result;
use indexmap::IndexMap;
use kittycad_modeling_cmds as kcmc;
use kittycad_modeling_cmds::{each_cmd as mcmd, length_unit::LengthUnit, websocket::ModelingCmdReq, ModelingCmd};
use kittycad_modeling_cmds::{ModelingCmd, each_cmd as mcmd, length_unit::LengthUnit, websocket::ModelingCmdReq};
use parse_display::{Display, FromStr};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
engine::{PlaneName, DEFAULT_PLANE_INFO},
engine::{DEFAULT_PLANE_INFO, PlaneName},
errors::{KclError, KclErrorDetails},
execution::{
types::NumericType, ArtifactId, ExecState, ExecutorContext, Metadata, TagEngineInfo, TagIdentifier, UnitLen,
ArtifactId, ExecState, ExecutorContext, Metadata, TagEngineInfo, TagIdentifier, UnitLen, types::NumericType,
},
parsing::ast::types::{Node, NodeRef, TagDeclarator, TagNode},
std::{args::TyF64, sketch::PlaneData},
@ -472,7 +472,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
PlaneData::Plane(_) => {
// We will never get here since we already checked for PlaneData::Plane.
return Err(KclError::new_internal(KclErrorDetails::new(
format!("PlaneData {:?} not found", value),
format!("PlaneData {value:?} not found"),
Default::default(),
)));
}
@ -480,7 +480,7 @@ impl TryFrom<PlaneData> for PlaneInfo {
let info = DEFAULT_PLANE_INFO.get(&name).ok_or_else(|| {
KclError::new_internal(KclErrorDetails::new(
format!("Plane {} not found", name),
format!("Plane {name} not found"),
Default::default(),
))
})?;
@ -815,8 +815,8 @@ impl EdgeCut {
pub fn set_id(&mut self, id: uuid::Uuid) {
match self {
EdgeCut::Fillet { id: ref mut i, .. } => *i = id,
EdgeCut::Chamfer { id: ref mut i, .. } => *i = id,
EdgeCut::Fillet { id: i, .. } => *i = id,
EdgeCut::Chamfer { id: i, .. } => *i = id,
}
}
@ -829,8 +829,8 @@ impl EdgeCut {
pub fn set_edge_id(&mut self, id: uuid::Uuid) {
match self {
EdgeCut::Fillet { edge_id: ref mut i, .. } => *i = id,
EdgeCut::Chamfer { edge_id: ref mut i, .. } => *i = id,
EdgeCut::Fillet { edge_id: i, .. } => *i = id,
EdgeCut::Chamfer { edge_id: i, .. } => *i = id,
}
}
@ -921,6 +921,12 @@ impl Point3d {
units: UnitLen::Unknown,
}
}
pub fn as_3_dims(&self) -> ([f64; 3], UnitLen) {
let p = [self.x, self.y, self.z];
let u = self.units;
(p, u)
}
}
impl From<[TyF64; 3]> for Point3d {
@ -939,6 +945,7 @@ impl From<Point3d> for Point3D {
Self { x: p.x, y: p.y, z: p.z }
}
}
impl From<Point3d> for kittycad_modeling_cmds::shared::Point3d<LengthUnit> {
fn from(p: Point3d) -> Self {
Self {
@ -1004,12 +1011,12 @@ pub struct BasePath {
impl BasePath {
pub fn get_to(&self) -> [TyF64; 2] {
let ty: NumericType = self.units.into();
[TyF64::new(self.to[0], ty.clone()), TyF64::new(self.to[1], ty)]
[TyF64::new(self.to[0], ty), TyF64::new(self.to[1], ty)]
}
pub fn get_from(&self) -> [TyF64; 2] {
let ty: NumericType = self.units.into();
[TyF64::new(self.from[0], ty.clone()), TyF64::new(self.from[1], ty)]
[TyF64::new(self.from[0], ty), TyF64::new(self.from[1], ty)]
}
}
@ -1030,7 +1037,7 @@ pub struct GeoMeta {
#[ts(export)]
#[serde(tag = "type")]
pub enum Path {
/// A path that goes to a point.
/// A straight line which ends at the given point.
ToPoint {
#[serde(flatten)]
base: BasePath,
@ -1225,14 +1232,14 @@ impl Path {
pub fn get_from(&self) -> [TyF64; 2] {
let p = &self.get_base().from;
let ty: NumericType = self.get_base().units.into();
[TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]
[TyF64::new(p[0], ty), TyF64::new(p[1], ty)]
}
/// Where does this path segment end?
pub fn get_to(&self) -> [TyF64; 2] {
let p = &self.get_base().to;
let ty: NumericType = self.get_base().units.into();
[TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]
[TyF64::new(p[0], ty), TyF64::new(p[1], ty)]
}
/// The path segment start point and its type.

View File

@ -2,12 +2,12 @@ use std::str::FromStr;
use anyhow::Result;
use kcmc::{
coord::{System, KITTYCAD},
ImportFile, ModelingCmd,
coord::{KITTYCAD, System},
each_cmd as mcmd,
format::InputFormat3d,
shared::FileImportFormat,
units::UnitLength,
ImportFile, ModelingCmd,
};
use kittycad_modeling_cmds as kcmc;
use serde::{Deserialize, Serialize};
@ -16,8 +16,8 @@ use uuid::Uuid;
use crate::{
errors::{KclError, KclErrorDetails},
execution::{
annotations, typed_path::TypedPath, types::UnitLen, ExecState, ExecutorContext, ImportedGeometry,
ModelingCmdMeta,
ExecState, ExecutorContext, ImportedGeometry, ModelingCmdMeta, annotations, typed_path::TypedPath,
types::UnitLen,
},
fs::FileSystem,
parsing::ast::types::{Annotation, Node},
@ -184,7 +184,7 @@ pub(super) fn format_from_annotations(
annotations::IMPORT_LENGTH_UNIT
),
vec![p.as_source_range()],
)))
)));
}
}
}
@ -225,7 +225,7 @@ fn set_coords(fmt: &mut InputFormat3d, coords_str: &str, source_range: SourceRan
annotations::IMPORT_COORDS
),
vec![source_range],
)))
)));
}
}
@ -246,7 +246,7 @@ fn set_length_unit(fmt: &mut InputFormat3d, units_str: &str, source_range: Sourc
annotations::IMPORT_LENGTH_UNIT
),
vec![source_range],
)))
)));
}
}
@ -291,7 +291,9 @@ fn get_import_format_from_extension(ext: &str) -> Result<InputFormat3d> {
} else if ext == "glb" {
FileImportFormat::Gltf
} else {
anyhow::bail!("unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format.")
anyhow::bail!(
"unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format."
)
}
}
};

View File

@ -6,12 +6,12 @@ use std::{
use anyhow::Result;
use crate::{
ExecState, ExecutorContext, KclError, ModuleId, SourceRange,
errors::KclErrorDetails,
execution::typed_path::TypedPath,
modules::{ModulePath, ModuleRepr},
parsing::ast::types::{ImportPath, ImportStatement, Node as AstNode},
walk::{Node, Visitable},
ExecState, ExecutorContext, KclError, ModuleId, SourceRange,
};
/// Specific dependency between two modules. The 0th element of this info
@ -147,7 +147,7 @@ fn import_dependencies(
ret.lock()
.map_err(|err| {
KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err),
format!("Failed to lock mutex: {err}"),
Default::default(),
))
})?
@ -157,7 +157,7 @@ fn import_dependencies(
ret.lock()
.map_err(|err| {
KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err),
format!("Failed to lock mutex: {err}"),
Default::default(),
))
})?
@ -179,7 +179,7 @@ fn import_dependencies(
let ret = ret.lock().map_err(|err| {
KclError::new_internal(KclErrorDetails::new(
format!("Failed to lock mutex: {}", err),
format!("Failed to lock mutex: {err}"),
Default::default(),
))
})?;
@ -224,7 +224,7 @@ pub(crate) async fn import_universe(
let repr = {
let Some(module_info) = exec_state.get_module(module_id) else {
return Err(KclError::new_internal(KclErrorDetails::new(
format!("Module {} not found", module_id),
format!("Module {module_id} not found"),
vec![import_stmt.into()],
)));
};
@ -244,9 +244,7 @@ mod tests {
use crate::parsing::ast::types::{ImportSelector, Program};
macro_rules! kcl {
( $kcl:expr ) => {{
$crate::parsing::top_level_parse($kcl).unwrap()
}};
( $kcl:expr_2021 ) => {{ $crate::parsing::top_level_parse($kcl).unwrap() }};
}
fn into_module_info(program: AstNode<Program>) -> DependencyInfo {

View File

@ -5,18 +5,18 @@ use schemars::JsonSchema;
use serde::Serialize;
use crate::{
CompilationError, KclError, ModuleId, SourceRange,
errors::KclErrorDetails,
execution::{
annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
EnvironmentRef, ExecState, Face, Geometry, GeometryWithImportedGeometry, Helix, ImportedGeometry, MetaSettings,
Metadata, Plane, Sketch, Solid, TagIdentifier,
annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
},
parsing::ast::types::{
DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode,
},
std::{args::TyF64, StdFnProps},
CompilationError, KclError, ModuleId, SourceRange,
std::{StdFnProps, args::TyF64},
};
pub type KclObjectFields = HashMap<String, KclValue>;
@ -136,9 +136,9 @@ impl JsonSchema for FunctionSource {
"FunctionSource".to_owned()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
// TODO: Actually generate a reasonable schema.
gen.subschema_for::<()>()
r#gen.subschema_for::<()>()
}
}
@ -415,15 +415,16 @@ impl KclValue {
/// Put the point into a KCL value.
pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec<Metadata>) -> Self {
let [x, y] = p;
Self::Tuple {
value: vec![
Self::Number {
value: p[0],
value: x,
meta: meta.clone(),
ty: ty.clone(),
ty,
},
Self::Number {
value: p[1],
value: y,
meta: meta.clone(),
ty,
},
@ -432,6 +433,56 @@ impl KclValue {
}
}
/// Put the point into a KCL value.
pub fn from_point3d(p: [f64; 3], ty: NumericType, meta: Vec<Metadata>) -> Self {
let [x, y, z] = p;
Self::Tuple {
value: vec![
Self::Number {
value: x,
meta: meta.clone(),
ty,
},
Self::Number {
value: y,
meta: meta.clone(),
ty,
},
Self::Number {
value: z,
meta: meta.clone(),
ty,
},
],
meta,
}
}
/// Put the point into a KCL point.
pub fn array_from_point3d(p: [f64; 3], ty: NumericType, meta: Vec<Metadata>) -> Self {
let [x, y, z] = p;
Self::HomArray {
value: vec![
Self::Number {
value: x,
meta: meta.clone(),
ty,
},
Self::Number {
value: y,
meta: meta.clone(),
ty,
},
Self::Number {
value: z,
meta: meta.clone(),
ty,
},
],
ty: ty.into(),
}
}
pub(crate) fn as_usize(&self) -> Option<usize> {
match self {
KclValue::Number { value, .. } => crate::try_f64_to_usize(*value),
@ -448,7 +499,7 @@ impl KclValue {
pub fn as_int_with_ty(&self) -> Option<(i64, NumericType)> {
match self {
KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, ty.clone())),
KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, *ty)),
_ => None,
}
}
@ -562,7 +613,7 @@ impl KclValue {
pub fn as_ty_f64(&self) -> Option<TyF64> {
match self {
KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())),
KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)),
_ => None,
}
}
@ -587,7 +638,7 @@ impl KclValue {
match self {
KclValue::TagIdentifier(t) => Ok(*t.clone()),
_ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag identifier: {:?}", self),
format!("Not a tag identifier: {self:?}"),
self.clone().into(),
))),
}
@ -598,7 +649,7 @@ impl KclValue {
match self {
KclValue::TagDeclarator(t) => Ok((**t).clone()),
_ => Err(KclError::new_semantic(KclErrorDetails::new(
format!("Not a tag declarator: {:?}", self),
format!("Not a tag declarator: {self:?}"),
self.clone().into(),
))),
}

View File

@ -207,8 +207,8 @@ use std::{
fmt,
pin::Pin,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc,
atomic::{AtomicBool, AtomicUsize, Ordering},
},
};
@ -489,7 +489,7 @@ impl ProgramMemory {
}
Err(KclError::new_undefined_value(
KclErrorDetails::new(format!("`{}` is not defined", var), vec![]),
KclErrorDetails::new(format!("`{var}` is not defined"), vec![]),
Some(var.to_owned()),
))
}
@ -541,22 +541,6 @@ impl Stack {
self.push_new_env_for_call(snapshot);
}
/// Push a new stack frame on to the call stack for callees which should not read or write
/// from memory.
///
/// This is suitable for calling standard library functions or other functions written in Rust
/// which will use 'Rust memory' rather than KCL's memory and cannot reach into the wider
/// environment.
///
/// Trying to read or write from this environment will panic with an index out of bounds.
pub fn push_new_env_for_rust_call(&mut self) {
self.call_stack.push(self.current_env);
// Rust functions shouldn't try to set or access anything in their environment, so don't
// waste time and space on a new env. Using usize::MAX means we'll get an overflow if we
// try to access anything rather than a silent error.
self.current_env = EnvironmentRef(usize::MAX, 0);
}
/// Push a new stack frame on to the call stack with no connection to a parent environment.
///
/// Suitable for executing a separate module.
@ -647,7 +631,7 @@ impl Stack {
let env = self.memory.get_env(self.current_env.index());
if env.contains_key(&key) {
return Err(KclError::new_value_already_defined(KclErrorDetails::new(
format!("Cannot redefine `{}`", key),
format!("Cannot redefine `{key}`"),
vec![source_range],
)));
}
@ -683,7 +667,7 @@ impl Stack {
env.contains_key(var)
}
/// Get a key from the first KCL (i.e., non-Rust) stack frame on the call stack.
/// Get a key from the first stack frame on the call stack.
pub fn get_from_call_stack(&self, key: &str, source_range: SourceRange) -> Result<(usize, &KclValue), KclError> {
if !self.current_env.skip_env() {
return Ok((self.current_env.1, self.get(key, source_range)?));
@ -695,7 +679,7 @@ impl Stack {
}
}
unreachable!("It can't be Rust frames all the way down");
unreachable!("No frames on the stack?");
}
/// Iterate over all keys in the current environment which satisfy the provided predicate.
@ -1047,7 +1031,7 @@ mod env {
}
/// Take all bindings from the environment.
pub(super) fn take_bindings(self: Pin<&mut Self>) -> impl Iterator<Item = (String, (usize, KclValue))> {
pub(super) fn take_bindings(self: Pin<&mut Self>) -> impl Iterator<Item = (String, (usize, KclValue))> + use<> {
// SAFETY: caller must have unique access since self is mut. We're not moving or invalidating `self`.
let bindings = std::mem::take(unsafe { self.bindings.get().as_mut().unwrap() });
bindings.into_iter()
@ -1217,24 +1201,6 @@ mod test {
assert_get_from(mem, "c", 5, callee);
}
#[test]
fn rust_env() {
let mem = &mut Stack::new_for_tests();
mem.add("a".to_owned(), val(1), sr()).unwrap();
mem.add("b".to_owned(), val(3), sr()).unwrap();
let sn = mem.snapshot();
mem.push_new_env_for_rust_call();
mem.push_new_env_for_call(sn);
assert_get(mem, "b", 3);
mem.add("b".to_owned(), val(4), sr()).unwrap();
assert_get(mem, "b", 4);
mem.pop_env();
mem.pop_env();
assert_get(mem, "b", 3);
}
#[test]
fn deep_call_env() {
let mem = &mut Stack::new_for_tests();

View File

@ -16,10 +16,9 @@ pub(crate) use import::PreImportedGeometry;
use indexmap::IndexMap;
pub use kcl_value::{KclObjectFields, KclValue};
use kcmc::{
each_cmd as mcmd,
ok_response::{output::TakeSnapshot, OkModelingCmdResponse},
ImageFormat, ModelingCmd, each_cmd as mcmd,
ok_response::{OkModelingCmdResponse, output::TakeSnapshot},
websocket::{ModelingSessionData, OkWebSocketResponseData},
ImageFormat, ModelingCmd,
};
use kittycad_modeling_cmds::{self as kcmc, id::ModelingCmdId};
pub use memory::EnvironmentRef;
@ -31,6 +30,7 @@ pub use state::{ExecState, MetaSettings};
use uuid::Uuid;
use crate::{
CompilationError, ExecError, KclErrorWithOutputs,
engine::{EngineManager, GridScaleBehavior},
errors::{KclError, KclErrorDetails},
execution::{
@ -43,7 +43,6 @@ use crate::{
modules::{ModuleId, ModulePath, ModuleRepr},
parsing::ast::types::{Expr, ImportPath, NodeRef},
source_range::SourceRange,
CompilationError, ExecError, KclErrorWithOutputs,
};
pub(crate) mod annotations;
@ -1329,7 +1328,7 @@ impl ExecutorContext {
created: if deterministic_time {
Some("2021-01-01T00:00:00Z".parse().map_err(|e| {
KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Failed to parse date: {}", e),
format!("Failed to parse date: {e}"),
vec![SourceRange::default()],
))
})?)
@ -1409,7 +1408,7 @@ pub(crate) async fn parse_execute_with_project_dir(
engine: Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| {
KclError::new_internal(crate::errors::KclErrorDetails::new(
format!("Failed to create mock engine connection: {}", err),
format!("Failed to create mock engine connection: {err}"),
vec![SourceRange::default()],
))
})?,
@ -1446,7 +1445,7 @@ mod tests {
use pretty_assertions::assert_eq;
use super::*;
use crate::{errors::KclErrorDetails, execution::memory::Stack, ModuleId};
use crate::{ModuleId, errors::KclErrorDetails, execution::memory::Stack};
/// Convenience function to get a JSON value from memory and unwrap.
#[track_caller]
@ -1921,6 +1920,22 @@ shape = layer() |> patternTransform(instances = 10, transform = transform)
);
}
#[tokio::test(flavor = "multi_thread")]
async fn pass_std_to_std() {
let ast = r#"sketch001 = startSketchOn(XY)
profile001 = circle(sketch001, center = [0, 0], radius = 2)
extrude001 = extrude(profile001, length = 5)
extrudes = patternLinear3d(
extrude001,
instances = 3,
distance = 5,
axis = [1, 1, 0],
)
clone001 = map(extrudes, f = clone)
"#;
parse_execute(ast).await.unwrap();
}
#[tokio::test(flavor = "multi_thread")]
async fn test_zero_param_fn() {
let ast = r#"sigmaAllow = 35000 // psi
@ -2045,8 +2060,7 @@ notFunction = !x";
fn_err
.message()
.starts_with("Cannot apply unary operator ! to non-boolean value: "),
"Actual error: {:?}",
fn_err
"Actual error: {fn_err:?}"
);
let code8 = "
@ -2059,8 +2073,7 @@ notTagDeclarator = !myTagDeclarator";
tag_declarator_err
.message()
.starts_with("Cannot apply unary operator ! to non-boolean value: a tag declarator"),
"Actual error: {:?}",
tag_declarator_err
"Actual error: {tag_declarator_err:?}"
);
let code9 = "
@ -2073,8 +2086,7 @@ notTagIdentifier = !myTag";
tag_identifier_err
.message()
.starts_with("Cannot apply unary operator ! to non-boolean value: a tag identifier"),
"Actual error: {:?}",
tag_identifier_err
"Actual error: {tag_identifier_err:?}"
);
let code10 = "notPipe = !(1 |> 2)";
@ -2226,7 +2238,7 @@ w = f() + f()
if let Err(err) = ctx.run_with_caching(old_program).await {
let report = err.into_miette_report_with_outputs(code).unwrap();
let report = miette::Report::new(report);
panic!("Error executing program: {:?}", report);
panic!("Error executing program: {report:?}");
}
// Get the id_generator from the first execution.

View File

@ -8,10 +8,10 @@ use uuid::Uuid;
#[cfg(feature = "artifact-graph")]
use crate::exec::ArtifactCommand;
use crate::{
ExecState, ExecutorContext, KclError, SourceRange,
exec::{IdGenerator, KclValue},
execution::Solid,
std::Args,
ExecState, ExecutorContext, KclError, SourceRange,
};
/// Context and metadata needed to send a single modeling command.

View File

@ -9,20 +9,19 @@ use uuid::Uuid;
#[cfg(feature = "artifact-graph")]
use crate::execution::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId};
use crate::{
CompilationError, EngineManager, ExecutorContext, KclErrorWithOutputs,
errors::{KclError, KclErrorDetails, Severity},
exec::DefaultPlanes,
execution::{
annotations,
EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, UnitAngle, UnitLen, annotations,
cad_op::Operation,
id_generator::IdGenerator,
memory::{ProgramMemory, Stack},
types::{self, NumericType},
EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue, UnitAngle, UnitLen,
},
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, ModuleSource},
parsing::ast::types::{Annotation, NodeRef},
source_range::SourceRange,
CompilationError, EngineManager, ExecutorContext, KclErrorWithOutputs,
};
/// State for executing a program.
@ -555,7 +554,7 @@ impl MetaSettings {
annotations::SETTINGS_UNIT_ANGLE
),
vec![annotation.as_source_range()],
)))
)));
}
}
}

View File

@ -220,9 +220,9 @@ impl schemars::JsonSchema for TypedPath {
"TypedPath".to_owned()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
// TODO: Actually generate a reasonable schema.
gen.subschema_for::<std::path::PathBuf>()
r#gen.subschema_for::<std::path::PathBuf>()
}
}

View File

@ -5,17 +5,17 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
CompilationError, SourceRange,
execution::{
ExecState, Plane, PlaneInfo, Point3d,
kcl_value::{KclValue, TypeDef},
memory::{self},
ExecState, Plane, PlaneInfo, Point3d,
},
parsing::{
ast::types::{PrimitiveType as AstPrimitiveType, Type},
token::NumericSuffix,
},
std::args::{FromKclValue, TyF64},
CompilationError, SourceRange,
};
#[derive(Debug, Clone, PartialEq)]
@ -210,7 +210,7 @@ impl RuntimeType {
let ty_val = exec_state
.stack()
.get(&format!("{}{}", memory::TYPE_PREFIX, alias), source_range)
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", alias)))?;
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {alias}")))?;
Ok(match ty_val {
KclValue::Type { value, .. } => match value {
@ -241,7 +241,7 @@ impl RuntimeType {
"a tuple with values of types ({})",
tys.iter().map(Self::human_friendly_type).collect::<Vec<_>>().join(", ")
),
RuntimeType::Object(_) => format!("an object with fields {}", self),
RuntimeType::Object(_) => format!("an object with fields {self}"),
}
}
@ -460,7 +460,7 @@ impl fmt::Display for PrimitiveType {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub enum NumericType {
@ -575,7 +575,7 @@ impl NumericType {
match (&ty, &i.ty) {
(Any, Default { .. }) if i.n == 0.0 => {}
(Any, t) => {
ty = t.clone();
ty = *t;
}
(_, Unknown) | (Default { .. }, Default { .. }) => return (result, Unknown),
@ -598,7 +598,7 @@ impl NumericType {
}
if ty == Any && !input.is_empty() {
ty = input[0].ty.clone();
ty = input[0].ty;
}
(result, ty)
@ -722,7 +722,7 @@ impl NumericType {
if ty.subtype(self) {
return Ok(KclValue::Number {
value: *value,
ty: ty.clone(),
ty: *ty,
meta: meta.clone(),
});
}
@ -736,7 +736,7 @@ impl NumericType {
(Any, _) => Ok(KclValue::Number {
value: *value,
ty: self.clone(),
ty: *self,
meta: meta.clone(),
}),
@ -744,7 +744,7 @@ impl NumericType {
// means accept any number rather than force the current default.
(_, Default { .. }) => Ok(KclValue::Number {
value: *value,
ty: ty.clone(),
ty: *ty,
meta: meta.clone(),
}),
@ -840,6 +840,18 @@ pub enum UnitType {
Angle(UnitAngle),
}
impl UnitType {
pub(crate) fn to_suffix(self) -> Option<String> {
match self {
UnitType::Count => Some("_".to_owned()),
UnitType::Length(UnitLen::Unknown) => None,
UnitType::Angle(UnitAngle::Unknown) => None,
UnitType::Length(l) => Some(l.to_string()),
UnitType::Angle(a) => Some(a.to_string()),
}
}
}
impl std::fmt::Display for UnitType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@ -1479,7 +1491,7 @@ impl KclValue {
pub fn principal_type(&self) -> Option<RuntimeType> {
match self {
KclValue::Bool { .. } => Some(RuntimeType::Primitive(PrimitiveType::Boolean)),
KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(ty.clone()))),
KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(*ty))),
KclValue::String { .. } => Some(RuntimeType::Primitive(PrimitiveType::String)),
KclValue::Object { value, .. } => {
let properties = value
@ -1529,7 +1541,7 @@ impl KclValue {
#[cfg(test)]
mod test {
use super::*;
use crate::execution::{parse_execute, ExecTestResults};
use crate::execution::{ExecTestResults, parse_execute};
fn values(exec_state: &mut ExecState) -> Vec<KclValue> {
vec![
@ -1975,14 +1987,16 @@ mod test {
])
)
);
assert!(RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any)),
RuntimeType::Primitive(PrimitiveType::Boolean)
])
.subtype(&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any)),
RuntimeType::Primitive(PrimitiveType::Boolean)
])));
assert!(
RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any)),
RuntimeType::Primitive(PrimitiveType::Boolean)
])
.subtype(&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Number(NumericType::Any)),
RuntimeType::Primitive(PrimitiveType::Boolean)
]))
);
// Covariance
let count = KclValue::Number {

View File

@ -45,6 +45,31 @@ pub fn format_number_literal(value: f64, suffix: NumericSuffix) -> Result<String
}
}
#[derive(Debug, Clone, PartialEq, Serialize, thiserror::Error)]
#[serde(tag = "type")]
pub enum FormatNumericTypeError {
#[error("Invalid numeric type: {0:?}")]
Invalid(NumericType),
}
/// For UI code generation, format a number value with a suffix such that the
/// result can parse as a literal. If it can't be done, returns an error.
///
/// This is used by TS.
pub fn format_number_value(value: f64, ty: NumericType) -> Result<String, FormatNumericTypeError> {
match ty {
NumericType::Default { .. } => Ok(value.to_string()),
// There isn't a syntactic suffix for these. For unknown, we don't want
// to ever generate the unknown suffix. We currently warn on it, and we
// may remove it in the future.
NumericType::Unknown | NumericType::Any => Err(FormatNumericTypeError::Invalid(ty)),
NumericType::Known(unit_type) => unit_type
.to_suffix()
.map(|suffix| format!("{value}{suffix}"))
.ok_or(FormatNumericTypeError::Invalid(ty)),
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
@ -134,4 +159,74 @@ mod tests {
Err(FormatNumericSuffixError::Invalid(NumericSuffix::Unknown))
);
}
#[test]
fn test_format_number_value() {
assert_eq!(
format_number_value(
1.0,
NumericType::Default {
len: Default::default(),
angle: Default::default()
}
),
Ok("1".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Unknown))),
Err(FormatNumericTypeError::Invalid(NumericType::Known(UnitType::Length(
UnitLen::Unknown
))))
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Unknown))),
Err(FormatNumericTypeError::Invalid(NumericType::Known(UnitType::Angle(
UnitAngle::Unknown
))))
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Count)),
Ok("1_".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Mm))),
Ok("1mm".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Cm))),
Ok("1cm".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::M))),
Ok("1m".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Inches))),
Ok("1in".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Feet))),
Ok("1ft".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Length(UnitLen::Yards))),
Ok("1yd".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Degrees))),
Ok("1deg".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Radians))),
Ok("1rad".to_owned())
);
assert_eq!(
format_number_value(1.0, NumericType::Unknown),
Err(FormatNumericTypeError::Invalid(NumericType::Unknown))
);
assert_eq!(
format_number_value(1.0, NumericType::Any),
Err(FormatNumericTypeError::Invalid(NumericType::Any))
);
}
}

View File

@ -3,10 +3,10 @@
use anyhow::Result;
use crate::{
SourceRange,
errors::{KclError, KclErrorDetails},
execution::typed_path::TypedPath,
fs::FileSystem,
SourceRange,
};
#[derive(Debug, Clone)]

View File

@ -2,7 +2,7 @@
use anyhow::Result;
use crate::{execution::typed_path::TypedPath, SourceRange};
use crate::{SourceRange, execution::typed_path::TypedPath};
#[cfg(not(target_arch = "wasm32"))]
pub mod local;

View File

@ -4,11 +4,11 @@ use anyhow::Result;
use wasm_bindgen::prelude::wasm_bindgen;
use crate::{
SourceRange,
errors::{KclError, KclErrorDetails},
execution::typed_path::TypedPath,
fs::FileSystem,
wasm::JsFuture,
SourceRange,
};
#[wasm_bindgen(module = "/../../src/lang/std/fileSystemManager.ts")]

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