Merge branch 'main' into nadro/adhoc/system-io-machine
4
.github/workflows/e2e-tests.yml
vendored
@ -285,7 +285,7 @@ jobs:
|
||||
# TODO: enable namespace-profile-windows-latest once available
|
||||
os:
|
||||
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
|
||||
- namespace-profile-macos-8-cores
|
||||
- namespace-profile-macos-6-cores
|
||||
- windows-latest-8-cores
|
||||
shardIndex: [1, 2, 3, 4]
|
||||
shardTotal: [4]
|
||||
@ -295,7 +295,7 @@ jobs:
|
||||
isScheduled:
|
||||
- ${{ github.event_name == 'schedule' }}
|
||||
exclude:
|
||||
- os: namespace-profile-macos-8-cores
|
||||
- os: namespace-profile-macos-6-cores
|
||||
isScheduled: true
|
||||
- os: windows-latest-8-cores
|
||||
isScheduled: true
|
||||
|
||||
2
.github/workflows/static-analysis.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm run fmt-check
|
||||
- run: npm run fmt:check
|
||||
|
||||
npm-build-wasm:
|
||||
# Build the wasm blob once on the fastest runner.
|
||||
|
||||
1
.gitignore
vendored
@ -84,3 +84,4 @@ dist
|
||||
venv
|
||||
|
||||
.vscode-test
|
||||
.biome/
|
||||
|
||||
54
README.md
@ -250,55 +250,29 @@ You will need a `./e2e/playwright/playwright-secrets.env` file:
|
||||
$ touch ./e2e/playwright/playwright-secrets.env
|
||||
$ cat ./e2e/playwright/playwright-secrets.env
|
||||
token=<dev.zoo.dev/account/api-tokens>
|
||||
snapshottoken=<your-snapshot-token>
|
||||
snapshottoken=<zoo.dev/account/api-tokens>
|
||||
```
|
||||
or use `export` to set the environment variables `token` and `snapshottoken`.
|
||||
|
||||
For a portable way to run Playwright you'll need Docker.
|
||||
#### Snapshot tests (Google Chrome on Ubuntu only)
|
||||
|
||||
#### Generic example
|
||||
|
||||
After that, open a terminal and run:
|
||||
|
||||
```bash
|
||||
docker run --network host --rm --init -it playwright/chrome:playwright-x.xx.x
|
||||
Only Ubunu and Google Chrome is supported for the set of tests evaluating screenshot snapshots.
|
||||
If you don't run Ubuntu locally or in a VM, you may use a GitHub Codespace.
|
||||
```
|
||||
|
||||
and in another terminal, run:
|
||||
|
||||
```bash
|
||||
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ npm run playwright test --project="Google Chrome" <test suite>
|
||||
npm run playwright -- install chrome
|
||||
npm run test:snapshots
|
||||
```
|
||||
You may use `-- --update-snapshots` as needed.
|
||||
|
||||
#### Specific example
|
||||
|
||||
open a terminal and run:
|
||||
|
||||
```bash
|
||||
docker run --network host --rm --init -it playwright/chrome:playwright-1.46.0
|
||||
```
|
||||
|
||||
and in another terminal, run:
|
||||
|
||||
```bash
|
||||
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ npm run playwright test --project="Google Chrome" e2e/playwright/command-bar-tests.spec.ts
|
||||
```
|
||||
|
||||
run a specific test change the test from `test('...` to `test.only('...`
|
||||
(note if you commit this, the tests will instantly fail without running any of the tests)
|
||||
|
||||
**Gotcha**: running the docker container with a mismatched image against your `./node_modules/playwright` will cause a failure. Make sure the versions are matched and up to date.
|
||||
|
||||
run headed
|
||||
#### Electron flow tests (Chromium on Ubuntu, macOS, Windows)
|
||||
|
||||
```
|
||||
npm run playwright test --headed
|
||||
npm run playwright -- install chromium
|
||||
npm run test:playwright:electron:local
|
||||
```
|
||||
You may use `-- -g "my test"` to match specific test titles, or `-- path/to/file.spec.ts` for a test file.
|
||||
|
||||
run with step through debugger
|
||||
|
||||
```
|
||||
PWDEBUG=1 npm run playwright test
|
||||
```
|
||||
#### Debugger
|
||||
|
||||
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
|
||||
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
|
||||
@ -446,7 +420,7 @@ npm run test-setup
|
||||
|
||||
```
|
||||
npm run tsc
|
||||
npm run fmt-check
|
||||
npm run fmt:check
|
||||
npm run lint
|
||||
npm run test:unit:local
|
||||
```
|
||||
|
||||
48
biome.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.6.0/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"correctness": {
|
||||
"noUnusedVariables": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "warn"
|
||||
},
|
||||
"style": {
|
||||
"useBlockStatements": "error",
|
||||
"useShorthandArrayType": "error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentWidth": 2,
|
||||
"indentStyle": "space",
|
||||
"lineWidth": 80,
|
||||
"formatWithErrors": true
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "single",
|
||||
"jsxQuoteStyle": "double",
|
||||
"trailingCommas": "es5",
|
||||
"semicolons": "asNeeded"
|
||||
},
|
||||
"parser": {
|
||||
"unsafeParameterDecoratorsEnabled": true
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"parser": {
|
||||
"cssModules": true
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"ignore": ["**/*.json"]
|
||||
}
|
||||
}
|
||||
@ -10,8 +10,10 @@ Draw an angled line from the current origin, constructing a line segment such th
|
||||
|
||||
```js
|
||||
angledLineThatIntersects(
|
||||
data: AngledLineThatIntersectsData,
|
||||
sketch: Sketch,
|
||||
angle: number,
|
||||
intersectTag: TagIdentifier,
|
||||
offset?: number,
|
||||
tag?: TagDeclarator,
|
||||
): Sketch
|
||||
```
|
||||
@ -21,9 +23,11 @@ angledLineThatIntersects(
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `data` | [`AngledLineThatIntersectsData`](/docs/kcl/types/AngledLineThatIntersectsData) | Data for drawing an angled line that intersects with a given line. | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
|
||||
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes |
|
||||
| `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes |
|
||||
| `intersectTag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The tag of the line to intersect with | Yes |
|
||||
| `offset` | [`number`](/docs/kcl/types/number) | The offset from the intersecting line. Defaults to 0. | No |
|
||||
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -38,11 +42,7 @@ exampleSketch = startSketchOn(XZ)
|
||||
|> line(endAbsolute = [5, 10])
|
||||
|> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
|
||||
|> line(endAbsolute = [0, 20])
|
||||
|> angledLineThatIntersects({
|
||||
angle = 80,
|
||||
intersectTag = lineToIntersect,
|
||||
offset = 10
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 80, intersectTag = lineToIntersect, offset = 10)
|
||||
|> close()
|
||||
|
||||
example = extrude(exampleSketch, length = 10)
|
||||
|
||||
4988
docs/kcl/std.json
@ -145,7 +145,7 @@ This helps keep your code neat and avoid unnecessary declarations.
|
||||
Say you have a long pipeline of sketch functions, like this:
|
||||
|
||||
```norun
|
||||
startSketchOn('XZ')
|
||||
startSketchOn(XZ)
|
||||
|> line(%, end = [3, 4])
|
||||
|> line(%, end = [10, 10])
|
||||
|> line(%, end = [-13, -14])
|
||||
@ -160,7 +160,7 @@ means that `|> line(%, end = [3, 4])` and `|> line(end = [3, 4])` are equivalent
|
||||
could be rewritten as
|
||||
|
||||
```norun
|
||||
startSketchOn('XZ')
|
||||
startSketchOn(XZ)
|
||||
|> line(end = [3, 4])
|
||||
|> line(end = [10, 10])
|
||||
|> line(end = [-13, -14])
|
||||
@ -182,7 +182,7 @@ The syntax for declaring a tag is `$myTag` you would use it in the following
|
||||
way:
|
||||
|
||||
```norun
|
||||
startSketchOn('XZ')
|
||||
startSketchOn(XZ)
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|
||||
|> angledLine(
|
||||
@ -217,7 +217,7 @@ However if the code was written like this:
|
||||
|
||||
```norun
|
||||
fn rect(origin) {
|
||||
return startSketchOn('XZ')
|
||||
return startSketchOn(XZ)
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|
||||
|> angledLine(
|
||||
@ -227,7 +227,7 @@ fn rect(origin) {
|
||||
)
|
||||
|> angledLine(
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001)
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
tag = $rectangleSegmentC001,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -247,7 +247,7 @@ For example the following code works.
|
||||
|
||||
```norun
|
||||
fn rect(origin) {
|
||||
return startSketchOn('XZ')
|
||||
return startSketchOn(XZ)
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001)
|
||||
|> angledLine(
|
||||
@ -257,7 +257,7 @@ fn rect(origin) {
|
||||
)
|
||||
|> angledLine(
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001)
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
tag = $rectangleSegmentC001,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -268,11 +268,8 @@ rect([0, 0])
|
||||
myRect = rect([20, 0])
|
||||
|
||||
myRect
|
||||
|> extrude(10, %)
|
||||
|> fillet(
|
||||
radius = 0.5,
|
||||
tags = [myRect.tags.rectangleSegmentA001]
|
||||
)
|
||||
|> extrude(length = 10)
|
||||
|> fillet(radius = 0.5, tags = [myRect.tags.rectangleSegmentA001])
|
||||
```
|
||||
|
||||
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
||||
|
||||
@ -94,11 +94,8 @@ rect([0, 0])
|
||||
myRect = rect([20, 0])
|
||||
|
||||
myRect
|
||||
|> extrude(10, %)
|
||||
|> fillet(
|
||||
radius = 0.5,
|
||||
tags = [myRect.tags.rectangleSegmentA001]
|
||||
)
|
||||
|> extrude(length = 10)
|
||||
|> fillet(radius = 0.5, tags = [myRect.tags.rectangleSegmentA001])
|
||||
```
|
||||
|
||||
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
||||
|
||||
@ -66,15 +66,17 @@ async function doBasicSketch(
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
await expect(
|
||||
u.codeLocator
|
||||
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})`)
|
||||
}
|
||||
await page.waitForTimeout(500)
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
await expect(
|
||||
u.codeLocator
|
||||
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})
|
||||
@ -85,8 +87,9 @@ async function doBasicSketch(
|
||||
await page.waitForTimeout(200)
|
||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
await expect(
|
||||
u.codeLocator
|
||||
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})
|
||||
@ -142,8 +145,9 @@ async function doBasicSketch(
|
||||
|
||||
// Open the code pane.
|
||||
await u.openKclCodePanel()
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
await expect(
|
||||
u.codeLocator
|
||||
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1}, tag = $seg01)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { join } from 'path'
|
||||
import { bracket } from '@e2e/playwright/fixtures/bracket'
|
||||
import fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from '@e2e/playwright/storageStates'
|
||||
import {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import path, { join } from 'path'
|
||||
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
|
||||
import * as fsp from 'fs/promises'
|
||||
import path, { join } from 'path'
|
||||
|
||||
import {
|
||||
executorInputPath,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
import fsp from 'fs/promises'
|
||||
|
||||
import {
|
||||
executorInputPath,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { join } from 'path'
|
||||
import { uuidv4 } from '@src/lib/utils'
|
||||
import fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import {
|
||||
TEST_COLORS,
|
||||
@ -82,7 +82,7 @@ sketch001 = startSketchOn(XY)
|
||||
.poll(() =>
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]').count()
|
||||
)
|
||||
.toBe(1)
|
||||
.toBe(2)
|
||||
await expect
|
||||
.poll(() => page.locator('[data-message-type="execution-done"]').count())
|
||||
.toBe(2)
|
||||
@ -106,7 +106,7 @@ sketch001 = startSketchOn(XY)
|
||||
).toHaveCount(3)
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(1)
|
||||
).toHaveCount(2)
|
||||
})
|
||||
|
||||
test('ensure we use the cache, and do not clear on append', async ({
|
||||
@ -133,7 +133,7 @@ sketch001 = startSketchOn(XY)
|
||||
await u.openDebugPanel()
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(1)
|
||||
).toHaveCount(2)
|
||||
await expect(
|
||||
page.locator('[data-message-type="execution-done"]')
|
||||
).toHaveCount(2)
|
||||
@ -161,7 +161,7 @@ sketch001 = startSketchOn(XY)
|
||||
).toHaveCount(3)
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(1)
|
||||
).toHaveCount(2)
|
||||
})
|
||||
|
||||
test('if you click the format button it formats your code', async ({
|
||||
@ -409,8 +409,9 @@ sketch_001 = startSketchOn(XY)
|
||||
// Hit alt+shift+f to format the code
|
||||
await page.keyboard.press('Alt+Shift+KeyF')
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`sketch001 = startSketchOn(XY)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`sketch001 = startSketchOn(XY)
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line(end = [20, 0])
|
||||
|> line(end = [0, 20])
|
||||
@ -462,8 +463,9 @@ sketch_001 = startSketchOn(XY)
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.closeDebugPanel()
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`sketch_001 = startSketchOn(XY)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`sketch_001 = startSketchOn(XY)
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line(end = [20, 0])
|
||||
|> line(end = [0, 20])
|
||||
@ -978,8 +980,9 @@ sketch001 = startSketchOn(XZ)
|
||||
await page.keyboard.up('Control')
|
||||
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line(end = [12.73, -0.09])
|
||||
|> tangentialArc(endAbsolute = [24.95, -5.38])
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import * as fsp from 'fs/promises'
|
||||
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { FILE_EXT } from '@src/lib/constants'
|
||||
import * as fs from 'fs'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import { FILE_EXT } from '@src/lib/constants'
|
||||
import * as fsp from 'fs/promises'
|
||||
|
||||
import {
|
||||
createProject,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { Locator, Page, Request, Route, TestInfo } from '@playwright/test'
|
||||
import { expect } from '@playwright/test'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import type { Locator, Page, Request, Route, TestInfo } from '@playwright/test'
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
type CmdBarSerialised =
|
||||
export type CmdBarSerialised =
|
||||
| {
|
||||
stage: 'commandBarClosed'
|
||||
}
|
||||
|
||||
@ -7,11 +7,11 @@ import type {
|
||||
} from '@playwright/test'
|
||||
import { _electron as electron } from '@playwright/test'
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'path'
|
||||
import { SETTINGS_FILE_NAME } from '@src/lib/constants'
|
||||
import type { DeepPartial } from '@src/lib/types'
|
||||
import fsp from 'fs/promises'
|
||||
import fs from 'node:fs'
|
||||
import path from 'path'
|
||||
|
||||
import type { Settings } from '@rust/kcl-lib/bindings/Settings'
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ export class SceneFixture {
|
||||
public page: Page
|
||||
public streamWrapper!: Locator
|
||||
public networkToggleConnected!: Locator
|
||||
public engineConnectionsSpinner!: Locator
|
||||
public startEditSketchBtn!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
@ -52,6 +53,7 @@ export class SceneFixture {
|
||||
this.networkToggleConnected = page
|
||||
.getByTestId('network-toggle-ok')
|
||||
.or(page.getByTestId('network-toggle-other'))
|
||||
this.engineConnectionsSpinner = page.getByTestId(`loading-engine`)
|
||||
this.startEditSketchBtn = page
|
||||
.getByRole('button', { name: 'Start Sketch' })
|
||||
.or(page.getByRole('button', { name: 'Edit Sketch' }))
|
||||
@ -228,6 +230,7 @@ export class SceneFixture {
|
||||
connectionEstablished = async () => {
|
||||
const timeout = 30000
|
||||
await expect(this.networkToggleConnected).toBeVisible({ timeout })
|
||||
await expect(this.engineConnectionsSpinner).not.toBeVisible()
|
||||
}
|
||||
|
||||
settled = async (cmdBar: CmdBarFixture) => {
|
||||
@ -235,6 +238,7 @@ export class SceneFixture {
|
||||
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled({ timeout: 15_000 })
|
||||
await expect(this.startEditSketchBtn).toBeVisible()
|
||||
await expect(this.engineConnectionsSpinner).not.toBeVisible()
|
||||
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('Settings · app · show debug panel')
|
||||
|
||||
@ -27,6 +27,7 @@ export class ToolbarFixture {
|
||||
offsetPlaneButton!: Locator
|
||||
helixButton!: Locator
|
||||
startSketchBtn!: Locator
|
||||
insertButton!: Locator
|
||||
lineBtn!: Locator
|
||||
tangentialArcBtn!: Locator
|
||||
circleBtn!: Locator
|
||||
@ -44,7 +45,7 @@ export class ToolbarFixture {
|
||||
featureTreePane!: Locator
|
||||
gizmo!: Locator
|
||||
gizmoDisabled!: Locator
|
||||
insertButton!: Locator
|
||||
loadButton!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
@ -59,6 +60,7 @@ export class ToolbarFixture {
|
||||
this.offsetPlaneButton = page.getByTestId('plane-offset')
|
||||
this.helixButton = page.getByTestId('helix')
|
||||
this.startSketchBtn = page.getByTestId('sketch')
|
||||
this.insertButton = page.getByTestId('insert')
|
||||
this.lineBtn = page.getByTestId('line')
|
||||
this.tangentialArcBtn = page.getByTestId('tangential-arc')
|
||||
this.circleBtn = page.getByTestId('circle-center')
|
||||
@ -68,6 +70,7 @@ export class ToolbarFixture {
|
||||
this.fileTreeBtn = page.locator('[id="files-button-holder"]')
|
||||
this.createFileBtn = page.getByTestId('create-file-button')
|
||||
this.treeInputField = page.getByTestId('tree-input-field')
|
||||
this.loadButton = page.getByTestId('load-external-model-pane-button')
|
||||
|
||||
this.filePane = page.locator('#files-pane')
|
||||
this.featureTreePane = page.locator('#feature-tree-pane')
|
||||
@ -79,8 +82,6 @@ export class ToolbarFixture {
|
||||
// element or two different elements can represent these states.
|
||||
this.gizmo = page.getByTestId('gizmo')
|
||||
this.gizmoDisabled = page.getByTestId('gizmo-disabled')
|
||||
|
||||
this.insertButton = page.getByTestId('insert-pane-button')
|
||||
}
|
||||
|
||||
get logoLink() {
|
||||
@ -204,6 +205,11 @@ export class ToolbarFixture {
|
||||
).toBeVisible()
|
||||
await this.page.getByTestId('dropdown-three-point-arc').click()
|
||||
}
|
||||
selectLine = async () => {
|
||||
await this.page
|
||||
.getByRole('button', { name: 'line Line', exact: true })
|
||||
.click()
|
||||
}
|
||||
|
||||
async closePane(paneId: SidebarType) {
|
||||
return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import path from 'path'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
import * as fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
test.describe('Import UI tests', () => {
|
||||
test('shows toast when trying to sketch on imported face', async ({
|
||||
test('shows toast when trying to sketch on imported face, and hovering over imported geometry should NOT highlight any code', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
@ -93,7 +93,6 @@ sketch002 = startSketchOn(extrude001, face = seg01)`
|
||||
await toolbar.startSketchPlaneSelection()
|
||||
|
||||
// Click on a face from the imported model
|
||||
// await new Promise(() => {})
|
||||
await importedFaceClick()
|
||||
|
||||
// Verify toast appears with correct content
|
||||
|
||||
@ -19,8 +19,9 @@ class MyAPIReporter implements Reporter {
|
||||
target: process.env.TARGET || null,
|
||||
platform: process.env.RUNNER_OS || process.platform,
|
||||
// Extra test and result data
|
||||
annotations: test.annotations.map((a) => a.type), // e.g. 'fail' or 'fixme'
|
||||
retry: result.retry,
|
||||
tags: test.tags,
|
||||
tags: test.tags, // e.g. '@snapshot' or '@skipWin'
|
||||
// Extra environment variables
|
||||
CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
|
||||
CI_PR_NUMBER: process.env.CI_PR_NUMBER || null,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import fsp from 'fs/promises'
|
||||
|
||||
import { executorInputPath } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { join } from 'path'
|
||||
import { PROJECT_SETTINGS_FILE_NAME } from '@src/lib/constants'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
||||
|
||||
|
||||
@ -534,7 +534,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
const expected = 'Open project'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('Modeling.File.Load a sample model', async ({
|
||||
test('Modeling.File.Load external model', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
@ -555,10 +555,10 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
throw new Error('app or app.applicationMenu is missing')
|
||||
}
|
||||
const openProject = app.applicationMenu.getMenuItemById(
|
||||
'File.Load a sample model'
|
||||
'File.Load external model'
|
||||
)
|
||||
if (!openProject) {
|
||||
throw new Error('File.Load a sample model')
|
||||
throw new Error('File.Load external model')
|
||||
}
|
||||
openProject.click()
|
||||
})
|
||||
@ -568,44 +568,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Open sample'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('Modeling.File.Insert from project file', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
throwTronAppMissing()
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
throw new Error('app or app.applicationMenu is missing')
|
||||
}
|
||||
const openProject = app.applicationMenu.getMenuItemById(
|
||||
'File.Insert from project file'
|
||||
)
|
||||
if (!openProject) {
|
||||
throw new Error('File.Insert from project file')
|
||||
}
|
||||
openProject.click()
|
||||
})
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Insert'
|
||||
const expected = 'Load external model'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
test('Modeling.File.Export current part', async ({
|
||||
@ -2159,6 +2122,44 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
test('Modeling.Design.Insert from project file', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
throwTronAppMissing()
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
throw new Error('app or app.applicationMenu is missing')
|
||||
}
|
||||
const openProject = app.applicationMenu.getMenuItemById(
|
||||
'Design.Insert from project file'
|
||||
)
|
||||
if (!openProject) {
|
||||
throw new Error('Design.Insert from project file')
|
||||
}
|
||||
openProject.click()
|
||||
})
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = 'Insert'
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
test('Modeling.Design.Create with Zoo Text-To-CAD', async ({
|
||||
tronApp,
|
||||
cmdBar,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { join } from 'path'
|
||||
import { bracket } from '@e2e/playwright/fixtures/bracket'
|
||||
import { onboardingPaths } from '@src/routes/Onboarding/paths'
|
||||
import fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import { expectPixelColor } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
import {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
import * as fsp from 'fs/promises'
|
||||
|
||||
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import type { Locator, Page } from '@playwright/test'
|
||||
|
||||
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
|
||||
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { DEFAULT_PROJECT_KCL_FILE } from '@src/lib/constants'
|
||||
import fs from 'fs'
|
||||
import fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { DEFAULT_PROJECT_KCL_FILE } from '@src/lib/constants'
|
||||
import fsp from 'fs/promises'
|
||||
|
||||
import type { Paths } from '@e2e/playwright/test-utils'
|
||||
import {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import path from 'path'
|
||||
import { bracket } from '@e2e/playwright/fixtures/bracket'
|
||||
import type { Page } from '@playwright/test'
|
||||
import { reportRejection } from '@src/lib/trap'
|
||||
import * as fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from '@e2e/playwright/storageStates'
|
||||
import type { TestColor } from '@e2e/playwright/test-utils'
|
||||
@ -304,8 +304,9 @@ extrude001 = extrude(sketch001, length = 50)
|
||||
await page.keyboard.press('Enter')
|
||||
await page.keyboard.press('ArrowLeft')
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toContainText(`exampleSketch = startSketchOn("XZ")
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toContainText(`exampleSketch = startSketchOn("XZ")
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine(angle = 50, length = 45 )
|
||||
|> yLine(endAbsolute = 0)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
import { roundOff, uuidv4 } from '@src/lib/utils'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import type { Page } from '@playwright/test'
|
||||
import { roundOff, uuidv4 } from '@src/lib/utils'
|
||||
|
||||
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
|
||||
@ -161,7 +161,8 @@ sketch001 = startSketchOn(XZ)
|
||||
// click to add segment
|
||||
await page.mouse.click(700, 200)
|
||||
|
||||
await expect.poll(u.normalisedEditorCode, { timeout: 1000 })
|
||||
await expect
|
||||
.poll(u.normalisedEditorCode, { timeout: 1000 })
|
||||
.toBe(`@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
@ -403,8 +404,9 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|
||||
await u.openKclCodePanel()
|
||||
|
||||
// expect the code to have changed
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([6.44, -12.07], %)
|
||||
|> line(end = [14.72, 1.97])
|
||||
|> tangentialArc(endAbsolute = [26.92, -3.32])
|
||||
@ -1363,73 +1365,6 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Sketch mode should be toleratant to syntax errors', () => {
|
||||
test(
|
||||
'adding a syntax error, recovers after fixing',
|
||||
{ tag: ['@skipWin'] },
|
||||
async ({ page, homePage, context, scene, editor, toolbar }) => {
|
||||
const file = await fs.readFile(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'../../',
|
||||
'./rust/kcl-lib/e2e/executor/inputs/e2e-can-sketch-on-chamfer.kcl'
|
||||
),
|
||||
'utf-8'
|
||||
)
|
||||
await context.addInitScript((file) => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
const [objClick] = scene.makeMouseHelpers(600, 250)
|
||||
const arrowHeadLocation = { x: 706, y: 129 } as const
|
||||
const arrowHeadWhite = TEST_COLORS.WHITE
|
||||
const backgroundGray: [number, number, number] = [28, 28, 28]
|
||||
const verifyArrowHeadColor = async (c: [number, number, number]) =>
|
||||
scene.expectPixelColor(c, arrowHeadLocation, 15)
|
||||
|
||||
await test.step('check chamfer selection changes cursor positon', async () => {
|
||||
await expect(async () => {
|
||||
// sometimes initial click doesn't register
|
||||
await objClick()
|
||||
await editor.expectActiveLinesToBe([
|
||||
'|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]',
|
||||
])
|
||||
}).toPass({ timeout: 15_000, intervals: [500] })
|
||||
})
|
||||
|
||||
await test.step('enter sketch and sanity check segments have been drawn', async () => {
|
||||
await toolbar.editSketch()
|
||||
// this checks sketch segments have been drawn
|
||||
await verifyArrowHeadColor(arrowHeadWhite)
|
||||
})
|
||||
|
||||
await test.step('Make typo and check the segments have Disappeared and there is a syntax error', async () => {
|
||||
await editor.replaceCode('line(endAbsolute = [pro', 'badBadBadFn([pro')
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: ['memoryitemkey`badBadBadFn`isnotdefined'],
|
||||
highlightedCode: '',
|
||||
})
|
||||
// this checks sketch segments have failed to be drawn
|
||||
await verifyArrowHeadColor(backgroundGray)
|
||||
})
|
||||
|
||||
await test.step('', async () => {
|
||||
await editor.replaceCode('badBadBadFn([pro', 'line(endAbsolute = [pro')
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: [],
|
||||
highlightedCode: '',
|
||||
})
|
||||
// this checks sketch segments have been drawn
|
||||
await verifyArrowHeadColor(arrowHeadWhite)
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test.describe(`Sketching with offset planes`, () => {
|
||||
test(`Can select an offset plane to sketch on`, async ({
|
||||
context,
|
||||
@ -1623,6 +1558,7 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`@settings(defaultLengthUnit = in)
|
||||
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile002 = startProfileAt([40.68, 87.67], sketch001)
|
||||
|> xLine(length = 239.17)
|
||||
@ -3034,4 +2970,387 @@ test.describe('Redirecting to home page and back to the original file should cle
|
||||
await homePage.openProject('testDefault')
|
||||
await expect(page.getByText('323.49')).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('Straight line snapping to previous tangent', async ({
|
||||
page,
|
||||
homePage,
|
||||
toolbar,
|
||||
scene,
|
||||
cmdBar,
|
||||
context,
|
||||
editor,
|
||||
}) => {
|
||||
await context.addInitScript(() => {
|
||||
localStorage.setItem('persistCode', `@settings(defaultLengthUnit = mm)`)
|
||||
})
|
||||
|
||||
const viewportSize = { width: 1200, height: 900 }
|
||||
await page.setBodyDimensions(viewportSize)
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// wait until scene is ready to be interacted with
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||
|
||||
// select an axis plane
|
||||
await page.mouse.click(700, 200)
|
||||
|
||||
// Needed as we don't yet have a way to get a signal from the engine that the camera has animated to the sketch plane
|
||||
await page.waitForTimeout(3000)
|
||||
|
||||
const center = { x: viewportSize.width / 2, y: viewportSize.height / 2 }
|
||||
const { click00r } = getMovementUtils({ center, page })
|
||||
|
||||
// Draw line
|
||||
await click00r(0, 0)
|
||||
await click00r(200, -200)
|
||||
|
||||
// Draw arc
|
||||
await toolbar.tangentialArcBtn.click()
|
||||
await click00r(0, 0)
|
||||
await click00r(100, 100)
|
||||
|
||||
// Switch back to line
|
||||
await toolbar.selectLine()
|
||||
await click00r(0, 0)
|
||||
await click00r(-100, 100)
|
||||
|
||||
// Draw a 3 point arc
|
||||
await toolbar.selectThreePointArc()
|
||||
await click00r(0, 0)
|
||||
await click00r(0, 100)
|
||||
await click00r(100, 0)
|
||||
|
||||
// draw a line to opposite tangnet direction of previous arc
|
||||
await toolbar.selectLine()
|
||||
await click00r(0, 0)
|
||||
await click00r(-200, 200)
|
||||
|
||||
await editor.expectEditor.toContain(
|
||||
`@settings(defaultLengthUnit = mm)
|
||||
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([0, 0], sketch001)
|
||||
|> line(end = [191.39, 191.39])
|
||||
|> tangentialArc(endAbsolute = [287.08, 95.69], tag = $seg01)
|
||||
|> angledLine(angle = tangentToEnd(seg01), length = 135.34)
|
||||
|> arcTo({
|
||||
interior = [191.39, -95.69],
|
||||
end = [287.08, -95.69]
|
||||
}, %, $seg02)
|
||||
|> angledLine(angle = tangentToEnd(seg02) + turns::HALF_TURN, length = 270.67)
|
||||
`.replaceAll('\n', '')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('manual edits during sketch mode', () => {
|
||||
test('Can edit sketch through feature tree with variable modifications', async ({
|
||||
page,
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `myVar1 = 5
|
||||
myVar2 = 6
|
||||
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([106.68, 89.77], sketch001)
|
||||
|> line(end = [132.34, 157.8])
|
||||
|> line(end = [67.65, -460.55], tag = $seg01)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude001 = extrude(profile001, length = 500)
|
||||
sketch002 = startSketchOn(extrude001, face = seg01)
|
||||
profile002 = startProfileAt([83.39, 329.15], sketch002)
|
||||
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|
||||
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 156.54, angle = -28)
|
||||
|> angledLine(
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
angle = -151,
|
||||
length = 116.27,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
profile003 = startProfileAt([-201.08, 254.17], sketch002)
|
||||
|> line(end = [103.55, 33.32])
|
||||
|> line(end = [48.8, -153.54])`
|
||||
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
const expectSketchOriginToBeDrawn = async () => {
|
||||
await scene.expectPixelColor(TEST_COLORS.WHITE, { x: 672, y: 193 }, 15)
|
||||
}
|
||||
|
||||
await test.step('Open feature tree and edit second sketch', async () => {
|
||||
await toolbar.openFeatureTreePane()
|
||||
const sketchButton = await toolbar.getFeatureTreeOperation('Sketch', 1)
|
||||
await sketchButton.dblclick()
|
||||
await page.waitForTimeout(700) // Wait for engine animation
|
||||
await expectSketchOriginToBeDrawn()
|
||||
})
|
||||
|
||||
await test.step('Add new variable and wait for re-execution', async () => {
|
||||
await page.waitForTimeout(500) // wait for deferred execution
|
||||
await editor.replaceCode('myVar2 = 6', 'myVar2 = 6\nmyVar3 = 7')
|
||||
await page.waitForTimeout(2000) // wait for deferred execution
|
||||
await expectSketchOriginToBeDrawn()
|
||||
})
|
||||
|
||||
const handle1Location = { x: 843, y: 235 }
|
||||
|
||||
await test.step('Edit sketch by dragging handle', async () => {
|
||||
await page.waitForTimeout(500)
|
||||
await editor.expectEditor.toContain('length = 156.54, angle = -28')
|
||||
await page.mouse.move(handle1Location.x, handle1Location.y)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(handle1Location.x + 50, handle1Location.y + 50, {
|
||||
steps: 5,
|
||||
})
|
||||
await page.mouse.up()
|
||||
await editor.expectEditor.toContain('length = 231.59, angle = -34')
|
||||
// await page.waitForTimeout(1000) // Wait for update
|
||||
})
|
||||
|
||||
await test.step('Delete variables and wait for re-execution', async () => {
|
||||
await page.waitForTimeout(500)
|
||||
await editor.replaceCode('myVar3 = 7', '')
|
||||
await page.waitForTimeout(50)
|
||||
await editor.replaceCode('myVar2 = 6', '')
|
||||
await page.waitForTimeout(2000) // Wait for deferred execution
|
||||
await expectSketchOriginToBeDrawn()
|
||||
})
|
||||
|
||||
const handle2Location = { x: 872, y: 273 }
|
||||
await test.step('Edit sketch again', async () => {
|
||||
await editor.expectEditor.toContain('length = 231.59, angle = -34')
|
||||
await page.waitForTimeout(500)
|
||||
await page.mouse.move(handle2Location.x, handle2Location.y)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(handle2Location.x, handle2Location.y - 50, {
|
||||
steps: 5,
|
||||
})
|
||||
await page.mouse.up()
|
||||
await editor.expectEditor.toContain('length = 167.36, angle = -14')
|
||||
})
|
||||
|
||||
await test.step('add whole other sketch before current sketch', async () => {
|
||||
await page.waitForTimeout(500)
|
||||
await editor.replaceCode(
|
||||
`myVar1 = 5`,
|
||||
`myVar1 = 5
|
||||
sketch003 = startSketchOn(XY)
|
||||
profile004 = circle(sketch003, center = [143.91, 136.89], radius = 71.63)`
|
||||
)
|
||||
await page.waitForTimeout(2000) // Wait for deferred execution
|
||||
await expectSketchOriginToBeDrawn()
|
||||
})
|
||||
|
||||
const handle3Location = { x: 844, y: 212 }
|
||||
await test.step('edit sketch again', async () => {
|
||||
await editor.expectEditor.toContain('length = 167.36, angle = -14')
|
||||
await page.mouse.move(handle3Location.x, handle3Location.y)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(handle3Location.x, handle3Location.y + 110, {
|
||||
steps: 5,
|
||||
})
|
||||
await page.mouse.up()
|
||||
await editor.expectEditor.toContain('length = 219.2, angle = -56')
|
||||
})
|
||||
|
||||
// exit sketch and assert whole code
|
||||
await test.step('Exit sketch and assert code', async () => {
|
||||
await toolbar.exitSketch()
|
||||
await editor.expectEditor.toContain(
|
||||
`myVar1 = 5
|
||||
sketch003 = startSketchOn(XY)
|
||||
profile004 = circle(sketch003, center = [143.91, 136.89], radius = 71.63)
|
||||
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([106.68, 89.77], sketch001)
|
||||
|> line(end = [132.34, 157.8])
|
||||
|> line(end = [67.65, -460.55], tag = $seg01)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude001 = extrude(profile001, length = 500)
|
||||
sketch002 = startSketchOn(extrude001, face = seg01)
|
||||
profile002 = startProfileAt([83.39, 329.15], sketch002)
|
||||
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|
||||
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 219.2, angle = -56)
|
||||
|> angledLine(
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
angle = -151,
|
||||
length = 116.27,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
profile003 = startProfileAt([-201.08, 254.17], sketch002)
|
||||
|> line(end = [103.55, 33.32])
|
||||
|> line(end = [48.8, -153.54])
|
||||
`,
|
||||
{ shouldNormalise: true }
|
||||
)
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: [],
|
||||
highlightedCode: '',
|
||||
})
|
||||
})
|
||||
})
|
||||
test('Will exit out of sketch mode for some incompatible edits', async ({
|
||||
page,
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `myVar1 = 5
|
||||
myVar2 = 6
|
||||
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([106.68, 89.77], sketch001)
|
||||
|> line(end = [132.34, 157.8])
|
||||
|> line(end = [67.65, -460.55], tag = $seg01)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude001 = extrude(profile001, length = 500)
|
||||
sketch002 = startSketchOn(extrude001, face = seg01)
|
||||
profile002 = startProfileAt([83.39, 329.15], sketch002)
|
||||
|> angledLine(angle = 0, length = 119.61, tag = $rectangleSegmentA001)
|
||||
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 156.54, angle = -28)
|
||||
|> angledLine(
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
angle = -151,
|
||||
length = 116.27,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
profile003 = startProfileAt([-201.08, 254.17], sketch002)
|
||||
|> line(end = [103.55, 33.32])
|
||||
|> line(end = [48.8, -153.54])`
|
||||
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
const expectSketchOriginToBeDrawn = async () => {
|
||||
await scene.expectPixelColor(TEST_COLORS.WHITE, { x: 672, y: 193 }, 15)
|
||||
}
|
||||
|
||||
await test.step('Open feature tree and edit second sketch', async () => {
|
||||
await toolbar.openFeatureTreePane()
|
||||
const sketchButton = await toolbar.getFeatureTreeOperation('Sketch', 1)
|
||||
await sketchButton.dblclick()
|
||||
await page.waitForTimeout(700) // Wait for engine animation
|
||||
await expectSketchOriginToBeDrawn()
|
||||
})
|
||||
|
||||
await test.step('rename variable of current sketch, sketch002 to changeSketchNamePartWayThrough', async () => {
|
||||
await editor.replaceCode('sketch002', 'changeSketchNamePartWayThrough')
|
||||
await page.waitForTimeout(100)
|
||||
// three times to rename the declaration and it's use
|
||||
await editor.replaceCode('sketch002', 'changeSketchNamePartWayThrough')
|
||||
await page.waitForTimeout(100)
|
||||
await editor.replaceCode('sketch002', 'changeSketchNamePartWayThrough')
|
||||
await expect(
|
||||
page.getByText('Unable to maintain sketch mode')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
||||
test(
|
||||
'adding a syntax error, recovers after fixing',
|
||||
{ tag: ['@skipWin'] },
|
||||
async ({ page, homePage, context, scene, editor, toolbar, cmdBar }) => {
|
||||
const file = await fs.readFile(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'../../',
|
||||
'./rust/kcl-lib/e2e/executor/inputs/e2e-can-sketch-on-chamfer.kcl'
|
||||
),
|
||||
'utf-8'
|
||||
)
|
||||
await context.addInitScript((file) => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
const [objClick] = scene.makeMouseHelpers(600, 250)
|
||||
const arrowHeadLocation = { x: 706, y: 129 } as const
|
||||
const arrowHeadWhite = TEST_COLORS.WHITE
|
||||
const backgroundGray: [number, number, number] = [28, 28, 28]
|
||||
const verifyArrowHeadColor = async (c: [number, number, number]) =>
|
||||
scene.expectPixelColor(c, arrowHeadLocation, 15)
|
||||
|
||||
// wait for scene to load
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step('check chamfer selection changes cursor positon', async () => {
|
||||
await expect(async () => {
|
||||
// sometimes initial click doesn't register
|
||||
await objClick()
|
||||
await editor.expectActiveLinesToBe([
|
||||
'|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]',
|
||||
])
|
||||
}).toPass({ timeout: 15_000, intervals: [500] })
|
||||
})
|
||||
|
||||
await test.step('enter sketch and sanity check segments have been drawn', async () => {
|
||||
await toolbar.editSketch()
|
||||
// this checks sketch segments have been drawn
|
||||
await verifyArrowHeadColor(arrowHeadWhite)
|
||||
})
|
||||
|
||||
await test.step('Make typo and check the segments have Disappeared and there is a syntax error', async () => {
|
||||
await editor.replaceCode(
|
||||
'line(endAbsolute = [pro',
|
||||
'badBadBadFn(endAbsolute = [pro'
|
||||
)
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: ['memoryitemkey`badBadBadFn`isnotdefined'],
|
||||
highlightedCode: '',
|
||||
})
|
||||
await expect(
|
||||
page.getByText(
|
||||
"Error in kcl script, sketch cannot be drawn until it's fixed"
|
||||
)
|
||||
).toBeVisible()
|
||||
// this checks sketch segments have failed to be drawn
|
||||
await verifyArrowHeadColor(backgroundGray)
|
||||
})
|
||||
|
||||
await test.step('', async () => {
|
||||
await editor.replaceCode(
|
||||
'badBadBadFn(endAbsolute = [pro',
|
||||
'line(endAbsolute = [pro'
|
||||
)
|
||||
await editor.expectState({
|
||||
activeLines: [],
|
||||
diagnostics: [],
|
||||
highlightedCode: '',
|
||||
})
|
||||
// this checks sketch segments have been drawn
|
||||
await verifyArrowHeadColor(arrowHeadWhite)
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { spawn } from 'child_process'
|
||||
import path from 'path'
|
||||
import type { Models } from '@kittycad/lib'
|
||||
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
|
||||
import { spawn } from 'child_process'
|
||||
import fsp from 'fs/promises'
|
||||
import JSZip from 'jszip'
|
||||
import path from 'path'
|
||||
|
||||
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
@ -13,6 +13,8 @@ import type { Paths } from '@e2e/playwright/test-utils'
|
||||
import {
|
||||
doExport,
|
||||
getUtils,
|
||||
headerMasks,
|
||||
networkingMasks,
|
||||
orRunWhenFullSuiteEnabled,
|
||||
settingsToToml,
|
||||
} from '@e2e/playwright/test-utils'
|
||||
@ -77,11 +79,7 @@ part001 = startSketchOn(-XZ)
|
||||
)
|
||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||
|> yLine(length = -armThick, tag = $seg01)
|
||||
|> angledLineThatIntersects({
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg04
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg04)
|
||||
|> angledLine(angle = segAng(seg04, %) + 180, endAbsoluteY = turns::ZERO)
|
||||
|> angledLine(
|
||||
angle = -bottomAng,
|
||||
@ -90,11 +88,7 @@ part001 = startSketchOn(-XZ)
|
||||
)
|
||||
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|
||||
|> yLine(length = -segLen(seg01, %))
|
||||
|> angledLineThatIntersects({
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg02
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg02)
|
||||
|> angledLine(angle = segAng(seg02, %) + 180, endAbsoluteY = -baseHeight)
|
||||
|> xLine(endAbsolute = turns::ZERO)
|
||||
|> close()
|
||||
@ -374,7 +368,7 @@ const extrudeDefaultPlane = async (
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
await u.openKclCodePanel()
|
||||
}
|
||||
@ -462,7 +456,7 @@ test(
|
||||
await page.waitForTimeout(500)
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
|
||||
const lineEndClick = () =>
|
||||
@ -491,7 +485,7 @@ test(
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
await endOfTangentClk()
|
||||
|
||||
@ -501,7 +495,7 @@ test(
|
||||
await threePointArcMidPointMv()
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
await threePointArcMidPointClk()
|
||||
await page.waitForTimeout(100)
|
||||
@ -510,7 +504,7 @@ test(
|
||||
await page.waitForTimeout(500)
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
|
||||
await threePointArcEndPointClk()
|
||||
@ -530,7 +524,7 @@ test(
|
||||
await page.waitForTimeout(500)
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
await arcEndClk()
|
||||
}
|
||||
@ -580,7 +574,7 @@ test(
|
||||
// Ensure the draft rectangle looks the same as it usually does
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -623,7 +617,7 @@ test(
|
||||
// Ensure the draft rectangle looks the same as it usually does
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`sketch001 = startSketchOn(XZ)profile001 = circle(sketch001, center = [366.89, -62.01], radius = 1)`
|
||||
@ -696,7 +690,7 @@ test.describe(
|
||||
// screen shot should show the sketch
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
|
||||
await u.doAndWaitForImageDiff(
|
||||
@ -709,7 +703,7 @@ test.describe(
|
||||
// second screen shot should look almost identical, i.e. scale should be the same.
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
})
|
||||
|
||||
@ -789,6 +783,7 @@ test.describe(
|
||||
// screen shot should show the sketch
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
|
||||
// exit sketch
|
||||
@ -802,6 +797,7 @@ test.describe(
|
||||
// second screen shot should look almost identical, i.e. scale should be the same.
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -863,7 +859,7 @@ part002 = startSketchOn(part001, face = seg01)
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -902,7 +898,7 @@ test(
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -942,7 +938,7 @@ test(
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -955,11 +951,6 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
const stream = page.getByTestId('stream')
|
||||
const mask = [
|
||||
page.locator('#app-header'),
|
||||
page.locator('#sidebar-top-ribbon'),
|
||||
page.locator('#sidebar-bottom-ribbon'),
|
||||
]
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.goto('/')
|
||||
@ -1012,18 +1003,13 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
|
||||
await expect(stream).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask,
|
||||
mask: [...headerMasks(page), ...networkingMasks(page)],
|
||||
})
|
||||
})
|
||||
|
||||
test('Grid turned off', async ({ page, cmdBar, scene }) => {
|
||||
const u = await getUtils(page)
|
||||
const stream = page.getByTestId('stream')
|
||||
const mask = [
|
||||
page.locator('#app-header'),
|
||||
page.locator('#sidebar-top-ribbon'),
|
||||
page.locator('#sidebar-bottom-ribbon'),
|
||||
]
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.goto('/')
|
||||
@ -1038,7 +1024,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
|
||||
await expect(stream).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask,
|
||||
mask: [...headerMasks(page), ...networkingMasks(page)],
|
||||
})
|
||||
})
|
||||
|
||||
@ -1063,11 +1049,6 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
|
||||
const u = await getUtils(page)
|
||||
const stream = page.getByTestId('stream')
|
||||
const mask = [
|
||||
page.locator('#app-header'),
|
||||
page.locator('#sidebar-top-ribbon'),
|
||||
page.locator('#sidebar-bottom-ribbon'),
|
||||
]
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.goto('/')
|
||||
@ -1082,7 +1063,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
|
||||
await expect(stream).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask,
|
||||
mask: [...headerMasks(page), ...networkingMasks(page)],
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1151,6 +1132,7 @@ test('theme persists', async ({ page, context }) => {
|
||||
|
||||
await expect(page, 'expect screenshot to have light theme').toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
})
|
||||
|
||||
@ -1166,9 +1148,9 @@ test.describe('code color goober', { tag: '@snapshot' }, () => {
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
sweepSketch = startSketchOn(XY)
|
||||
@ -1195,7 +1177,7 @@ sweepSketch = startSketchOn(XY)
|
||||
|
||||
await expect(page, 'expect small color widget').toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
})
|
||||
|
||||
@ -1215,9 +1197,9 @@ sweepSketch = startSketchOn(XY)
|
||||
sweepPath = startSketchOn(XZ)
|
||||
|> startProfileAt([0.05, 0.05], %)
|
||||
|> line(end = [0, 7])
|
||||
|> tangentialArc({ offset = 90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = 90, radius = 5)
|
||||
|> line(end = [-3, 0])
|
||||
|> tangentialArc({ offset = -90, radius = 5 }, %)
|
||||
|> tangentialArc(angle = -90, radius = 5)
|
||||
|> line(end = [0, 7])
|
||||
|
||||
sweepSketch = startSketchOn(XY)
|
||||
@ -1252,7 +1234,7 @@ sweepSketch = startSketchOn(XY)
|
||||
'expect small color widget to have window open'
|
||||
).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 63 KiB |
@ -1,33 +0,0 @@
|
||||
{
|
||||
"original_source_code": "sketch001 = startSketchOn(XZ)\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn(XY)\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001)\n |> angledLine(angle = segAng(rectangleSegmentA001) - 90,\n length = 53.4\n ], tag = $rectangleSegmentB001)\n |> angledLine(angle = segAng(rectangleSegmentA001),\n length = -segLen(rectangleSegmentA001)\n tag = $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
|
||||
"prompt": "make this neon green please, use #39FF14",
|
||||
"source_ranges": [
|
||||
{
|
||||
"prompt": "The users main selection is the end cap of a general-sweep (that is an extrusion, revolve, sweep or loft).\nThe source range most likely refers to \"startProfileAt\" simply because this is the start of the profile that was swept.\nIf you need to operate on this cap, for example for sketching on the face, you can use the special string END i.e. `startSketchOn(someSweepVariable, END)`\nWhen they made this selection they main have intended this surface directly or meant something more general like the sweep body.\nSee later source ranges for more context.",
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 11,
|
||||
"column": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 11,
|
||||
"column": 40
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"prompt": "This is the sweep's source range from the user's main selection of the end cap.",
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 17,
|
||||
"column": 13
|
||||
},
|
||||
"end": {
|
||||
"line": 17,
|
||||
"column": 44
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"kcl_version": "0.2.48"
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
"original_source_code": "sketch001 = startSketchOn(XZ)\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn(XZ)\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn(XY)\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine(angle = 0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, length = $rectangleSegmentB001)\n |> angledLine(\n angle = segAng(rectangleSegmentA001),\n length = -segLen(rectangleSegmentA001),\n tag = $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
|
||||
"original_source_code": "sketch001 = startSketchOn(XZ)\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn(XZ)\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn(XY)\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001)\n |> angledLine(\n angle = segAng(rectangleSegmentA001) - 90,\n length = 53.4,\n tag = $rectangleSegmentB001,\n )\n |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
|
||||
"prompt": "make this neon green please, use #39FF14",
|
||||
"source_ranges": [
|
||||
{
|
||||
"prompt": "The users main selection is the end cap of a general-sweep (that is an extrusion, revolve, sweep or loft).\nThe source range most likely refers to \"startProfileAt\" simply because this is the start of the profile that was swept.\nIf you need to operate on this cap, for example for sketching on the face, you can use the special string END i.e. `startSketchOn(someSweepVariable, END)`\nWhen they made this selection they main have intended this surface directly or meant something more general like the sweep body.\nSee later source ranges for more context.",
|
||||
"prompt": "The users main selection is the end cap of a general-sweep (that is an extrusion, revolve, sweep or loft).\nThe source range most likely refers to \"startProfileAt\" simply because this is the start of the profile that was swept.\nIf you need to operate on this cap, for example for sketching on the face, you can use the special string END i.e. `startSketchOn(someSweepVariable, face = END)`\nWhen they made this selection they main have intended this surface directly or meant something more general like the sweep body.\nSee later source ranges for more context.",
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 11,
|
||||
@ -29,5 +29,5 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"kcl_version": "0.2.57"
|
||||
}
|
||||
"kcl_version": "0.2.61"
|
||||
}
|
||||
@ -93,11 +93,7 @@ part001 = startSketchOn(XZ)
|
||||
|> angledLine(angle = 30, lengthY = 3 + 0 )
|
||||
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|
||||
|> angledLine(angle = 30, endAbsoluteY = 11.14)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 3.14,
|
||||
intersectTag: a,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
|
||||
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|
||||
|> close()
|
||||
|> extrude(length = 5 + 7)
|
||||
|
||||
@ -126,8 +126,9 @@ test.describe('Test network and connection issues', () => {
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})`)
|
||||
|
||||
// Expect the network to be up
|
||||
@ -215,7 +216,8 @@ test.describe('Test network and connection issues', () => {
|
||||
await page.waitForTimeout(100)
|
||||
// Ensure we can continue sketching
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||
await expect.poll(u.normalisedEditorCode)
|
||||
await expect
|
||||
.poll(u.normalisedEditorCode)
|
||||
.toBe(`sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([12.34, -12.34], sketch001)
|
||||
|> xLine(length = 12.34)
|
||||
@ -225,7 +227,8 @@ profile001 = startProfileAt([12.34, -12.34], sketch001)
|
||||
await page.waitForTimeout(100)
|
||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||
|
||||
await expect.poll(u.normalisedEditorCode)
|
||||
await expect
|
||||
.poll(u.normalisedEditorCode)
|
||||
.toBe(`sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfileAt([12.34, -12.34], sketch001)
|
||||
|> xLine(length = 12.34)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import path from 'path'
|
||||
import * as TOML from '@iarna/toml'
|
||||
import type { Models } from '@kittycad/lib'
|
||||
import type { BrowserContext, Locator, Page, TestInfo } from '@playwright/test'
|
||||
@ -9,7 +10,6 @@ import { reportRejection } from '@src/lib/trap'
|
||||
import type { DeepPartial } from '@src/lib/types'
|
||||
import { isArray } from '@src/lib/utils'
|
||||
import fsp from 'fs/promises'
|
||||
import path from 'path'
|
||||
import pixelMatch from 'pixelmatch'
|
||||
import type { Protocol } from 'playwright-core/types/protocol'
|
||||
import { PNG } from 'pngjs'
|
||||
@ -29,6 +29,17 @@ const toNormalizedCode = (text: string) => {
|
||||
return text.replace(/\s+/g, '')
|
||||
}
|
||||
|
||||
export const headerMasks = (page: Page) => [
|
||||
page.locator('#app-header'),
|
||||
page.locator('#sidebar-top-ribbon'),
|
||||
page.locator('#sidebar-bottom-ribbon'),
|
||||
]
|
||||
|
||||
export const networkingMasks = (page: Page) => [
|
||||
page.getByTestId('model-state-indicator'),
|
||||
page.getByTestId('network-toggle'),
|
||||
]
|
||||
|
||||
export type TestColor = [number, number, number]
|
||||
export const TEST_COLORS: { [key: string]: TestColor } = {
|
||||
WHITE: [249, 249, 249],
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import path from 'node:path'
|
||||
import { XOR } from '@src/lib/utils'
|
||||
import * as fsp from 'fs/promises'
|
||||
import path from 'node:path'
|
||||
|
||||
import {
|
||||
TEST_COLORS,
|
||||
@ -219,7 +219,9 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await expect(activeLinesContent[0]).toHaveText(
|
||||
`|> line(end = [74.36, 130.4], tag = $seg01)`
|
||||
)
|
||||
await expect(activeLinesContent[1]).toHaveText(`}, %)`)
|
||||
await expect(activeLinesContent[1]).toHaveText(
|
||||
` |> angledLineThatIntersects(angle = -57, offset = ${offset}, intersectTag = seg01)`
|
||||
)
|
||||
|
||||
// checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
|
||||
await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
import { join } from 'path'
|
||||
import { bracket } from '@e2e/playwright/fixtures/bracket'
|
||||
import { FILE_EXT } from '@src/lib/constants'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import type { CmdBarSerialised } from '@e2e/playwright/fixtures/cmdBarFixture'
|
||||
import type { ElectronZoo } from '@e2e/playwright/fixtures/fixtureSetup'
|
||||
import {
|
||||
executorInputPath,
|
||||
getUtils,
|
||||
orRunWhenFullSuiteEnabled,
|
||||
runningOnWindows,
|
||||
testsInputPath,
|
||||
} from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Testing in-app sample loading', () => {
|
||||
test.describe('Testing loading external models', () => {
|
||||
/**
|
||||
* Note this test implicitly depends on the KCL sample "parametric-bearing-pillow-block",
|
||||
* its title, and its units settings. https://github.com/KittyCAD/kcl-samples/blob/main/parametric-bearing-pillow-block/main.kcl
|
||||
@ -39,7 +43,7 @@ test.describe('Testing in-app sample loading', () => {
|
||||
}
|
||||
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
||||
const samplesCommandOption = page.getByRole('option', {
|
||||
name: 'Open Sample',
|
||||
name: 'Load external model',
|
||||
})
|
||||
const commandSampleOption = page.getByRole('option', {
|
||||
name: newSample.title,
|
||||
@ -83,7 +87,7 @@ test.describe('Testing in-app sample loading', () => {
|
||||
test(
|
||||
'Desktop: should create new file by default, optionally overwrite',
|
||||
{ tag: '@electron' },
|
||||
async ({ editor, context, page, scene, cmdBar }, testInfo) => {
|
||||
async ({ editor, context, page, scene, cmdBar, toolbar }) => {
|
||||
if (runningOnWindows()) {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
}
|
||||
@ -106,20 +110,12 @@ test.describe('Testing in-app sample loading', () => {
|
||||
title: '100mm Gear Rack',
|
||||
}
|
||||
const projectCard = page.getByRole('link', { name: 'bracket' })
|
||||
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
||||
const commandOption = page.getByRole('option', { name: 'Open Sample' })
|
||||
const commandSampleOption = (name: string) =>
|
||||
page.getByRole('option', {
|
||||
name,
|
||||
exact: true,
|
||||
})
|
||||
const commandMethodArgButton = page.getByRole('button', {
|
||||
name: 'Method',
|
||||
})
|
||||
const commandMethodOption = page.getByRole('option', {
|
||||
name: 'Overwrite',
|
||||
})
|
||||
const newFileWarning = page.getByText('Create a new file from sample?')
|
||||
const overwriteWarning = page.getByText(
|
||||
'Overwrite current file with sample?'
|
||||
)
|
||||
@ -129,6 +125,18 @@ test.describe('Testing in-app sample loading', () => {
|
||||
page.getByRole('listitem').filter({
|
||||
has: page.getByRole('button', { name }),
|
||||
})
|
||||
const defaultLoadCmdBarState: CmdBarSerialised = {
|
||||
commandName: 'Load external model',
|
||||
currentArgKey: 'source',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: 'newFile',
|
||||
Sample: '',
|
||||
Source: '',
|
||||
},
|
||||
highlightedHeaderArg: 'source',
|
||||
stage: 'arguments',
|
||||
}
|
||||
|
||||
await test.step(`Test setup`, async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
@ -147,14 +155,12 @@ test.describe('Testing in-app sample loading', () => {
|
||||
})
|
||||
|
||||
await test.step(`Load a KCL sample with the command palette`, async () => {
|
||||
await commandBarButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandSampleOption(sampleOne.title).click()
|
||||
await toolbar.loadButton.click()
|
||||
await cmdBar.expectState(defaultLoadCmdBarState)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.selectOption({ name: sampleOne.title }).click()
|
||||
await expect(overwriteWarning).not.toBeVisible()
|
||||
await expect(newFileWarning).toBeVisible()
|
||||
await confirmButton.click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
@ -165,21 +171,15 @@ test.describe('Testing in-app sample loading', () => {
|
||||
})
|
||||
|
||||
await test.step(`Now overwrite the current file`, async () => {
|
||||
await commandBarButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandSampleOption(sampleTwo.title).click()
|
||||
await page.waitForTimeout(1000)
|
||||
await toolbar.loadButton.click()
|
||||
await cmdBar.expectState(defaultLoadCmdBarState)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.selectOption({ name: sampleTwo.title }).click()
|
||||
await commandMethodArgButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandMethodOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(commandMethodArgButton).toContainText('overwrite')
|
||||
await expect(newFileWarning).not.toBeVisible()
|
||||
await expect(overwriteWarning).toBeVisible()
|
||||
await confirmButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step(`Ensure we overwrote the current file without navigating`, async () => {
|
||||
@ -200,4 +200,96 @@ test.describe('Testing in-app sample loading', () => {
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const externalModelCases = [
|
||||
{
|
||||
modelName: 'cylinder.kcl',
|
||||
deconflictedModelName: 'cylinder-1.kcl',
|
||||
modelPath: executorInputPath('cylinder.kcl'),
|
||||
},
|
||||
{
|
||||
modelName: 'cube.step',
|
||||
deconflictedModelName: 'cube-1.step',
|
||||
modelPath: testsInputPath('cube.step'),
|
||||
},
|
||||
]
|
||||
externalModelCases.map(({ modelName, deconflictedModelName, modelPath }) => {
|
||||
test(
|
||||
`Load external models from local drive - ${modelName}`,
|
||||
{ tag: ['@electron'] },
|
||||
async ({ page, homePage, scene, toolbar, cmdBar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
const modelFileContent = await fsp.readFile(modelPath, 'utf-8')
|
||||
const { editorTextMatches } = await getUtils(page, test)
|
||||
|
||||
async function loadExternalFileThroughCommandBar(tronApp: ElectronZoo) {
|
||||
await toolbar.loadButton.click()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Load external model',
|
||||
currentArgKey: 'source',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: 'newFile',
|
||||
Sample: '',
|
||||
Source: '',
|
||||
},
|
||||
highlightedHeaderArg: 'source',
|
||||
stage: 'arguments',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'Local Drive' }).click()
|
||||
|
||||
// Mock the file picker selection
|
||||
const handleFile = tronApp.electron.evaluate(
|
||||
async ({ dialog }, filePaths) => {
|
||||
dialog.showOpenDialog = () =>
|
||||
Promise.resolve({ canceled: false, filePaths })
|
||||
},
|
||||
[modelPath]
|
||||
)
|
||||
await page.getByTestId('cmd-bar-arg-file-button').click()
|
||||
await handleFile
|
||||
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Load external model',
|
||||
headerArguments: {
|
||||
Source: 'local',
|
||||
Path: modelName,
|
||||
},
|
||||
stage: 'review',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
}
|
||||
|
||||
await test.step('Load the external model from local drive', async () => {
|
||||
await loadExternalFileThroughCommandBar(tronApp)
|
||||
// TODO: I think the files pane should auto open?
|
||||
await toolbar.openPane('files')
|
||||
await toolbar.expectFileTreeState([modelName, 'main.kcl'])
|
||||
if (modelName.endsWith('.kcl')) {
|
||||
await editorTextMatches(modelFileContent)
|
||||
}
|
||||
})
|
||||
|
||||
await test.step('Load the same external model, except deconflicted name', async () => {
|
||||
await loadExternalFileThroughCommandBar(tronApp)
|
||||
await toolbar.openPane('files')
|
||||
await toolbar.expectFileTreeState([
|
||||
deconflictedModelName,
|
||||
modelName,
|
||||
'main.kcl',
|
||||
])
|
||||
if (modelName.endsWith('.kcl')) {
|
||||
await editorTextMatches(modelFileContent)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -224,11 +224,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
|> angledLine(angle = -91, lengthY = 19 + 0)
|
||||
|> angledLine(angle = 3 + 0, endAbsoluteX = 5 + 26)
|
||||
|> angledLine(angle = 89, endAbsoluteY = 20 + 9.14 + 0)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|
||||
|> tangentialArc(endAbsolute = [5 + 3.14 + 13, 20 + 3.14])
|
||||
`
|
||||
)
|
||||
@ -472,11 +468,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
|> angledLine(angle = -91, lengthY = 19 + 0)
|
||||
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|
||||
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 3.14])
|
||||
`
|
||||
)
|
||||
@ -597,11 +589,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
|> angledLine(angle = -91, lengthY = 19 + 0)
|
||||
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|
||||
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|
||||
`
|
||||
)
|
||||
@ -691,21 +679,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
y: angledLineThatIntersects.y,
|
||||
},
|
||||
constraintType: 'angle',
|
||||
expectBeforeUnconstrained: `angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)`,
|
||||
expectAfterUnconstrained: `angledLineThatIntersects({
|
||||
angle = angle003,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)`,
|
||||
expectFinal: `angledLineThatIntersects({
|
||||
angle = -176,
|
||||
offset = 9,
|
||||
intersectTag = a
|
||||
}, %)`,
|
||||
expectBeforeUnconstrained: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
|
||||
expectAfterUnconstrained: `angledLineThatIntersects(angle = angle003, intersectTag = a,offset = 9)`,
|
||||
expectFinal: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
|
||||
ang: ang + 180,
|
||||
locator: '[data-overlay-toolbar-index="11"]',
|
||||
})
|
||||
@ -716,21 +692,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
y: angledLineThatIntersects.y,
|
||||
},
|
||||
constraintType: 'intersectionOffset',
|
||||
expectBeforeUnconstrained: `angledLineThatIntersects({
|
||||
angle = -176,
|
||||
offset = 9,
|
||||
intersectTag = a
|
||||
}, %)`,
|
||||
expectAfterUnconstrained: `angledLineThatIntersects({
|
||||
angle = -176,
|
||||
offset = perpDist001,
|
||||
intersectTag = a
|
||||
}, %)`,
|
||||
expectFinal: `angledLineThatIntersects({
|
||||
angle = -176,
|
||||
offset = 9,
|
||||
intersectTag = a
|
||||
}, %)`,
|
||||
expectBeforeUnconstrained: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
|
||||
expectAfterUnconstrained: `angledLineThatIntersects(angle = -176, offset = perpDist001, intersectTag = a)`,
|
||||
expectFinal: `angledLineThatIntersects(angle = -176, offset = 9, intersectTag = a)`,
|
||||
ang: ang + 180,
|
||||
locator: '[data-overlay-toolbar-index="11"]',
|
||||
})
|
||||
@ -753,11 +717,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
|
||||
|> angledLine(angle = -91, lengthY = 19 + 0)
|
||||
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|
||||
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, -3.14])
|
||||
`
|
||||
)
|
||||
@ -1083,11 +1043,7 @@ part001 = startSketchOn(XZ)
|
||||
|> angledLine(angle = -91, lengthY = 19 + 0)
|
||||
|> angledLine(angle = 3 + 0, endAbsoluteX = 26)
|
||||
|> angledLine(angle = 89, endAbsoluteY = 9.14 + 0)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)
|
||||
|> tangentialArc(endAbsolute = [3.14 + 13, 1.14])
|
||||
|> arcTo({
|
||||
interior = [16.25, 5.12],
|
||||
@ -1169,11 +1125,7 @@ part001 = startSketchOn(XZ)
|
||||
ang = await u.getAngle('[data-overlay-index="11"]')
|
||||
await deleteSegmentSequence({
|
||||
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
|
||||
codeToBeDeleted: `angledLineThatIntersects({
|
||||
angle = 4.14,
|
||||
intersectTag = a,
|
||||
offset = 9
|
||||
}, %)`,
|
||||
codeToBeDeleted: `angledLineThatIntersects(angle = 4.14, intersectTag = a, offset = 9)`,
|
||||
stdLibFnName: 'angledLineThatIntersects',
|
||||
ang: ang + 180,
|
||||
steps: 7,
|
||||
|
||||
@ -78,22 +78,25 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
|
||||
await page.waitForTimeout(100)
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})`)
|
||||
|
||||
await page.waitForTimeout(100)
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})
|
||||
|> yLine(length = ${commonPoints.num1 + 0.01})`)
|
||||
await page.waitForTimeout(100)
|
||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
await expect(
|
||||
page.locator('.cm-content')
|
||||
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(length = ${commonPoints.num1})
|
||||
@ -524,11 +527,7 @@ part001 = startSketchOn(XZ)
|
||||
|> angledLine(angle = 30, lengthY = 3 + 0)
|
||||
|> angledLine(angle = 22.14 + 0, endAbsoluteX = 12)
|
||||
|> angledLine(angle = 30, endAbsoluteY = 11.14)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 3.14,
|
||||
intersectTag = a,
|
||||
offset = 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)
|
||||
|> tangentialArc(endAbsolute = [13.14 + 0, 13.14])
|
||||
|> close()
|
||||
|> extrude(length = 5 + 7)
|
||||
@ -660,8 +659,8 @@ part001 = startSketchOn(XZ)
|
||||
await checkCodeAtHoverPosition(
|
||||
'flatExtrusionFace',
|
||||
flatExtrusionFace,
|
||||
`angledLineThatIntersects({angle=3.14,intersectTag=a,offset=0},%)extrude(length=5+7)`,
|
||||
'}, %)'
|
||||
`angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)extrude(length=5+7)`,
|
||||
'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
|
||||
)
|
||||
|
||||
await checkCodeAtHoverPosition(
|
||||
@ -724,8 +723,8 @@ part001 = startSketchOn(XZ)
|
||||
await checkCodeAtHoverPosition(
|
||||
'straightSegmentAdjacentEdge',
|
||||
straightSegmentAdjacentEdge,
|
||||
`angledLineThatIntersects({angle=3.14,intersectTag=a,offset=0},%)`,
|
||||
'}, %)'
|
||||
`angledLineThatIntersects(angle=3.14,intersectTag=a,offset=0)`,
|
||||
'angledLineThatIntersects(angle = 3.14, intersectTag = a, offset = 0)'
|
||||
)
|
||||
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { join } from 'path'
|
||||
import {
|
||||
PROJECT_SETTINGS_FILE_NAME,
|
||||
SETTINGS_FILE_NAME,
|
||||
@ -5,7 +6,6 @@ import {
|
||||
import type { SettingsLevel } from '@src/lib/settings/settingsTypes'
|
||||
import type { DeepPartial } from '@src/lib/types'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
|
||||
import type { Settings } from '@rust/kcl-lib/bindings/Settings'
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
createProject,
|
||||
executorInputPath,
|
||||
getUtils,
|
||||
networkingMasks,
|
||||
orRunWhenFullSuiteEnabled,
|
||||
tomlToSettings,
|
||||
} from '@e2e/playwright/test-utils'
|
||||
@ -1036,7 +1037,7 @@ fn cube`
|
||||
'toggle-settings-initial.png',
|
||||
{
|
||||
maxDiffPixels: 15,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
}
|
||||
)
|
||||
|
||||
@ -1053,7 +1054,7 @@ fn cube`
|
||||
'toggle-settings-initial.png',
|
||||
{
|
||||
maxDiffPixels: 15,
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
mask: networkingMasks(page),
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
import fs from 'fs'
|
||||
import { join } from 'path'
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import {
|
||||
createProject,
|
||||
|
||||
@ -66,11 +66,7 @@ part001 = startSketchOn(-XZ)
|
||||
)
|
||||
|> xLine(endAbsolute = totalLen, tag = $seg03)
|
||||
|> yLine(length = -armThick, tag = $seg01)
|
||||
|> angledLineThatIntersects({
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg04
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg04)
|
||||
|> angledLine(angle = segAng(seg04) + 180, endAbsoluteY = turns::ZERO)
|
||||
|> angledLine(
|
||||
angle = -bottomAng,
|
||||
@ -79,11 +75,7 @@ part001 = startSketchOn(-XZ)
|
||||
)
|
||||
|> xLine(endAbsolute = segEndX(seg03) + 0)
|
||||
|> yLine(length = -segLen(seg01))
|
||||
|> angledLineThatIntersects({
|
||||
angle = turns::HALF_TURN,
|
||||
offset = -armThick,
|
||||
intersectTag = seg02
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = turns::HALF_TURN, offset = -armThick, intersectTag = seg02)
|
||||
|> angledLine(angle = segAng(seg02) + 180, endAbsoluteY = -baseHeight)
|
||||
|> xLine(endAbsolute = turns::ZERO)
|
||||
|> close()
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import path from 'path'
|
||||
import { FusesPlugin } from '@electron-forge/plugin-fuses'
|
||||
import { VitePlugin } from '@electron-forge/plugin-vite'
|
||||
import type { ForgeConfig } from '@electron-forge/shared-types'
|
||||
import { FuseV1Options, FuseVersion } from '@electron/fuses'
|
||||
import path from 'path'
|
||||
|
||||
const rootDir = process.cwd()
|
||||
|
||||
|
||||
4
interface.d.ts
vendored
@ -1,10 +1,10 @@
|
||||
import { MachinesListing } from 'components/MachineManagerProvider'
|
||||
import 'electron'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'path'
|
||||
import { dialog, shell } from 'electron'
|
||||
import type { WebContentSendPayload } from 'menu/channels'
|
||||
import { ZooLabel } from 'menu/roles'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
// Extend the interface with additional custom properties
|
||||
declare module 'electron' {
|
||||
|
||||
243
package-lock.json
generated
@ -76,6 +76,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@electron-forge/cli": "^7.8.0",
|
||||
"@electron-forge/plugin-fuses": "^7.8.0",
|
||||
"@electron-forge/plugin-vite": "^7.8.0",
|
||||
@ -87,7 +88,6 @@
|
||||
"@playwright/test": "^1.51.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^15.0.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/diff": "^7.0.2",
|
||||
"@types/electron": "^1.6.10",
|
||||
"@types/isomorphic-fetch": "^0.0.39",
|
||||
@ -131,8 +131,6 @@
|
||||
"pngjs": "^7.0.0",
|
||||
"postcss": "^8.4.43",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"ts-node": "^10.0.0",
|
||||
@ -1926,6 +1924,170 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz",
|
||||
"integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"bin": {
|
||||
"biome": "bin/biome"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/biome"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@biomejs/cli-darwin-arm64": "1.9.4",
|
||||
"@biomejs/cli-darwin-x64": "1.9.4",
|
||||
"@biomejs/cli-linux-arm64": "1.9.4",
|
||||
"@biomejs/cli-linux-arm64-musl": "1.9.4",
|
||||
"@biomejs/cli-linux-x64": "1.9.4",
|
||||
"@biomejs/cli-linux-x64-musl": "1.9.4",
|
||||
"@biomejs/cli-win32-arm64": "1.9.4",
|
||||
"@biomejs/cli-win32-x64": "1.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz",
|
||||
"integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-x64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz",
|
||||
"integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz",
|
||||
"integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz",
|
||||
"integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz",
|
||||
"integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz",
|
||||
"integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-arm64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz",
|
||||
"integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-x64": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz",
|
||||
"integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/autocomplete": {
|
||||
"version": "6.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||
@ -5038,41 +5200,6 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@trivago/prettier-plugin-sort-imports": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz",
|
||||
"integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.26.5",
|
||||
"@babel/parser": "^7.26.7",
|
||||
"@babel/traverse": "^7.26.7",
|
||||
"@babel/types": "^7.26.7",
|
||||
"javascript-natural-sort": "^0.7.1",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/compiler-sfc": "3.x",
|
||||
"prettier": "2.x - 3.x",
|
||||
"prettier-plugin-svelte": "3.x",
|
||||
"svelte": "4.x || 5.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/compiler-sfc": {
|
||||
"optional": true
|
||||
},
|
||||
"prettier-plugin-svelte": {
|
||||
"optional": true
|
||||
},
|
||||
"svelte": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@ts-stack/markdown": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@ts-stack/markdown/-/markdown-1.5.0.tgz",
|
||||
@ -13349,13 +13476,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/javascript-natural-sort": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
||||
"integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jest-diff": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
|
||||
@ -16552,39 +16672,6 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-organize-imports": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz",
|
||||
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"prettier": ">=2.0",
|
||||
"typescript": ">=2.9",
|
||||
"vue-tsc": "^2.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"vue-tsc": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
|
||||
39
package.json
@ -96,9 +96,10 @@
|
||||
"simpleserver:stop": "kill-port 3000",
|
||||
"tsc": "tsc",
|
||||
"playwright": "playwright",
|
||||
"fmt": "prettier --write .eslintrc.json ./src *.ts *.json *.js ./e2e ./packages ./rust/kcl-language-server ./rust/kcl-lib/bindings ./rust/kcl-wasm-lib/pkg",
|
||||
"fmt:generated": "prettier --write .eslintrc.json *.ts *.json *.js ./rust/kcl-lib/bindings ./rust/kcl-wasm-lib/pkg",
|
||||
"fmt-check": "prettier --check .eslintrc.json ./src *.ts *.json *.js ./e2e ./packages ./rust/kcl-language-server",
|
||||
"fmt": "biome format --write .eslintrc.json ./src *.ts *.js ./e2e ./packages ./rust/kcl-language-server ./rust/kcl-lib/bindings ./rust/kcl-wasm-lib/pkg",
|
||||
"fmt:check": "biome check --write --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false --files-ignore-unknown=true ./src *.ts *.js ./e2e ./packages ./rust/kcl-language-server ./rust/kcl-lib/bindings ./rust/kcl-wasm-lib/pkg",
|
||||
"organize-imports": "biome check --write --organize-imports-enabled=true --formatter-enabled=false --linter-enabled=false ./src ./e2e ./packages --files-ignore-unknown=true",
|
||||
"check": "biome check ./src ./e2e ./packages/codemirror-lsp-client/src ./rust/kcl-language-server/client/src",
|
||||
"fetch:wasm": "./scripts/get-latest-wasm-bundle.sh",
|
||||
"fetch:wasm:windows": "powershell -ExecutionPolicy Bypass -File ./scripts/get-latest-wasm-bundle.ps1",
|
||||
"fetch:samples": "rm -rf public/kcl-samples* && curl -L -o public/kcl-samples.zip https://github.com/KittyCAD/kcl-samples/archive/refs/heads/achalmers/kw-args-xylineto.zip && unzip -o public/kcl-samples.zip -d public && mv public/kcl-samples-* public/kcl-samples",
|
||||
@ -131,7 +132,7 @@
|
||||
"tronb:package:prod": "npm run tronb:vite:prod && electron-builder --config electron-builder.yml --publish always",
|
||||
"test-setup": "npm install && npm run build:wasm",
|
||||
"test": "vitest --mode development",
|
||||
"test:snapshots": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --update-snapshots --grep=@snapshot --trace=on --shard=1/1",
|
||||
"test:snapshots": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --grep=@snapshot --trace=on --shard=1/1",
|
||||
"test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts",
|
||||
"test:unit:kcl-samples": "vitest run --mode development ./src/lang/kclSamples.test.ts",
|
||||
"test:playwright:electron": "playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'",
|
||||
@ -146,32 +147,8 @@
|
||||
"test:unit:local": "npm run simpleserver:bg && npm run test:unit; kill-port 3000",
|
||||
"test:unit:kcl-samples:local": "npm run simpleserver:bg && npm run test:unit:kcl-samples; kill-port 3000"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"importOrder": [
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^@rust/(.*)$",
|
||||
"^@public/(.*)$",
|
||||
"^@e2e/(.*)$",
|
||||
"^@src/(.*)$",
|
||||
"^[./]"
|
||||
],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true,
|
||||
"plugins": [
|
||||
"@trivago/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-organize-imports"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"production": [">0.2%", "not dead", "not op_mini all"],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
@ -181,6 +158,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@electron-forge/cli": "^7.8.0",
|
||||
"@electron-forge/plugin-fuses": "^7.8.0",
|
||||
"@electron-forge/plugin-vite": "^7.8.0",
|
||||
@ -192,7 +170,6 @@
|
||||
"@playwright/test": "^1.51.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^15.0.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/diff": "^7.0.2",
|
||||
"@types/electron": "^1.6.10",
|
||||
"@types/isomorphic-fetch": "^0.0.39",
|
||||
@ -236,8 +213,6 @@
|
||||
"pngjs": "^7.0.0",
|
||||
"postcss": "^8.4.43",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"ts-node": "^10.0.0",
|
||||
|
||||
@ -32,7 +32,5 @@
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.1.1"
|
||||
},
|
||||
"files": [
|
||||
"dist/"
|
||||
]
|
||||
"files": ["dist/"]
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { fileTests } from '@lezer/generator/dist/test'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { fileTests } from '@lezer/generator/dist/test'
|
||||
|
||||
import { KclLanguage } from '../src/index'
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
import os from 'os'
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
|
||||
const platform = os.platform() // 'linux' (Ubuntu), 'darwin' (macOS), 'win32' (Windows)
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
import os from 'os'
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
|
||||
const platform = os.platform() // 'linux' (Ubuntu), 'darwin' (macOS), 'win32' (Windows)
|
||||
|
||||
@ -20,7 +20,7 @@ if (process.env.E2E_WORKERS) {
|
||||
case 'darwin':
|
||||
case 'win32':
|
||||
default:
|
||||
workers = '25%' // Lower concurrency for heavier Electron processes
|
||||
workers = '40%' // Lower concurrency for heavier Electron processes
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,11 +153,7 @@ fn z(origin, scale, depth) {
|
||||
|> yLine(length = segLen(seg3))
|
||||
|> xLine(endAbsolute = 0 + origin[0])
|
||||
|> yLine(length = -0.225 * scale)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 0,
|
||||
intersectTag = seg2,
|
||||
offset = 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 0, intersectTag = seg2, offset = 0)
|
||||
|> close()
|
||||
|> extrude(length = -depth)
|
||||
|> appearance(color = baseColor)
|
||||
|
||||
@ -21,11 +21,7 @@ export fn zLogo(surface, origin, scale) {
|
||||
|> yLine(length = segLen(seg3))
|
||||
|> xLine(endAbsolute = 0 + origin[0])
|
||||
|> yLine(length = -0.225 * scale)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 0,
|
||||
intersectTag = seg2,
|
||||
offset = 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 0, intersectTag = seg2, offset = 0)
|
||||
|> close()
|
||||
return zSketch
|
||||
}
|
||||
|
||||
60
rust/Cargo.lock
generated
@ -133,9 +133,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.97"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -482,9 +482,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.32"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -492,9 +492,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.32"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -995,9 +995,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@ -1615,9 +1615,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.5"
|
||||
version = "0.25.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
|
||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
@ -1780,7 +1780,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1791,7 +1791,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1810,7 +1810,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1819,7 +1819,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.61"
|
||||
version = "0.2.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1840,7 +1840,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1860,7 +1860,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.61"
|
||||
version = "0.2.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1928,7 +1928,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.61"
|
||||
version = "0.3.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1943,7 +1943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1956,7 +1956,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1970,7 +1970,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"console_error_panic_hook",
|
||||
@ -2033,9 +2033,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.2.113"
|
||||
version = "0.2.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa1c927569925425a1b03711617c384a30cb7554394e8a6a01266910b22421de"
|
||||
checksum = "681ce29b9da92aa6f8bfc003ccb79a9f1a84368e064d68684327b3181dfe16ec"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2156,9 +2156,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.26"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -2414,9 +2414,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "oncemutex"
|
||||
@ -3890,9 +3890,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.40"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
@ -3911,9 +3911,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.21"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
|
||||
@ -31,12 +31,12 @@ debug = "line-tables-only"
|
||||
async-trait = "0.1.88"
|
||||
anyhow = { version = "1" }
|
||||
bson = { version = "2.13.0", features = ["uuid-1", "chrono"] }
|
||||
clap = { version = "4.5.31", features = ["derive"] }
|
||||
clap = { version = "4.5.36", features = ["derive"] }
|
||||
dashmap = { version = "6.1.0" }
|
||||
http = "1"
|
||||
indexmap = "2.7.0"
|
||||
kittycad = { version = "0.3.36", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.113", features = ["ts-rs", "websocket"] }
|
||||
kittycad-modeling-cmds = { version = "0.2.114", features = ["ts-rs", "websocket"] }
|
||||
lazy_static = "1.5.0"
|
||||
miette = "7.5.0"
|
||||
pyo3 = { version = "0.24.1" }
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
@ -14,7 +14,7 @@ bench = false
|
||||
[dependencies]
|
||||
Inflector = "0.11.4"
|
||||
convert_case = "0.8.0"
|
||||
once_cell = "1.20.3"
|
||||
once_cell = "1.21.3"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
regex = "1.11"
|
||||
|
||||
@ -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.61"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.61"
|
||||
version = "0.1.62"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
@ -14,14 +14,14 @@ bench = false
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = ["cargo", "derive", "env", "unicode"] }
|
||||
flate2 = "1.1.0"
|
||||
flate2 = "1.1.1"
|
||||
lazy_static = { workspace = true }
|
||||
log = { version = "0.4.26", features = ["serde"] }
|
||||
log = { version = "0.4.27", features = ["serde"] }
|
||||
slog = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
slog-json = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
time = "0.3.40"
|
||||
time = "0.3.41"
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tracing-subscriber = { workspace = true }
|
||||
xshell = "0.2.6"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.61"
|
||||
version = "0.2.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -23,7 +23,7 @@ kcl-lib = { path = "../kcl-lib", default-features = false, features = [
|
||||
] }
|
||||
kittycad = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
log = { version = "0.4.26", features = ["serde"] }
|
||||
log = { version = "0.4.27", features = ["serde"] }
|
||||
slog = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
slog-json = { workspace = true }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { runTests } from '@vscode/test-electron'
|
||||
import * as path from 'path'
|
||||
import { runTests } from '@vscode/test-electron'
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
|
||||
@ -17,9 +17,7 @@
|
||||
"cad",
|
||||
"manufacturing"
|
||||
],
|
||||
"categories": [
|
||||
"Programming Languages"
|
||||
],
|
||||
"categories": ["Programming Languages"],
|
||||
"repository": {
|
||||
"url": "https://github.com/kittycad/modeling-app.git",
|
||||
"type": "git"
|
||||
@ -28,17 +26,13 @@
|
||||
"vscode": "^1.97.0"
|
||||
},
|
||||
"enabledApiProposals": [],
|
||||
"activationEvents": [
|
||||
"onLanguage:kcl"
|
||||
],
|
||||
"activationEvents": ["onLanguage:kcl"],
|
||||
"main": "./dist/main.js",
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "kcl",
|
||||
"extensions": [
|
||||
".kcl"
|
||||
]
|
||||
"extensions": [".kcl"]
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
@ -46,10 +40,7 @@
|
||||
"title": "kcl-language-server",
|
||||
"properties": {
|
||||
"kcl-language-server.server.path": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
],
|
||||
"type": ["null", "string"],
|
||||
"scope": "machine-overridable",
|
||||
"default": null,
|
||||
"markdownDescription": "Path to kcl-language-server executable (points to bundled binary by default)."
|
||||
@ -57,16 +48,8 @@
|
||||
"kcl-language-server.trace.server": {
|
||||
"type": "string",
|
||||
"scope": "window",
|
||||
"enum": [
|
||||
"off",
|
||||
"messages",
|
||||
"verbose"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"No traces",
|
||||
"Error only",
|
||||
"Full log"
|
||||
],
|
||||
"enum": ["off", "messages", "verbose"],
|
||||
"enumDescriptions": ["No traces", "Error only", "Full log"],
|
||||
"default": "off",
|
||||
"description": "Trace requests to the kcl-language-server (this is usually overly verbose and not recommended for regular users)."
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.61"
|
||||
version = "0.2.62"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
@ -26,7 +26,7 @@ async-trait = { workspace = true }
|
||||
base64 = "0.22.1"
|
||||
bson = { workspace = true }
|
||||
chrono = "0.4.38"
|
||||
clap = { version = "4.5.27", default-features = false, optional = true, features = [
|
||||
clap = { version = "4.5.36", default-features = false, optional = true, features = [
|
||||
"std",
|
||||
"derive",
|
||||
] }
|
||||
@ -39,7 +39,7 @@ futures = { version = "0.3.31" }
|
||||
git_rev = "0.1.0"
|
||||
gltf-json = "1.4.1"
|
||||
http = { workspace = true }
|
||||
image = { version = "0.25.5", default-features = false, features = ["png"] }
|
||||
image = { version = "0.25.6", default-features = false, features = ["png"] }
|
||||
indexmap = { workspace = true, features = ["serde"] }
|
||||
itertools = "0.13.0"
|
||||
kcl-derive-docs = { version = "0.1", path = "../kcl-derive-docs" }
|
||||
@ -121,7 +121,7 @@ base64 = "0.22.1"
|
||||
criterion = { version = "0.5.1", features = ["async_tokio"] }
|
||||
expectorate = "1.1.0"
|
||||
handlebars = "6.3.2"
|
||||
image = { version = "0.25.5", default-features = false, features = ["png"] }
|
||||
image = { version = "0.25.6", default-features = false, features = ["png"] }
|
||||
insta = { version = "1.41.1", features = ["json", "filters", "redactions"] }
|
||||
kcl-directory-test-macro = { version = "0.1", path = "../kcl-directory-test-macro" }
|
||||
miette = { version = "7.5.0", features = ["fancy"] }
|
||||
|
||||
@ -152,11 +152,11 @@ const extrude005l = extrude(sketch005l, length = 1)
|
||||
|
||||
const sketch006l = startSketchOn(plane001)
|
||||
|> startProfileAt([1, 1], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 70,
|
||||
intersectTag: lineToIntersect4,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = 70,
|
||||
intersectTag = lineToIntersect4,
|
||||
offset = 0,
|
||||
)
|
||||
|> angledLine(angle = -70, length = 1.414 )
|
||||
|> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -168,11 +168,11 @@ const sketch007l = startSketchOn(plane001)
|
||||
serverDepth - 1.2,
|
||||
railHeight * 1.75 + 1
|
||||
], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 70,
|
||||
intersectTag: lineToIntersect5,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = 70,
|
||||
intersectTag = lineToIntersect5,
|
||||
offset = 0,
|
||||
)
|
||||
|> angledLine(angle = -70, length = 1.414 )
|
||||
|> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -243,11 +243,12 @@ const sketch006w = startSketchOn(plane002)
|
||||
], %)
|
||||
|> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1)
|
||||
|> yLine(length = 2.56)
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 90 + 180,
|
||||
intersectTag: lineToIntersect,
|
||||
offset: 0
|
||||
}, %, $lineToIntersect2)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 90 + 180,
|
||||
intersectTag = lineToIntersect,
|
||||
offset = 0,
|
||||
tag = $lineToIntersect2,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude006w = extrude(sketch006w, length = 1)
|
||||
@ -256,28 +257,28 @@ const sketch007w = startSketchOn(plane002)
|
||||
|> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %)
|
||||
|> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3)
|
||||
|> angledLine(angle = 23 - 90, length = 1.414 )
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 180,
|
||||
intersectTag: lineToIntersect2,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 180,
|
||||
intersectTag = lineToIntersect2,
|
||||
offset = 0,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude007w = extrude(sketch007w, length = 1)
|
||||
|
||||
const sketch008w = startSketchOn(plane002)
|
||||
|> startProfileAt([1, 41.7 + 1.75 / 2], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 90,
|
||||
intersectTag: lineToIntersect3,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 90,
|
||||
intersectTag = lineToIntersect3,
|
||||
offset = 0,
|
||||
)
|
||||
|> angledLine(angle = -23 - 45, length = 1.414 )
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 - 90,
|
||||
intersectTag: lineToIntersect,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 - 90,
|
||||
intersectTag = lineToIntersect,
|
||||
offset = 0,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude008w = extrude(sketch008w, length = 1)
|
||||
|
||||
@ -150,11 +150,7 @@ const extrude005l = extrude(sketch005l, length = 1)
|
||||
|
||||
const sketch006l = startSketchOn(plane001)
|
||||
|> startProfileAt([1, 1], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 70,
|
||||
intersectTag: lineToIntersect4,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 70, intersectTag = lineToIntersect4, offset = 0)
|
||||
|> angledLine(angle = -70, length = 1.414 )
|
||||
|> angledLine(angle = 70 + 180, endAbsoluteY = 2 - 1)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -166,11 +162,7 @@ const sketch007l = startSketchOn(plane001)
|
||||
serverDepth - 1.2,
|
||||
railHeight * 1.75 + 1
|
||||
], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 70,
|
||||
intersectTag: lineToIntersect5,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(angle = 70, intersectTag = lineToIntersect5, offset = 0)
|
||||
|> angledLine(angle = -70, length = 1.414 )
|
||||
|> angledLine(angle = 70 + 180, endAbsoluteY = railHeight * 1.75 + 1)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
@ -241,11 +233,12 @@ const sketch006w = startSketchOn(plane002)
|
||||
], %)
|
||||
|> angledLine(angle = -23 + 90, endAbsoluteX = depth - 1)
|
||||
|> yLine(length = 2.56)
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 90 + 180,
|
||||
intersectTag: lineToIntersect,
|
||||
offset: 0
|
||||
}, %, $lineToIntersect2)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 90 + 180,
|
||||
intersectTag = lineToIntersect,
|
||||
offset = 0,
|
||||
tag = $lineToIntersect2,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude006w = extrude(sketch006w, length = 1)
|
||||
@ -254,28 +247,28 @@ const sketch007w = startSketchOn(plane002)
|
||||
|> startProfileAt([depth - 1, 60.65 + 1.75 / 2], %)
|
||||
|> angledLine(angle = -23 + 180, length = 34.93 , tag = $lineToIntersect3)
|
||||
|> angledLine(angle = 23 - 90, length = 1.414 )
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 180,
|
||||
intersectTag: lineToIntersect2,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 180,
|
||||
intersectTag = lineToIntersect2,
|
||||
offset = 0,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude007w = extrude(sketch007w, length = 1)
|
||||
|
||||
const sketch008w = startSketchOn(plane002)
|
||||
|> startProfileAt([1, 41.7 + 1.75 / 2], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 + 90,
|
||||
intersectTag: lineToIntersect3,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 + 90,
|
||||
intersectTag = lineToIntersect3,
|
||||
offset = 0,
|
||||
)
|
||||
|> angledLine(angle = -23 - 45, length = 1.414 )
|
||||
|> angledLineThatIntersects({
|
||||
angle: -23 - 90,
|
||||
intersectTag: lineToIntersect,
|
||||
offset: 0
|
||||
}, %)
|
||||
|> angledLineThatIntersects(
|
||||
angle = -23 - 90,
|
||||
intersectTag = lineToIntersect,
|
||||
offset = 0,
|
||||
)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
const extrude008w = extrude(sketch008w, length = 1)
|
||||
|
||||
@ -644,7 +644,7 @@ impl GetTangentialInfoFromPathsResult {
|
||||
pub(crate) fn tan_previous_point(&self, last_arc_end: [f64; 2]) -> [f64; 2] {
|
||||
match self {
|
||||
GetTangentialInfoFromPathsResult::PreviousPoint(p) => *p,
|
||||
GetTangentialInfoFromPathsResult::Arc { center, ccw, .. } => {
|
||||
GetTangentialInfoFromPathsResult::Arc { center, ccw } => {
|
||||
crate::std::utils::get_tangent_point_from_previous_arc(*center, *ccw, last_arc_end)
|
||||
}
|
||||
// The circle always starts at 0 degrees, so a suitable tangent
|
||||
@ -1231,12 +1231,9 @@ impl Path {
|
||||
},
|
||||
Path::ArcThreePoint { p1, p2, p3, .. } => {
|
||||
let circle_center = crate::std::utils::calculate_circle_from_3_points([*p1, *p2, *p3]);
|
||||
let radius = linear_distance(&[circle_center.center[0], circle_center.center[1]], p1);
|
||||
let center_point = [circle_center.center[0], circle_center.center[1]];
|
||||
GetTangentialInfoFromPathsResult::Circle {
|
||||
center: center_point,
|
||||
ccw: true,
|
||||
radius,
|
||||
GetTangentialInfoFromPathsResult::Arc {
|
||||
center: circle_center.center,
|
||||
ccw: crate::std::utils::is_points_ccw(&[*p1, *p2, *p3]) > 0,
|
||||
}
|
||||
}
|
||||
Path::Circle {
|
||||
@ -1252,6 +1249,7 @@ impl Path {
|
||||
let center_point = [circle_center.center[0], circle_center.center[1]];
|
||||
GetTangentialInfoFromPathsResult::Circle {
|
||||
center: center_point,
|
||||
// Note: a circle is always ccw regardless of the order of points
|
||||
ccw: true,
|
||||
radius,
|
||||
}
|
||||
|
||||
@ -4497,8 +4497,8 @@ e
|
||||
/// )
|
||||
/// |> yLine(endAbsolute = 0)
|
||||
/// |> close(%)
|
||||
///
|
||||
/// example = extrude(5, exampleSketch)
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 5)
|
||||
/// ```
|
||||
@(impl = std_rust)
|
||||
export fn cos(num: number(rad)): number(_) {}"#;
|
||||
|
||||
@ -2482,6 +2482,7 @@ mod intersect_cubes {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
|
||||
mod pattern_into_union {
|
||||
const TEST_NAME: &str = "pattern_into_union";
|
||||
|
||||
@ -2524,3 +2525,24 @@ mod subtract_doesnt_need_brackets {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
|
||||
mod tangent_to_3_point_arc {
|
||||
const TEST_NAME: &str = "tangent_to_3_point_arc";
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn unparse() {
|
||||
super::unparse(TEST_NAME).await
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -991,20 +991,6 @@ macro_rules! let_field_of {
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for super::sketch::AngledLineThatIntersectsData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
let_field_of!(obj, angle);
|
||||
let_field_of!(obj, intersect_tag "intersectTag");
|
||||
let_field_of!(obj, offset?);
|
||||
Some(Self {
|
||||
angle,
|
||||
intersect_tag,
|
||||
offset,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromKclValue<'a> for super::shapes::PolygonData {
|
||||
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
|
||||
let obj = arg.as_object()?;
|
||||
|
||||
@ -617,12 +617,12 @@ pub async fn angled_line(exec_state: &mut ExecState, args: Args) -> Result<KclVa
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch = { docs = "Which sketch should this path be added to?"},
|
||||
angle = { docs = "Which angle should the line be drawn at?" },
|
||||
length = { docs = "Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
length_x = { docs = "Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
length_y = { docs = "Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
end_absolute_x = { docs = "Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
end_absolute_y = { docs = "Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
angle = { docs = "Which angle should the line be drawn at?" },
|
||||
length = { docs = "Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
length_x = { docs = "Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
length_y = { docs = "Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
end_absolute_x = { docs = "Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
end_absolute_y = { docs = "Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given."},
|
||||
tag = { docs = "Create a new tag which refers to this line"},
|
||||
}
|
||||
}]
|
||||
@ -871,25 +871,16 @@ async fn inner_angled_line_to_y(
|
||||
Ok(new_sketch)
|
||||
}
|
||||
|
||||
/// Data for drawing an angled line that intersects with a given line.
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
// TODO: make sure the docs on the args below are correct.
|
||||
pub struct AngledLineThatIntersectsData {
|
||||
/// The angle of the line.
|
||||
pub angle: TyF64,
|
||||
/// The tag of the line to intersect with.
|
||||
pub intersect_tag: TagIdentifier,
|
||||
/// The offset from the intersecting line.
|
||||
pub offset: Option<TyF64>,
|
||||
}
|
||||
|
||||
/// Draw an angled line that intersects with a given line.
|
||||
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch, tag): (AngledLineThatIntersectsData, Sketch, Option<TagNode>) =
|
||||
args.get_data_and_sketch_and_tag(exec_state)?;
|
||||
let new_sketch = inner_angled_line_that_intersects(data, sketch, tag, exec_state, args).await?;
|
||||
let sketch =
|
||||
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
|
||||
let angle: TyF64 = args.get_kw_arg("angle")?;
|
||||
let intersect_tag: TagIdentifier = args.get_kw_arg("intersectTag")?;
|
||||
let offset: Option<TyF64> = args.get_kw_arg_opt("offset")?;
|
||||
let tag: Option<TagNode> = args.get_kw_arg_opt("tag")?;
|
||||
let new_sketch =
|
||||
inner_angled_line_that_intersects(sketch, angle, intersect_tag, offset, tag, exec_state, args).await?;
|
||||
Ok(KclValue::Sketch {
|
||||
value: Box::new(new_sketch),
|
||||
})
|
||||
@ -905,26 +896,37 @@ pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args)
|
||||
/// |> line(endAbsolute = [5, 10])
|
||||
/// |> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
|
||||
/// |> line(endAbsolute = [0, 20])
|
||||
/// |> angledLineThatIntersects({
|
||||
/// |> angledLineThatIntersects(
|
||||
/// angle = 80,
|
||||
/// intersectTag = lineToIntersect,
|
||||
/// offset = 10
|
||||
/// }, %)
|
||||
/// offset = 10,
|
||||
/// )
|
||||
/// |> close()
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 10)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "angledLineThatIntersects",
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch = { docs = "Which sketch should this path be added to?"},
|
||||
angle = { docs = "Which angle should the line be drawn at?" },
|
||||
intersect_tag = { docs = "The tag of the line to intersect with" },
|
||||
offset = { docs = "The offset from the intersecting line. Defaults to 0." },
|
||||
tag = { docs = "Create a new tag which refers to this line"},
|
||||
}
|
||||
}]
|
||||
pub async fn inner_angled_line_that_intersects(
|
||||
data: AngledLineThatIntersectsData,
|
||||
sketch: Sketch,
|
||||
angle: TyF64,
|
||||
intersect_tag: TagIdentifier,
|
||||
offset: Option<TyF64>,
|
||||
tag: Option<TagNode>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Sketch, KclError> {
|
||||
let intersect_path = args.get_tag_engine_info(exec_state, &data.intersect_tag)?;
|
||||
let intersect_path = args.get_tag_engine_info(exec_state, &intersect_tag)?;
|
||||
let path = intersect_path.path.clone().ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected an intersect path with a path, found `{:?}`", intersect_path),
|
||||
@ -935,13 +937,12 @@ pub async fn inner_angled_line_that_intersects(
|
||||
let from = sketch.current_pen_position()?;
|
||||
let to = intersection_with_parallel_line(
|
||||
&[untype_point(path.get_from()).0, untype_point(path.get_to()).0],
|
||||
data.offset.map(|t| t.n).unwrap_or_default(),
|
||||
data.angle.n,
|
||||
offset.map(|t| t.n).unwrap_or_default(),
|
||||
angle.n,
|
||||
from.into(),
|
||||
);
|
||||
|
||||
let new_sketch = straight_line(StraightLineParams::absolute(to, sketch, tag), exec_state, args).await?;
|
||||
Ok(new_sketch)
|
||||
straight_line(StraightLineParams::absolute(to, sketch, tag), exec_state, args).await
|
||||
}
|
||||
|
||||
/// Data for start sketch on.
|
||||
|
||||
@ -2137,16 +2137,13 @@ mySk1 = startSketchOn(XY)
|
||||
|
||||
#[test]
|
||||
fn test_recast_multiline_object() {
|
||||
let some_program_string = r#"part001 = startSketchOn(XY)
|
||||
|> startProfileAt([-0.01, -0.08], %)
|
||||
|> line([0.62, 4.15], %, $seg01)
|
||||
|> line([2.77, -1.24], %)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 201,
|
||||
offset = -1.35,
|
||||
intersectTag = seg01
|
||||
}, %)
|
||||
|> line([-0.42, -1.72], %)"#;
|
||||
let some_program_string = r#"x = {
|
||||
a = 1000000000,
|
||||
b = 2000000000,
|
||||
c = 3000000000,
|
||||
d = 4000000000,
|
||||
e = 5000000000
|
||||
}"#;
|
||||
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
|
||||
let recasted = program.recast(&Default::default(), 0);
|
||||
|
||||
@ -122,11 +122,8 @@ export type string
|
||||
/// myRect = rect([20, 0])
|
||||
///
|
||||
/// myRect
|
||||
/// |> extrude(10, %)
|
||||
/// |> fillet(
|
||||
/// radius = 0.5,
|
||||
/// tags = [myRect.tags.rectangleSegmentA001]
|
||||
/// )
|
||||
/// |> extrude(length = 10)
|
||||
/// |> fillet(radius = 0.5, tags = [myRect.tags.rectangleSegmentA001])
|
||||
/// ```
|
||||
///
|
||||
/// See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
||||
|
||||