Compare commits
240 Commits
jtran/fix-
...
kcl-79
Author | SHA1 | Date | |
---|---|---|---|
f97bdaf8b7 | |||
3f3693e12d | |||
73660d1db8 | |||
c373f33507 | |||
2dc76a71cc | |||
ce42966f2b | |||
b47b9c9613 | |||
2af2144f89 | |||
bd37c488ee | |||
a3551e4b2f | |||
d3979edb41 | |||
095a7a575b | |||
b5c8ca05a5 | |||
33f7badf41 | |||
569935c21f | |||
7680605085 | |||
2bb6c74f42 | |||
faf4d42b6a | |||
8dd2a86191 | |||
13c4de77c3 | |||
e29ee9d1ca | |||
b7437e949a | |||
08781ff010 | |||
eb79b1f746 | |||
8df81b2753 | |||
e75a604c64 | |||
0624e42822 | |||
1c07e8af5b | |||
5fccaad0e7 | |||
a506f7f698 | |||
1bb96cd878 | |||
b63b0e538a | |||
5118198cec | |||
1611244b94 | |||
227ad31fc2 | |||
80e3dc9095 | |||
46b6707e3a | |||
0eebb76bfd | |||
464372e7ed | |||
75dff9f775 | |||
5f6d810fbb | |||
55e1ec7dad | |||
b123dacc41 | |||
87e3588ceb | |||
c4d2e33a99 | |||
2ac05508bc | |||
5c6d4fbf5a | |||
aaff027830 | |||
355a450c09 | |||
21f4fcb041 | |||
37aea72a88 | |||
783b6ed76c | |||
9dfb67cf61 | |||
889c72ec60 | |||
067e193780 | |||
77730196ae | |||
dba0173cc3 | |||
8f4327ab6b | |||
cc2769e907 | |||
91b6db0ba5 | |||
8bae76000c | |||
f502e445cc | |||
083bfe6ec2 | |||
2c1a5ff5c4 | |||
0c2785df67 | |||
fa9d5a0104 | |||
678433d2b3 | |||
30bd307931 | |||
08dfaba7f7 | |||
eb2327827b | |||
1f53dd1357 | |||
034366e65e | |||
cd537cd9c2 | |||
22f92942f6 | |||
4eee50d79e | |||
125b2c44d4 | |||
db9e35d686 | |||
d0958220fe | |||
fa4b3cfd1b | |||
8972f8f109 | |||
85ccc6900c | |||
4e2deca5d8 | |||
04a2c184d7 | |||
2c7701e2d4 | |||
ae569b61db | |||
0a0e6abd3f | |||
9c7aee32bd | |||
ed979d807b | |||
f5c244dbb1 | |||
0ea1e9a6da | |||
a36530d6df | |||
825d34718a | |||
d90d445d84 | |||
5976a0cba6 | |||
b50f2f5a2a | |||
f877b52898 | |||
4a585db637 | |||
4d404bf137 | |||
e644b7e1fc | |||
aff1684064 | |||
d9afc50f91 | |||
eb7b4ccda6 | |||
bbf4f1d251 | |||
3cc7859ca5 | |||
ab63345c57 | |||
3df02e02fa | |||
35f5c62633 | |||
0f0fc39d07 | |||
a13b6b2b70 | |||
4212b95232 | |||
38a73a603b | |||
c48d9fd4d7 | |||
0753987b5a | |||
815ff7dc2b | |||
46684d420d | |||
eca09984a3 | |||
ce63c6423e | |||
09699afe82 | |||
36c8ad439d | |||
5dc77ceed5 | |||
c7baa26b2d | |||
4d0454abcd | |||
1dafbf105e | |||
773f013115 | |||
c5cd460595 | |||
845352046b | |||
597f1087f9 | |||
511334683a | |||
223a4ad45d | |||
edf31ec1d3 | |||
1539557005 | |||
1d3ba4e3ac | |||
4110aa00db | |||
7eb52cda36 | |||
7872fb9cbd | |||
651181e62c | |||
38a245f2fc | |||
1b4289f93f | |||
d0697c24fd | |||
8c24e29081 | |||
2b9d26e2ff | |||
ab148a7654 | |||
553e650fbe | |||
9690a24c68 | |||
978d5d44a2 | |||
9df476543a | |||
cf303ebe97 | |||
b1d1d89ca5 | |||
3a599d0a0a | |||
8340f6b906 | |||
ddb034b14d | |||
bfa2f67393 | |||
447069a97b | |||
49b78d726a | |||
5b4cddd0b0 | |||
8878c148ed | |||
c3c2ded795 | |||
fb35fdcc38 | |||
e76ba9921c | |||
b19acd550d | |||
f3e9d110c0 | |||
658497da1d | |||
bd01059a92 | |||
57a977e6be | |||
94b0cc1f3e | |||
5734cc7fc3 | |||
3168c22de7 | |||
3c94fe9047 | |||
cdd6b56d42 | |||
75ac3bc61b | |||
29d511d085 | |||
b0a41939e8 | |||
7d2c1061ba | |||
d768073d17 | |||
dc8496c62e | |||
416de9a9fb | |||
da65426ddc | |||
585b485852 | |||
e85f16ff9c | |||
e7d2289a14 | |||
d35531758d | |||
729e0a7949 | |||
620b7401aa | |||
e3e67b00d5 | |||
49d4f8e5c3 | |||
47b159c605 | |||
c7b086fa69 | |||
203db79204 | |||
48a4fd8373 | |||
17eb84325f | |||
ebf048478d | |||
28a8cd2421 | |||
1506de92f5 | |||
8a03413643 | |||
f59b806a88 | |||
23a0085c78 | |||
a280a8c3f0 | |||
11620dfa6b | |||
f6e26e0bab | |||
f6b3a55cbf | |||
74939e5cd6 | |||
9906c9947a | |||
48d6a21f0a | |||
dd6a980915 | |||
2516df3a39 | |||
52125f0566 | |||
e489222b6a | |||
d93a57d7bf | |||
d34aea345b | |||
0b6102b0ac | |||
9e0873ed84 | |||
8587eb5fea | |||
b898c27e74 | |||
3026866a16 | |||
92fc294eae | |||
21e967ea7f | |||
3f00e7186c | |||
d3a4fd8b55 | |||
2be7107cca | |||
94f194a984 | |||
4fe880a970 | |||
8f5fbfc273 | |||
e660f52bb0 | |||
d74fdd9369 | |||
334145f0be | |||
c24073b6ae | |||
078b7f3bf7 | |||
3d65676ccb | |||
ce566fb6e5 | |||
b23fc9f623 | |||
5c2dfb8e40 | |||
0e341d7863 | |||
6a03ff9596 | |||
d7bd0c937d | |||
d3b2483f4f | |||
7838b7c9fd | |||
130ecf1f88 | |||
550d8b3753 | |||
696222a070 | |||
edb424988d |
12
.github/ci-cd-scripts/playwright-electron.sh
vendored
12
.github/ci-cd-scripts/playwright-electron.sh
vendored
@ -7,11 +7,11 @@ if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||
# If no last run artifact, than run Playwright normally
|
||||
echo "run playwright normally"
|
||||
if [[ "$3" == *ubuntu* ]]; then
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron -- --shard=$1/$2 || true
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:e2e:desktop -- --shard=$1/$2 || true
|
||||
elif [[ "$3" == *windows* ]]; then
|
||||
npm run test:playwright:electron -- --grep=@windows --shard=$1/$2 || true
|
||||
npm run test:e2e:desktop -- --grep=@windows --shard=$1/$2 || true
|
||||
elif [[ "$3" == *macos* ]]; then
|
||||
npm run test:playwright:electron -- --grep=@macos --shard=$1/$2 || true
|
||||
npm run test:e2e:desktop -- --grep=@macos --shard=$1/$2 || true
|
||||
else
|
||||
echo "Do not run Playwright. Unable to detect os runtime."
|
||||
exit 1
|
||||
@ -31,11 +31,11 @@ while [[ $retry -le $max_retries ]]; do
|
||||
echo "retried=true" >>$GITHUB_OUTPUT
|
||||
echo "run playwright with last failed tests and retry $retry"
|
||||
if [[ "$3" == *ubuntu* ]]; then
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron -- --last-failed || true
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:e2e:desktop -- --last-failed || true
|
||||
elif [[ "$3" == *windows* ]]; then
|
||||
npm run test:playwright:electron -- --grep=@windows --last-failed || true
|
||||
npm run test:e2e:desktop -- --grep=@windows --last-failed || true
|
||||
elif [[ "$3" == *macos* ]]; then
|
||||
npm run test:playwright:electron -- --grep=@macos --last-failed || true
|
||||
npm run test:e2e:desktop -- --grep=@macos --last-failed || true
|
||||
else
|
||||
echo "Do not run playwright. Unable to detect os runtime."
|
||||
exit 1
|
||||
|
2
.github/ci-cd-scripts/upload-results.sh
vendored
2
.github/ci-cd-scripts/upload-results.sh
vendored
@ -6,6 +6,7 @@ if [ -z "${TAB_API_URL:-}" ] || [ -z "${TAB_API_KEY:-}" ]; then
|
||||
fi
|
||||
|
||||
project="https://github.com/KittyCAD/modeling-app"
|
||||
suite="${CI_SUITE:-unit}"
|
||||
branch="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-}}"
|
||||
commit="${CI_COMMIT_SHA:-${GITHUB_SHA:-}}"
|
||||
|
||||
@ -13,6 +14,7 @@ echo "Uploading batch results"
|
||||
curl --silent --request POST \
|
||||
--header "X-API-Key: ${TAB_API_KEY}" \
|
||||
--form "project=${project}" \
|
||||
--form "suite=${suite}" \
|
||||
--form "branch=${branch}" \
|
||||
--form "commit=${commit}" \
|
||||
--form "tests=@test-results/junit.xml" \
|
||||
|
55
.github/workflows/build-apps.yml
vendored
55
.github/workflows/build-apps.yml
vendored
@ -123,18 +123,6 @@ jobs:
|
||||
- id: export_notes
|
||||
run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare electron-builder.yml file for updater test
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
run: |
|
||||
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/updater-test"' electron-builder.yml
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
with:
|
||||
name: prepared-files-updater-test
|
||||
path: |
|
||||
electron-builder.yml
|
||||
|
||||
|
||||
build-apps:
|
||||
needs: [prepare-files]
|
||||
@ -259,49 +247,6 @@ jobs:
|
||||
|
||||
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back
|
||||
|
||||
# The steps below are for updater-test builds, only on release
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
name: prepared-files-updater-test
|
||||
|
||||
- name: Copy updated electron-builder.yml file for updater test
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
run: |
|
||||
ls -R prepared-files-updater-test
|
||||
cp prepared-files-updater-test/electron-builder.yml electron-builder.yml
|
||||
|
||||
- name: Build the app (updater-test)
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
|
||||
run: npm run tronb:package:prod
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
with:
|
||||
name: updater-test-arm64-${{ matrix.platform }}
|
||||
path: |
|
||||
out/*-arm64-win.exe
|
||||
out/*-arm64-mac.dmg
|
||||
out/*-arm64-linux.AppImage
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ env.IS_RELEASE == 'true' }}
|
||||
with:
|
||||
name: updater-test-x64-${{ matrix.platform }}
|
||||
path: |
|
||||
out/*-x64-win.exe
|
||||
out/*-x64-mac.dmg
|
||||
out/*-x86_64-linux.AppImage
|
||||
|
||||
|
||||
upload-apps-release:
|
||||
runs-on: ubuntu-22.04
|
||||
|
56
.github/workflows/build-wasm.yml
vendored
Normal file
56
.github/workflows/build-wasm.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name: Build WASM
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
npm-build-wasm:
|
||||
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false # configured below
|
||||
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Use Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './rust'
|
||||
|
||||
- name: Build Wasm
|
||||
shell: bash
|
||||
run: npm run build:wasm
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prepared-wasm
|
||||
path: |
|
||||
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prepared-ts-rs-bindings
|
||||
path: |
|
||||
rust/kcl-lib/bindings/*
|
63
.github/workflows/cargo-test.yml
vendored
63
.github/workflows/cargo-test.yml
vendored
@ -1,16 +1,22 @@
|
||||
name: cargo test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 * * * * # hourly
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
name: cargo test
|
||||
|
||||
jobs:
|
||||
build-test-artifacts:
|
||||
name: Build test artifacts
|
||||
@ -88,6 +94,7 @@ jobs:
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
|
||||
ZOO_HOST: https://api.dev.zoo.dev
|
||||
RUST_BACKTRACE: full
|
||||
RUST_MIN_STACK: 10485760000
|
||||
- name: Commit differences
|
||||
if: steps.path-changes.outputs.outside-kcl-samples == 'false' && steps.cargo-test-kcl-samples.outcome == 'failure'
|
||||
shell: bash
|
||||
@ -119,6 +126,7 @@ jobs:
|
||||
# Configure nextest when it's run by insta (via just).
|
||||
NEXTEST_PROFILE: ci
|
||||
RUST_BACKTRACE: full
|
||||
RUST_MIN_STACK: 10485760000
|
||||
- name: Build and archive tests
|
||||
run: |
|
||||
cd rust
|
||||
@ -155,7 +163,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
- name: Install rust
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false # Configured below.
|
||||
@ -182,6 +190,7 @@ jobs:
|
||||
env:
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
|
||||
ZOO_HOST: https://api.dev.zoo.dev
|
||||
RUST_MIN_STACK: 10485760000
|
||||
- name: Upload results
|
||||
if: always()
|
||||
run: .github/ci-cd-scripts/upload-results.sh
|
||||
@ -190,6 +199,56 @@ jobs:
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
CI_SUITE: e2e:kcl
|
||||
run-internal-kcl-samples:
|
||||
name: cargo test (internal-kcl-samples)
|
||||
runs-on:
|
||||
- runs-on=${{ github.run_id }}
|
||||
- runner=32cpu-linux-x64
|
||||
- extras=s3-cache
|
||||
steps:
|
||||
- uses: runs-on/action@v1
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
|
||||
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false # Configured below.
|
||||
- name: Start Vector
|
||||
run: .github/ci-cd-scripts/start-vector-ubuntu.sh
|
||||
env:
|
||||
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
|
||||
OS_NAME: ${{ env.OS_NAME }}
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- name: Download internal KCL samples
|
||||
run: git clone --depth=1 https://x-access-token:${{ secrets.GH_PAT_KCL_SAMPLES_INTERNAL }}@github.com/KittyCAD/kcl-samples-internal public/kcl-samples/internal
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |-
|
||||
cd rust/kcl-lib
|
||||
cargo nextest run \
|
||||
--retries=10 --no-fail-fast --features artifact-graph --profile=ci \
|
||||
internal \
|
||||
2>&1 | tee /tmp/github-actions.log
|
||||
env:
|
||||
TWENTY_TWENTY: overwrite
|
||||
INSTA_UPDATE: always
|
||||
EXPECTORATE: overwrite
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
|
||||
ZOO_HOST: https://api.dev.zoo.dev
|
||||
MODELING_APP_INTERNAL_SAMPLES_SECRET: ${{secrets.MODELING_APP_INTERNAL_SAMPLES_SECRET}}
|
||||
RUST_MIN_STACK: 10485760000
|
||||
run-wasm-tests:
|
||||
name: Run wasm tests
|
||||
strategy:
|
||||
|
173
.github/workflows/e2e-tests.yml
vendored
173
.github/workflows/e2e-tests.yml
vendored
@ -1,4 +1,5 @@
|
||||
name: E2E Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -19,9 +20,11 @@ permissions:
|
||||
jobs:
|
||||
|
||||
prepare-wasm:
|
||||
|
||||
# separate job on Ubuntu to build or fetch the wasm blob once on the fastest runner
|
||||
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- id: filter
|
||||
@ -40,7 +43,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Download Wasm Cache
|
||||
- name: Download Wasm cache
|
||||
id: download-wasm
|
||||
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
@ -52,7 +55,7 @@ jobs:
|
||||
branch: main
|
||||
path: rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Build WASM condition
|
||||
- name: Build Wasm condition
|
||||
id: wasm
|
||||
run: |
|
||||
set -euox pipefail
|
||||
@ -70,7 +73,7 @@ jobs:
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
|
||||
- name: Install rust
|
||||
- name: Install Rust
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
@ -81,7 +84,7 @@ jobs:
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Rust Cache
|
||||
- name: Use Rust cache
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
@ -99,10 +102,13 @@ jobs:
|
||||
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
|
||||
|
||||
snapshots:
|
||||
name: playwright:snapshots:ubuntu
|
||||
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
|
||||
needs: [prepare-wasm]
|
||||
|
||||
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
|
||||
name: e2e:snapshots
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
@ -117,7 +123,7 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
name: prepared-wasm
|
||||
|
||||
- name: Copy prepared wasm
|
||||
- name: Copy prepared Wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
@ -130,23 +136,19 @@ jobs:
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
id: deps-install
|
||||
run: npm install
|
||||
|
||||
- name: Cache Playwright Browsers
|
||||
- name: Download browser cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ms-playwright/
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
- name: Install browsers
|
||||
run: npm run playwright install --with-deps
|
||||
|
||||
- name: build web
|
||||
run: npm run tronb:vite:dev
|
||||
|
||||
- name: Run ubuntu/chrome snapshots
|
||||
- name: npm run test:snapshots
|
||||
uses: nick-fields/retry@v3.0.2
|
||||
with:
|
||||
shell: bash
|
||||
@ -159,6 +161,19 @@ jobs:
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
CI_SUITE: e2e:snapshots
|
||||
TARGET: web
|
||||
|
||||
- name: Update snapshots
|
||||
if: always()
|
||||
run: npm run test:snapshots -- --last-failed --update-snapshots
|
||||
env:
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
CI_SUITE: e2e:snapshots
|
||||
TARGET: web
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
@ -170,20 +185,19 @@ jobs:
|
||||
retention-days: 30
|
||||
overwrite: true
|
||||
|
||||
- name: Check for changes
|
||||
- name: Check diff
|
||||
if: ${{ github.ref != 'refs/heads/main' }}
|
||||
shell: bash
|
||||
id: git-check
|
||||
run: |
|
||||
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
|
||||
if git status | grep -q "Changes to be committed"
|
||||
if git status | grep --quiet "Changes to be committed"
|
||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Commit changes, if any
|
||||
# TODO: find a more reliable way to detect visual changes
|
||||
if: ${{ false && steps.git-check.outputs.modified == 'true' }}
|
||||
- name: Commit changes
|
||||
if: ${{ steps.git-check.outputs.modified == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
|
||||
@ -193,16 +207,100 @@ jobs:
|
||||
git fetch origin
|
||||
echo ${{ github.head_ref }}
|
||||
git checkout ${{ github.head_ref }}
|
||||
git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true
|
||||
git commit --message "Update snapshots" || true
|
||||
git push
|
||||
git push origin ${{ github.head_ref }}
|
||||
|
||||
electron:
|
||||
web:
|
||||
needs: [prepare-wasm]
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
|
||||
- os: namespace-profile-macos-8-cores
|
||||
- os: windows-latest-8-cores
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: e2e:web (${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }})
|
||||
env:
|
||||
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
|
||||
name: playwright:electron:${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }} (shard ${{ matrix.shardIndex }})
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
|
||||
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
name: prepared-wasm
|
||||
|
||||
- name: Copy prepared Wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
mkdir rust/kcl-wasm-lib/pkg
|
||||
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Download browser cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ms-playwright/
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
- name: Install browsers
|
||||
run: npm run playwright install --with-deps
|
||||
|
||||
- name: Start Vector
|
||||
if: ${{ !contains(matrix.os, 'windows') }}
|
||||
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh
|
||||
env:
|
||||
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
|
||||
OS_NAME: ${{ env.OS_NAME }}
|
||||
|
||||
- name: npm run test:e2e:web
|
||||
uses: nick-fields/retry@v3.0.2
|
||||
with:
|
||||
shell: bash
|
||||
command: npm run test:e2e:web
|
||||
timeout_minutes: 5
|
||||
max_attempts: 5
|
||||
env:
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
CI_SUITE: e2e:web
|
||||
TARGET: web
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() && (success() || failure()) }}
|
||||
with:
|
||||
path: playwright-report/
|
||||
include-hidden-files: true
|
||||
retention-days: 30
|
||||
overwrite: true
|
||||
|
||||
desktop:
|
||||
needs: [prepare-wasm]
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -234,18 +332,28 @@ jobs:
|
||||
shardTotal: 8
|
||||
- os: namespace-profile-macos-8-cores
|
||||
shardIndex: 1
|
||||
shardTotal: 1
|
||||
shardTotal: 2
|
||||
- os: namespace-profile-macos-8-cores
|
||||
shardIndex: 2
|
||||
shardTotal: 2
|
||||
- os: windows-latest-8-cores
|
||||
shardIndex: 1
|
||||
shardTotal: 1
|
||||
shardTotal: 2
|
||||
- os: windows-latest-8-cores
|
||||
shardIndex: 2
|
||||
shardTotal: 2
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: e2e:desktop (${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}, shard ${{ matrix.shardIndex }})
|
||||
env:
|
||||
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
name: prepared-wasm
|
||||
|
||||
- name: Copy prepared wasm
|
||||
- name: Copy prepared Wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
@ -261,19 +369,16 @@ jobs:
|
||||
id: deps-install
|
||||
run: npm install
|
||||
|
||||
- name: Cache Playwright Browsers
|
||||
- name: Download browser cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ms-playwright/
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
- name: Install browsers
|
||||
run: npm run playwright install --with-deps
|
||||
|
||||
- name: Build web
|
||||
run: npm run tronb:vite:dev
|
||||
|
||||
- name: Start Vector
|
||||
if: ${{ !contains(matrix.os, 'windows') }}
|
||||
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh
|
||||
@ -281,6 +386,9 @@ jobs:
|
||||
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
|
||||
OS_NAME: ${{ env.OS_NAME }}
|
||||
|
||||
- name: Build app
|
||||
run: npm run tronb:vite:dev
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
if: ${{ !cancelled() && (success() || failure()) }}
|
||||
continue-on-error: true
|
||||
@ -288,7 +396,7 @@ jobs:
|
||||
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
|
||||
path: test-results/
|
||||
|
||||
- name: Run playwright/electron flow (with retries)
|
||||
- name: npm run test:e2e:desktop
|
||||
id: retry
|
||||
if: ${{ !cancelled() && steps.deps-install.outcome == 'success' }}
|
||||
uses: nick-fields/retry@v3.0.2
|
||||
@ -304,6 +412,7 @@ jobs:
|
||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
CI_SUITE: e2e:desktop
|
||||
TARGET: desktop
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
99
.github/workflows/kcl-language-server.yml
vendored
99
.github/workflows/kcl-language-server.yml
vendored
@ -21,14 +21,11 @@ on:
|
||||
- '**.rs'
|
||||
- .github/workflows/kcl-language-server.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_NET_RETRY: 10
|
||||
@ -38,10 +35,9 @@ env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: vscode tests
|
||||
name: kcl-language-server (vscode tests)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -77,22 +73,20 @@ jobs:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
code-target:
|
||||
win32-x64
|
||||
#- os: windows-latest
|
||||
#target: i686-pc-windows-msvc
|
||||
#code-target:
|
||||
#win32-ia32
|
||||
#- os: windows-latest
|
||||
#target: aarch64-pc-windows-msvc
|
||||
#code-target: win32-arm64
|
||||
code-target: win32-x64
|
||||
#- os: windows-latest
|
||||
#target: i686-pc-windows-msvc
|
||||
#code-target:
|
||||
#win32-ia32
|
||||
#- os: windows-latest
|
||||
#target: aarch64-pc-windows-msvc
|
||||
#code-target: win32-arm64
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
code-target:
|
||||
linux-x64
|
||||
#- os: ubuntu-latest
|
||||
#target: aarch64-unknown-linux-musl
|
||||
#code-target: linux-arm64
|
||||
code-target: linux-x64
|
||||
#- os: ubuntu-latest
|
||||
#target: aarch64-unknown-linux-musl
|
||||
#code-target: linux-arm64
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
code-target: linux-arm64
|
||||
@ -105,41 +99,33 @@ jobs:
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
code-target: darwin-arm64
|
||||
|
||||
name: build-release (${{ matrix.target }})
|
||||
name: kcl-language-server build-release (${{ matrix.target }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ${{ matrix.container }}
|
||||
|
||||
env:
|
||||
RA_TARGET: ${{ matrix.target }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: ${{ env.FETCH_DEPTH }}
|
||||
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
rm rust/rust-toolchain.toml
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: rust
|
||||
components: rust-src
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Update apt repositories
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' || matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update
|
||||
|
||||
- if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
name: Install deps
|
||||
shell: bash
|
||||
@ -164,64 +150,53 @@ jobs:
|
||||
zlib1g-dev
|
||||
|
||||
cargo install cross
|
||||
|
||||
- name: Install AArch64 target toolchain
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: sudo apt-get install gcc-aarch64-linux-gnu
|
||||
|
||||
- name: Install ARM target toolchain
|
||||
if: matrix.target == 'arm-unknown-linux-gnueabihf'
|
||||
run: sudo apt-get install gcc-arm-linux-gnueabihf
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
cd rust
|
||||
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
# npm will symlink which will cause issues w tarballing later
|
||||
yarn install
|
||||
|
||||
- name: Package Extension (release)
|
||||
if: startsWith(github.event.ref, 'refs/tags/')
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
|
||||
|
||||
- name: Package Extension (nightly)
|
||||
if: startsWith(github.event.ref, 'refs/tags/') == false
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
|
||||
|
||||
- name: remove server
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu'
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
rm -rf server
|
||||
|
||||
- name: Package Extension (no server, release)
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/')
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix
|
||||
|
||||
- name: Package Extension (no server, nightly)
|
||||
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix --pre-release
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-${{ matrix.target }}
|
||||
path: ./rust/build
|
||||
|
||||
build-release-x86_64-unknown-linux-musl:
|
||||
name: build-release (x86_64-unknown-linux-musl)
|
||||
name: kcl-language-server build-release (x86_64-unknown-linux-musl)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RA_TARGET: x86_64-unknown-linux-musl
|
||||
@ -231,7 +206,6 @@ jobs:
|
||||
image: alpine:latest
|
||||
volumes:
|
||||
- /usr/local/cargo/registry:/usr/local/cargo/registry
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@ -245,55 +219,46 @@ jobs:
|
||||
nodejs \
|
||||
npm \
|
||||
yarn
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: ${{ env.FETCH_DEPTH }}
|
||||
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
rm rust/rust-toolchain.toml
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: rust
|
||||
components: rust-src
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
cd rust
|
||||
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
# npm will symlink which will cause issues w tarballing later
|
||||
yarn install
|
||||
|
||||
- name: Package Extension (release)
|
||||
if: startsWith(github.event.ref, 'refs/tags/')
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64
|
||||
|
||||
- name: Package Extension (release)
|
||||
if: startsWith(github.event.ref, 'refs/tags/') == false
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-x86_64-unknown-linux-musl
|
||||
path: ./rust/build
|
||||
|
||||
publish:
|
||||
name: publish
|
||||
name: kcl-language-server (publish)
|
||||
runs-on: ubuntu-latest
|
||||
needs: ["build-release", "build-release-x86_64-unknown-linux-musl"]
|
||||
if: startsWith(github.event.ref, 'refs/tags')
|
||||
@ -301,22 +266,17 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- run: 'echo "TAG: $TAG"'
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: ${{ env.FETCH_DEPTH }}
|
||||
|
||||
- name: Install Nodejs
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
||||
- run: 'echo "HEAD_SHA: $HEAD_SHA"'
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-aarch64-apple-darwin
|
||||
@ -344,33 +304,29 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-x86_64-pc-windows-msvc
|
||||
path:
|
||||
rust/build
|
||||
#- uses: actions/download-artifact@v4
|
||||
#with:
|
||||
#name: release-i686-pc-windows-msvc
|
||||
#path:
|
||||
#build
|
||||
#- uses: actions/download-artifact@v4
|
||||
#with:
|
||||
#name: release-aarch64-pc-windows-msvc
|
||||
#path: rust/build
|
||||
path: rust/build
|
||||
#- uses: actions/download-artifact@v4
|
||||
#with:
|
||||
#name: release-i686-pc-windows-msvc
|
||||
#path:
|
||||
#build
|
||||
#- uses: actions/download-artifact@v4
|
||||
#with:
|
||||
#name: release-aarch64-pc-windows-msvc
|
||||
#path: rust/build
|
||||
- run: ls -al ./rust/build
|
||||
|
||||
- name: Publish Release
|
||||
uses: ./.github/actions/github-release
|
||||
with:
|
||||
files: "rust/build/*"
|
||||
name: ${{ env.TAG }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: move files to dir for upload
|
||||
shell: bash
|
||||
run: |
|
||||
cd rust
|
||||
mkdir -p releases/language-server/${{ env.TAG }}
|
||||
cp -r build/* releases/language-server/${{ env.TAG }}
|
||||
|
||||
- name: "Authenticate to Google Cloud"
|
||||
uses: "google-github-actions/auth@v2.1.8"
|
||||
with:
|
||||
@ -385,15 +341,12 @@ jobs:
|
||||
with:
|
||||
path: rust/releases
|
||||
destination: dl.kittycad.io
|
||||
|
||||
- run: rm rust/build/kcl-language-server-no-server.vsix
|
||||
|
||||
- name: Publish Extension (Code Marketplace, release)
|
||||
# token from https://dev.azure.com/kcl-language-server/
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
npx vsce publish --pat ${{ secrets.VSCE_PAT }} --packagePath ../build/kcl-language-server-*.vsix
|
||||
|
||||
- name: Publish Extension (OpenVSX, release)
|
||||
run: |
|
||||
cd rust/kcl-language-server
|
||||
|
32
.github/workflows/kcl-python-bindings.yml
vendored
32
.github/workflows/kcl-python-bindings.yml
vendored
@ -4,7 +4,6 @@
|
||||
# maturin generate-ci github
|
||||
#
|
||||
name: kcl-python-bindings
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -27,16 +26,14 @@ on:
|
||||
- '**.rs'
|
||||
- .github/workflows/kcl-python-bindings.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux-x86_64:
|
||||
name: kcl-python-bindings (linux-x86_64)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -58,8 +55,8 @@ jobs:
|
||||
with:
|
||||
name: wheels-linux-x86_64
|
||||
path: rust/kcl-python-bindings/dist
|
||||
|
||||
windows:
|
||||
name: kcl-python-bindings (windows)
|
||||
runs-on: windows-16-cores
|
||||
strategy:
|
||||
matrix:
|
||||
@ -84,8 +81,8 @@ jobs:
|
||||
with:
|
||||
name: wheels-windows-${{ matrix.target }}
|
||||
path: rust/kcl-python-bindings/dist
|
||||
|
||||
macos:
|
||||
name: kcl-python-bindings (macos)
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
@ -110,8 +107,8 @@ jobs:
|
||||
with:
|
||||
name: wheels-macos-${{ matrix.target }}
|
||||
path: rust/kcl-python-bindings/dist
|
||||
|
||||
test:
|
||||
name: kcl-python-bindings (test)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -127,8 +124,8 @@ jobs:
|
||||
env:
|
||||
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
ZOO_HOST: https://api.dev.zoo.dev
|
||||
|
||||
sdist:
|
||||
name: kcl-python-bindings (sdist)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -136,10 +133,10 @@ jobs:
|
||||
uses: astral-sh/setup-uv@v5
|
||||
- name: Install codespell
|
||||
run: |
|
||||
uv venv .venv
|
||||
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
|
||||
echo "$PWD/.venv/bin" >> $GITHUB_PATH
|
||||
uv pip install pip --upgrade
|
||||
uv venv .venv
|
||||
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
|
||||
echo "$PWD/.venv/bin" >> $GITHUB_PATH
|
||||
uv pip install pip --upgrade
|
||||
- name: Build sdist
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
@ -151,7 +148,6 @@ jobs:
|
||||
with:
|
||||
name: wheels-sdist
|
||||
path: rust/kcl-python-bindings/dist
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
@ -168,11 +164,11 @@ jobs:
|
||||
uses: astral-sh/setup-uv@v5
|
||||
- name: do uv things
|
||||
run: |
|
||||
cd rust/kcl-python-bindings
|
||||
uv venv .venv
|
||||
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
|
||||
echo "$PWD/.venv/bin" >> $GITHUB_PATH
|
||||
uv pip install pip --upgrade
|
||||
cd rust/kcl-python-bindings
|
||||
uv venv .venv
|
||||
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
|
||||
echo "$PWD/.venv/bin" >> $GITHUB_PATH
|
||||
uv pip install pip --upgrade
|
||||
- name: Publish to PyPI
|
||||
uses: PyO3/maturin-action@v1
|
||||
env:
|
||||
|
167
.github/workflows/static-analysis.yml
vendored
167
.github/workflows/static-analysis.yml
vendored
@ -28,53 +28,7 @@ jobs:
|
||||
- run: npm run fmt:check
|
||||
|
||||
npm-build-wasm:
|
||||
# Build the wasm blob once on the fastest runner.
|
||||
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false # Configured below.
|
||||
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './rust'
|
||||
|
||||
- name: Build Wasm
|
||||
shell: bash
|
||||
run: npm run build:wasm
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prepared-wasm
|
||||
path: |
|
||||
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prepared-ts-rs-bindings
|
||||
path: |
|
||||
rust/kcl-lib/bindings/*
|
||||
uses: ./.github/workflows/build-wasm.yml
|
||||
|
||||
npm-tsc:
|
||||
runs-on: ubuntu-latest
|
||||
@ -173,122 +127,3 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Run codespell
|
||||
uses: crate-ci/typos@v1.32.0
|
||||
|
||||
npm-unit-test-kcl-samples:
|
||||
runs-on: ubuntu-latest
|
||||
needs: npm-build-wasm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm install
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Copy prepared wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
mkdir rust/kcl-wasm-lib/pkg
|
||||
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Copy prepared ts-rs bindings
|
||||
run: |
|
||||
ls -R prepared-ts-rs-bindings
|
||||
mkdir rust/kcl-lib/bindings
|
||||
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
|
||||
|
||||
- run: npm run simpleserver:bg
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
|
||||
- name: Install Chromium Browser
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: npm run playwright install chromium --with-deps
|
||||
|
||||
- name: Download internal KCL samples
|
||||
run: git clone --depth=1 https://x-access-token:${{ secrets.GH_PAT_KCL_SAMPLES_INTERNAL }}@github.com/KittyCAD/kcl-samples-internal public/kcl-samples/internal
|
||||
|
||||
- name: Regenerate KCL samples manifest
|
||||
run: cd rust/kcl-lib && EXPECTORATE=overwrite cargo test generate_manifest
|
||||
|
||||
- name: Check public and internal KCL samples
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: npm run test:unit:kcl-samples
|
||||
env:
|
||||
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
|
||||
npm-unit-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: npm-build-wasm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm install
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Copy prepared wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
mkdir rust/kcl-wasm-lib/pkg
|
||||
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Copy prepared ts-rs bindings
|
||||
run: |
|
||||
ls -R prepared-ts-rs-bindings
|
||||
mkdir rust/kcl-lib/bindings
|
||||
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
|
||||
|
||||
- run: npm run simpleserver:bg
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
|
||||
- name: Install Chromium Browser
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: npm run playwright install chromium --with-deps
|
||||
|
||||
- name: Run unit tests
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: xvfb-run -a npm run test:unit
|
||||
env:
|
||||
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
|
||||
- name: Check for changes
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
id: git-check
|
||||
run: |
|
||||
git add src/lang/std/artifactMapGraphs
|
||||
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
|
||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Commit changes, if any
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
||||
git fetch origin
|
||||
echo ${{ github.head_ref }}
|
||||
git checkout ${{ github.head_ref }}
|
||||
# TODO when webkit works on ubuntu remove the os part of the commit message
|
||||
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
|
||||
git push
|
||||
git push origin ${{ github.head_ref }}
|
||||
|
124
.github/workflows/unit-tests.yml
vendored
Normal file
124
.github/workflows/unit-tests.yml
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
name: Unit Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
npm-build-wasm:
|
||||
uses: ./.github/workflows/build-wasm.yml
|
||||
|
||||
npm-test-unit:
|
||||
runs-on: ubuntu-latest
|
||||
needs: npm-build-wasm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm install
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Copy prepared wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
mkdir rust/kcl-wasm-lib/pkg
|
||||
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Copy prepared ts-rs bindings
|
||||
run: |
|
||||
ls -R prepared-ts-rs-bindings
|
||||
mkdir rust/kcl-lib/bindings
|
||||
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
|
||||
|
||||
- run: npm run simpleserver:bg
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
|
||||
- name: Install Chromium Browser
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: npm run playwright install chromium --with-deps
|
||||
|
||||
- name: Run unit tests
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: xvfb-run -a npm run test:unit
|
||||
env:
|
||||
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
|
||||
- name: Check for changes
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
id: git-check
|
||||
run: |
|
||||
git add src/lang/std/artifactMapGraphs
|
||||
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
|
||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Commit changes, if any
|
||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
||||
git fetch origin
|
||||
echo ${{ github.head_ref }}
|
||||
git checkout ${{ github.head_ref }}
|
||||
# TODO when webkit works on ubuntu remove the os part of the commit message
|
||||
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
|
||||
git push
|
||||
git push origin ${{ github.head_ref }}
|
||||
|
||||
npm-test-unit-components:
|
||||
runs-on: ubuntu-latest
|
||||
needs: npm-build-wasm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm install
|
||||
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Copy prepared wasm
|
||||
run: |
|
||||
ls -R prepared-wasm
|
||||
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
|
||||
mkdir rust/kcl-wasm-lib/pkg
|
||||
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Copy prepared ts-rs bindings
|
||||
run: |
|
||||
ls -R prepared-ts-rs-bindings
|
||||
mkdir rust/kcl-lib/bindings
|
||||
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
|
||||
|
||||
- name: Run component tests
|
||||
run: npm run test:unit:components
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -58,6 +58,8 @@ trace.zip
|
||||
/public/kcl-samples/.github
|
||||
/public/kcl-samples/screenshots/main.kcl
|
||||
/public/kcl-samples/step/main.kcl
|
||||
/public/kcl-samples/internal
|
||||
/rust/kcl-lib/tests/kcl_samples/internal
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
|
@ -122,33 +122,29 @@ https://github.com/KittyCAD/modeling-app/issues/new
|
||||
|
||||
#### 2. Push a new tag
|
||||
|
||||
Create a new tag and push it to the repo. The `semantic-release.sh` script will automatically bump the minor part, which we use the most. For instance going from `v0.27.0` to `v0.28.0`.
|
||||
Decide on a `v`-prefixed semver `VERSION` (e.g. `v1.2.3`) with the team and tag the repo on the latest main:
|
||||
|
||||
```
|
||||
VERSION=$(./scripts/semantic-release.sh)
|
||||
git tag $VERSION
|
||||
git push origin --tags
|
||||
git tag $VERSION --message=""
|
||||
git push origin $VERSION
|
||||
```
|
||||
|
||||
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
|
||||
This will trigger the `build-apps` workflow to set the version, build & sign the apps, and generate release files.
|
||||
|
||||
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush)).
|
||||
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush).
|
||||
|
||||
#### 3. Manually test artifacts
|
||||
|
||||
##### Release builds
|
||||
|
||||
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in 2.).
|
||||
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in step 2).
|
||||
|
||||
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
|
||||
Manually test against [this list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
|
||||
|
||||
##### Updater-test builds
|
||||
|
||||
The other `build-apps` output in the release `build-apps` workflow (triggered by 2.) is `updater-test-{arch}-{platform}`. It's a semi-automated process: for macOS, Windows, and Linux, download the corresponding updater-test artifact file, install the app, run it, expect an updater prompt to a dummy v0.255.255, install it and check that the app comes back at that version.
|
||||
|
||||
The only difference with these builds is that they point to a different update location on the release bucket, with this dummy v0.255.255 always available. This helps ensuring that the version we release will be able to update to the next one available.
|
||||
|
||||
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing (or the updater-test location in the storage bucket).
|
||||
A prompt should show up asking for a downgrade to the last release version. Running through that at the end of testing
|
||||
and making sure the current release candidate has the ability to be updated to what electron-updater points to is critical,
|
||||
but what is actually being downloaded and installed isn't.
|
||||
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing.
|
||||
|
||||
```
|
||||
# Windows (PowerShell)
|
||||
@ -161,15 +157,20 @@ If the prompt doesn't show up, start the app in command line to grab the electro
|
||||
./Zoo Design Studio-{version}-{arch}-linux.AppImage
|
||||
```
|
||||
|
||||
#### 4. Publish the release
|
||||
#### 4. Bump the KCL version
|
||||
|
||||
Head over to https://github.com/KittyCAD/modeling-app/releases/new, pick the newly created tag and type it in the _Release title_ field as well.
|
||||
Follow the instructions [here](./rust/README.md) to publish new crates.
|
||||
This ensures that the KCL accepted by the app is also accepted by the CLI.
|
||||
|
||||
Hit _Generate release notes_ as a starting point to discuss the changelog in the issue. Once done, make sure _Set as the latest release_ is checked, and hit _Publish release_.
|
||||
#### 5. Publish the release
|
||||
|
||||
A new `publish-apps-release` will kick in and you should be able to find it [here](https://github.com/KittyCAD/modeling-app/actions?query=event%3Arelease). On success, the files will be uploaded to the public bucket as well as to the GitHub release, and the announcement on Discord will be sent.
|
||||
Head over to https://github.com/KittyCAD/modeling-app/releases/new, pick the newly created tag and type it in the **Release title** field as well.
|
||||
|
||||
#### 5. Close the issue
|
||||
Click **Generate release notes** as a starting point to discuss the changelog in the issue. Once done, make sure **Set as the latest release** is checked, and click **Publish release**.
|
||||
|
||||
A new `publish-apps-release` workflow will start and you should be able to find it [here](https://github.com/KittyCAD/modeling-app/actions?query=event%3Arelease). On success, the files will be uploaded to the public bucket as well as to the GitHub release, and the announcement on Discord will be sent.
|
||||
|
||||
#### 6. Close the issue
|
||||
|
||||
If everything is well and the release is out to the public, the issue tracking the release shall be closed.
|
||||
|
||||
@ -204,7 +205,7 @@ Prepare these system dependencies:
|
||||
|
||||
#### Snapshot tests (Google Chrome on Ubuntu only)
|
||||
|
||||
Only Ubunu and Google Chrome is supported for the set of tests evaluating screenshot snapshots.
|
||||
Only Ubuntu 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.
|
||||
```
|
||||
npm run playwright -- install chrome
|
||||
@ -212,14 +213,21 @@ npm run test:snapshots
|
||||
```
|
||||
You may use `-- --update-snapshots` as needed.
|
||||
|
||||
#### Electron flow tests (Chromium on Ubuntu, macOS, Windows)
|
||||
#### Desktop tests (Electron on all platforms)
|
||||
|
||||
```
|
||||
npm run playwright -- install chromium
|
||||
npm run test:playwright:electron:local
|
||||
npm run test:e2e:desktop:local
|
||||
```
|
||||
|
||||
You may use `-- -g "my test"` to match specific test titles, or `-- path/to/file.spec.ts` for a test file.
|
||||
|
||||
#### Web tests (Google Chrome on all platforms)
|
||||
|
||||
```
|
||||
npm run test:e2e:web
|
||||
```
|
||||
|
||||
#### 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.
|
||||
|
10
INSTALL.md
10
INSTALL.md
@ -4,7 +4,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
|
||||
|
||||
## Windows
|
||||
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Windows and for your processor type.
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Windows and for your processor type.
|
||||
|
||||
2. Once downloaded, run the installer `Zoo Design Studio-{version}-{arch}-win.exe` which should take a few seconds.
|
||||
|
||||
@ -12,16 +12,16 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
|
||||
|
||||
## macOS
|
||||
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for macOS and for your processor type.
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for macOS and for your processor type.
|
||||
|
||||
2. Once downloaded, open the disk image `Zoo Design Studio-{version}-{arch}-mac.dmg` and drag the applications to your `Applications` directory.
|
||||
|
||||
3. You can then open your `Applications` directory and double-click on `Zoo Design Studio` to open.
|
||||
|
||||
|
||||
## Linux
|
||||
## Linux
|
||||
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Linux and for your processor type.
|
||||
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Linux and for your processor type.
|
||||
|
||||
2. Install the dependencies needed to run the [AppImage format](https://appimage.org/).
|
||||
- On Ubuntu, install the FUSE library with these commands in a terminal.
|
||||
@ -29,7 +29,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
|
||||
sudo apt update
|
||||
sudo apt install libfuse2
|
||||
```
|
||||
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
|
||||
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
|
||||
- Once installed, copy the downloaded `Zoo Design Studio-{version}-{arch}-linux.AppImage` to the directory of your choice, for instance `~/Applications`.
|
||||
|
||||
- `appimaged` should automatically find it and make it executable. If not, run:
|
||||
|
10
Makefile
10
Makefile
@ -114,26 +114,24 @@ test-unit: install ## Run the unit tests
|
||||
npm run test:unit:components
|
||||
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
|
||||
npm run test:unit
|
||||
npm run test:unit:kcl-samples
|
||||
|
||||
.PHONY: test-e2e
|
||||
test-e2e: test-e2e-$(TARGET)
|
||||
|
||||
.PHONY: test-e2e-web
|
||||
test-e2e-web: install build ## Run the web e2e tests
|
||||
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
|
||||
ifdef E2E_GREP
|
||||
npm run chrome:test -- --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
|
||||
npm run test:e2e:web -- --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
|
||||
else
|
||||
npm run chrome:test -- --headed --workers='100%'
|
||||
npm run test:e2e:web -- --headed --workers='100%'
|
||||
endif
|
||||
|
||||
.PHONY: test-e2e-desktop
|
||||
test-e2e-desktop: install build ## Run the desktop e2e tests
|
||||
ifdef E2E_GREP
|
||||
npm run test:playwright:electron -- --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
|
||||
npm run test:e2e:desktop -- --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
|
||||
else
|
||||
npm run test:playwright:electron -- --workers='100%'
|
||||
npm run test:e2e:desktop -- --workers='100%'
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
|
12
README.md
12
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
# Zoo Design Studio
|
||||
|
||||
[zoo.dev/modeling-app](https://zoo.dev/modeling-app)
|
||||
[zoo.dev/design-studio](https://zoo.dev/design-studio)
|
||||
|
||||
A CAD application from the future, brought to you by the [Zoo team](https://zoo.dev).
|
||||
|
||||
@ -40,14 +40,8 @@ The 3D view in Design Studio is just a video stream from our hosted geometry eng
|
||||
|
||||
## Get Started
|
||||
|
||||
We recommend downloading the latest application binary from our [releases](https://github.com/KittyCAD/modeling-app/releases) page. If you don't see your platform or architecture supported there, please file an issue.
|
||||
|
||||
If you'd like to try out upcoming changes sooner, you can also download those from our [nightly releases](https://zoo.dev/modeling-app/download/nightly) page.
|
||||
We recommend downloading the latest application binary from our [website](https://zoo.dev/design-studio/download). If you don't see your platform or architecture supported there, please file an issue. See the [installation guide](INSTALL.md) for additional instructions.
|
||||
|
||||
## Developing
|
||||
|
||||
Finally, if you'd like to run a development build or contribute to the project, please visit our [contributor guide](CONTRIBUTING.md) to get started.
|
||||
|
||||
## KCL
|
||||
|
||||
To contribute to the KittyCAD Language, see the [README](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib) for KCL.
|
||||
Finally, if you'd like to run a development build or contribute to the project, please visit our [contributor guide](CONTRIBUTING.md) to get started. To contribute to the KittyCAD Language, see the dedicated [readme](rust/kcl-lib/README.md) for KCL.
|
||||
|
@ -21,7 +21,7 @@ extend-exclude = [
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
metalness = "metalness" # appearance API
|
||||
metalness = "metalness" # appearance API
|
||||
Hom = "Hom" # short for homogenous
|
||||
typ = "typ" # used to declare a variable named 'type' which is a reserved keyword in Rust
|
||||
ue = "ue" # short for UnaryExpression
|
||||
@ -29,6 +29,7 @@ THRE = "THRE" # Weird bug that wrongly detects THREEjs as a typo
|
||||
nwo = "nwo" # don't know what this is about tbh
|
||||
"ot" = "ot" # some abbreviation, idk what
|
||||
"oe" = "oe" # some abbreviation, idk what
|
||||
"colinear" = "colinear" # some engine shit, kidding
|
||||
|
||||
[default]
|
||||
extend-ignore-identifiers-re = [
|
||||
|
@ -16,15 +16,16 @@ There are some useful functions for working with arrays in the standard library,
|
||||
|
||||
Arrays have their own types: `[T]` where `T` is the type of the elements of the array, for example, `[string]` means an array of `string`s and `[any]` means an array of any values.
|
||||
|
||||
Array types can also include length information: `[T; n]` denotes an array of length `n` (where `n` is a number literal) and `[T; 1+]` denotes an array whose length is at least one (i.e., a non-empty array). E.g., `[string; 1+]` and `[number(mm); 3]` are valid array types.
|
||||
Array types can also include length information: `[T; n]` denotes an array of length `n` (where `n` is a number literal) and `[T; n+]` denotes an array whose length is at least `n`. The common case for that is `[T; 1+]`, i.e., a non-empty array. E.g., `[string; 1+]` and `[number(mm); 3]` are valid array types.
|
||||
|
||||
## Ranges
|
||||
|
||||
Ranges are a succinct way to create an array of sequential numbers. The syntax is `[start .. end]` where `start` and `end` evaluate to whole numbers (integers). Ranges are inclusive of the start and end. The end must be greater than the start. Examples:
|
||||
Ranges are a succinct way to create an array of sequential numbers. The syntax is `[start .. end]` where `start` and `end` evaluate to whole numbers (integers). Ranges are inclusive of the start and end. The end must be greater than the start. A range which is exclusive of its end is written with `<end`. Examples:
|
||||
|
||||
```kcl,norun
|
||||
[0..3] // [0, 1, 2, 3]
|
||||
[3..10] // [3, 4, 5, 6, 7, 8, 9, 10]
|
||||
[3..<10] // [3, 4, 5, 6, 7, 8, 9]
|
||||
x = 2
|
||||
[x..x+1] // [2, 3]
|
||||
```
|
||||
|
@ -4,7 +4,7 @@ excerpt: "Documentation of the KCL language for the Zoo Design Studio."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
This is a reference for KCL. If you are learning KCL, you may prefer the [guide]() which explains
|
||||
This is a reference for KCL. If you are learning KCL, you may prefer the [guide](https://zoo.dev/docs/kcl-book/intro.html) which explains
|
||||
things in a more tutorial fashion. See also our documentation of the [standard library](/docs/kcl-std).
|
||||
|
||||
## Topics
|
||||
|
@ -27,9 +27,6 @@ import increment from "util.kcl"
|
||||
answer = increment(41)
|
||||
```
|
||||
|
||||
Imported files _must_ be in the same project so that units are uniform across
|
||||
modules. This means that it must be in the same directory.
|
||||
|
||||
Import statements must be at the top-level of a file. It is not allowed to have
|
||||
an `import` statement inside a function or in the body of an if‑else.
|
||||
|
||||
@ -58,6 +55,9 @@ Imported symbols can be renamed for convenience or to avoid name collisions.
|
||||
import increment as inc, decrement as dec from "util.kcl"
|
||||
```
|
||||
|
||||
You can import files from the current directory or from subdirectories, but if importing from a
|
||||
subdirectory you can only import `main.kcl`.
|
||||
|
||||
---
|
||||
|
||||
## Functions vs `clone`
|
||||
@ -177,7 +177,7 @@ You can also import the whole module. This is useful if you want to use the
|
||||
result of a module as a variable, like a part.
|
||||
|
||||
```norun
|
||||
import "tests/inputs/cube.kcl" as cube
|
||||
import "cube.kcl"
|
||||
cube
|
||||
|> translate(x=10)
|
||||
```
|
||||
@ -229,6 +229,19 @@ The final statement is what's important because it's the return value of the
|
||||
entire module. The module is expected to return a single object that can be used
|
||||
as a variable by the file that imports it.
|
||||
|
||||
The name of the file or subdirectory is used as the name of the variable within the importing program.
|
||||
If you want to use a different name, you can do so by using the `as` keyword:
|
||||
|
||||
```kcl,norun
|
||||
import "cube.kcl" // Introduces a new variable called `cube`.
|
||||
import "cube.kcl" as block // Introduces a new variable called `block`.
|
||||
import "cube/main.kcl" // Introduces a new variable called `cube`.
|
||||
import "cube/main.kcl" as block // Introduces a new variable called `block`.
|
||||
```
|
||||
|
||||
If the filename includes hyphens (`-`) or starts with an underscore (`_`), then you must specify a
|
||||
variable name.
|
||||
|
||||
---
|
||||
|
||||
## Multiple instances of the same import
|
||||
@ -241,7 +254,7 @@ If you want to have multiple instances of the same object, you can use the
|
||||
[`clone`](/docs/kcl/clone) function. This will render a new instance of the object in memory.
|
||||
|
||||
```norun
|
||||
import cube from "tests/inputs/cube.kcl"
|
||||
import cube from "cube.kcl"
|
||||
|
||||
cube
|
||||
|> translate(x=10)
|
||||
@ -257,7 +270,7 @@ separate objects in memory, and can be manipulated independently.
|
||||
Here is an example with a file from another CAD system:
|
||||
|
||||
```kcl
|
||||
import "tests/inputs/cube.step" as cube
|
||||
import "tests/inputs/cube.step"
|
||||
|
||||
cube
|
||||
|> translate(x=10)
|
||||
|
@ -13,6 +13,7 @@ arc(
|
||||
angleStart?: number,
|
||||
angleEnd?: number,
|
||||
radius?: number,
|
||||
diameter?: number,
|
||||
interiorAbsolute?: Point2d,
|
||||
endAbsolute?: Point2d,
|
||||
tag?: TagDeclarator,
|
||||
@ -30,7 +31,8 @@ Unless this makes a lot of sense and feels like what you're looking for to const
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | Which sketch should this path be added to? | Yes |
|
||||
| `angleStart` | [`number`](/docs/kcl-std/types/std-types-number) | Where along the circle should this arc start? | No |
|
||||
| `angleEnd` | [`number`](/docs/kcl-std/types/std-types-number) | Where along the circle should this arc end? | No |
|
||||
| `radius` | [`number`](/docs/kcl-std/types/std-types-number) | How large should the circle be? | No |
|
||||
| `radius` | [`number`](/docs/kcl-std/types/std-types-number) | How large should the circle be? Incompatible with `diameter`. | No |
|
||||
| `diameter` | [`number`](/docs/kcl-std/types/std-types-number) | How large should the circle be? Incompatible with `radius`. | No |
|
||||
| `interiorAbsolute` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | Any point between the arc's start and end? Requires `endAbsolute`. Incompatible with `angleStart` or `angleEnd` | No |
|
||||
| `endAbsolute` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | Where should this arc end? Requires `interiorAbsolute`. Incompatible with `angleStart` or `angleEnd` | No |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | Create a new tag which refers to this line | No |
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -14,7 +14,7 @@ close(
|
||||
): Sketch
|
||||
```
|
||||
|
||||
|
||||
If you want to perform some 3-dimensional operation on a sketch, like extrude or sweep, you must `close` it first. `close` must be called even if the end point of the last segment is coincident with the sketch starting point.
|
||||
|
||||
### Arguments
|
||||
|
||||
|
16
docs/kcl-std/consts/std-sweep-SKETCH_PLANE.md
Normal file
16
docs/kcl-std/consts/std-sweep-SKETCH_PLANE.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "sweep::SKETCH_PLANE"
|
||||
subtitle: "Constant in std::sweep"
|
||||
excerpt: "Local/relative to a position centered within the plane being sketched on"
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Local/relative to a position centered within the plane being sketched on
|
||||
|
||||
```kcl
|
||||
sweep::SKETCH_PLANE: string = 'sketchPlane'
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
16
docs/kcl-std/consts/std-sweep-TRAJECTORY.md
Normal file
16
docs/kcl-std/consts/std-sweep-TRAJECTORY.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "sweep::TRAJECTORY"
|
||||
subtitle: "Constant in std::sweep"
|
||||
excerpt: "Local/relative to the trajectory curve"
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Local/relative to the trajectory curve
|
||||
|
||||
```kcl
|
||||
sweep::TRAJECTORY: string = 'trajectoryCurve'
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
127
docs/kcl-std/functions/std-appearance-hexString.md
Normal file
127
docs/kcl-std/functions/std-appearance-hexString.md
Normal file
File diff suppressed because one or more lines are too long
64
docs/kcl-std/functions/std-appearance-rgb.md
Normal file
64
docs/kcl-std/functions/std-appearance-rgb.md
Normal file
File diff suppressed because one or more lines are too long
@ -12,7 +12,7 @@ reduce(
|
||||
@array: [any],
|
||||
initial: any,
|
||||
f: fn(any, accum: any): any,
|
||||
): [any]
|
||||
): any
|
||||
```
|
||||
|
||||
Take a starting value. Then, for each element of an array, calculate the next value,
|
||||
@ -28,7 +28,7 @@ using the previous value and the element.
|
||||
|
||||
### Returns
|
||||
|
||||
[`[any]`](/docs/kcl-std/types/std-types-any)
|
||||
[`any`](/docs/kcl-std/types/std-types-any)
|
||||
|
||||
|
||||
### Examples
|
||||
|
50
docs/kcl-std/functions/std-assert.md
Normal file
50
docs/kcl-std/functions/std-assert.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
title: "assert"
|
||||
subtitle: "Function in std"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
```kcl
|
||||
assert(
|
||||
@actual: number,
|
||||
isGreaterThan?: number,
|
||||
isLessThan?: number,
|
||||
isGreaterThanOrEqual?: number,
|
||||
isLessThanOrEqual?: number,
|
||||
isEqualTo?: number,
|
||||
tolerance?: number,
|
||||
error?: string,
|
||||
)
|
||||
```
|
||||
|
||||
Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met.
|
||||
If you provide multiple conditions, they will all be checked and all must be met.
|
||||
|
||||
### Arguments
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `actual` | [`number`](/docs/kcl-std/types/std-types-number) | Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. | Yes |
|
||||
| `isGreaterThan` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is greater than this. | No |
|
||||
| `isLessThan` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than this. | No |
|
||||
| `isGreaterThanOrEqual` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is greater than or equal to this. | No |
|
||||
| `isLessThanOrEqual` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than or equal to this. | No |
|
||||
| `isEqualTo` | [`number`](/docs/kcl-std/types/std-types-number) | Comparison argument. If given, checks the `actual` value is less than or equal to this. | No |
|
||||
| `tolerance` | [`number`](/docs/kcl-std/types/std-types-number) | If `isEqualTo` is used, this is the tolerance to allow for the comparison. This tolerance is used because KCL's number system has some floating-point imprecision when used with very large decimal places. | No |
|
||||
| `error` | [`string`](/docs/kcl-std/types/std-types-string) | If the value was false, the program will terminate with this error message | No |
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
```kcl
|
||||
n = 10
|
||||
assert(n, isEqualTo = 10)
|
||||
assert(n, isGreaterThanOrEqual = 0, isLessThan = 100, error = "number should be between 0 and 100")
|
||||
assert(1.0000000000012, isEqualTo = 1, tolerance = 0.0001, error = "number should be almost exactly 1")
|
||||
```
|
||||
|
||||
|
||||
|
35
docs/kcl-std/functions/std-assertIs.md
Normal file
35
docs/kcl-std/functions/std-assertIs.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "assertIs"
|
||||
subtitle: "Function in std"
|
||||
excerpt: "Asserts that a value is the boolean value true."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Asserts that a value is the boolean value true.
|
||||
|
||||
```kcl
|
||||
assertIs(
|
||||
@actual: bool,
|
||||
error?: string,
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Arguments
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `actual` | [`bool`](/docs/kcl-std/types/std-types-bool) | Value to check. If this is the boolean value true, assert passes. Otherwise it fails.. | Yes |
|
||||
| `error` | [`string`](/docs/kcl-std/types/std-types-string) | If the value was false, the program will terminate with this error message | No |
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
```kcl
|
||||
kclIsFun = true
|
||||
assertIs(kclIsFun)
|
||||
```
|
||||
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@ Compute the length of the given leg.
|
||||
legLen(
|
||||
hypotenuse: number(Length),
|
||||
leg: number(Length),
|
||||
): number(deg)
|
||||
): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ legLen(
|
||||
|
||||
### Returns
|
||||
|
||||
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
||||
|
@ -9,9 +9,10 @@ layout: manual
|
||||
|
||||
```kcl
|
||||
circle(
|
||||
@sketch_or_surface: Sketch | Plane | Face,
|
||||
@sketchOrSurface: Sketch | Plane | Face,
|
||||
center: Point2d,
|
||||
radius: number(Length),
|
||||
radius?: number(Length),
|
||||
diameter?: number(Length),
|
||||
tag?: tag,
|
||||
): Sketch
|
||||
```
|
||||
@ -23,9 +24,10 @@ the provided (x, y) origin point.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketch_or_surface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
|
||||
| `sketchOrSurface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
|
||||
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center of the circle. | Yes |
|
||||
| `radius` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The radius of the circle. | Yes |
|
||||
| `radius` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The radius of the circle. Incompatible with `diameter`. | No |
|
||||
| `diameter` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The diameter of the circle. Incompatible with `radius`. | No |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | Create a new tag which refers to this circle. | No |
|
||||
|
||||
### Returns
|
||||
@ -51,7 +53,7 @@ exampleSketch = startSketchOn(XZ)
|
||||
|> line(end = [0, 30])
|
||||
|> line(end = [-30, 0])
|
||||
|> close()
|
||||
|> subtract2d(tool = circle(center = [0, 15], radius = 5))
|
||||
|> subtract2d(tool = circle(center = [0, 15], diameter = 10))
|
||||
|
||||
example = extrude(exampleSketch, length = 5)
|
||||
```
|
||||
|
@ -9,11 +9,11 @@ Construct a circle derived from 3 points.
|
||||
|
||||
```kcl
|
||||
circleThreePoint(
|
||||
@sketchSurfaceOrGroup: Sketch | Plane | Face,
|
||||
@sketchOrSurface: Sketch | Plane | Face,
|
||||
p1: Point2d,
|
||||
p2: Point2d,
|
||||
p3: Point2d,
|
||||
tag?: TagDeclarator,
|
||||
tag?: tag,
|
||||
): Sketch
|
||||
```
|
||||
|
||||
@ -23,11 +23,11 @@ circleThreePoint(
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketchSurfaceOrGroup` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Plane or surface to sketch on. | Yes |
|
||||
| `sketchOrSurface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Plane or surface to sketch on. | Yes |
|
||||
| `p1` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | 1st point to derive the circle. | Yes |
|
||||
| `p2` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | 2nd point to derive the circle. | Yes |
|
||||
| `p3` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | 3rd point to derive the circle. | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | Identifier for the circle to reference elsewhere. | No |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | Identifier for the circle to reference elsewhere. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -38,7 +38,7 @@ circleThreePoint(
|
||||
|
||||
```kcl
|
||||
exampleSketch = startSketchOn(XY)
|
||||
|> circleThreePoint(p1 = [10, 10], p2 = [20, 8], p3 = [15, 5])
|
||||
|> circleThreePoint(p1 = [10,10], p2 = [20,8], p3 = [15,5])
|
||||
|> extrude(length = 5)
|
||||
```
|
||||
|
@ -1,39 +1,43 @@
|
||||
---
|
||||
title: "extrude"
|
||||
subtitle: "Function in std::sketch"
|
||||
excerpt: "Extend a 2-dimensional sketch through a third dimension in order to create new 3-dimensional volume, or if extruded into an existing volume, cut into an existing solid."
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Extend a 2-dimensional sketch through a third dimension in order to create new 3-dimensional volume, or if extruded into an existing volume, cut into an existing solid.
|
||||
|
||||
|
||||
```kcl
|
||||
extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
@sketches: [Sketch; 1+],
|
||||
length: number(Length),
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagDeclarator,
|
||||
tagEnd?: TagDeclarator,
|
||||
): [Solid]
|
||||
bidirectionalLength?: number(Length),
|
||||
tagStart?: tag,
|
||||
tagEnd?: tag,
|
||||
): [Solid; 1+]
|
||||
```
|
||||
|
||||
You can provide more than one sketch to extrude, and they will all be extruded in the same direction.
|
||||
Extend a 2-dimensional sketch through a third dimension in order to
|
||||
create new 3-dimensional volume, or if extruded into an existing volume,cut into an existing solid.
|
||||
|
||||
You can provide more than one sketch to extrude, and they will all be
|
||||
extruded in the same direction.
|
||||
|
||||
### Arguments
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketches` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | Which sketch or sketches should be extruded | Yes |
|
||||
| `length` | [`number`](/docs/kcl-std/types/std-types-number) | How far to extrude the given sketches | Yes |
|
||||
| `sketches` | [`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch) | Which sketch or sketches should be extruded. | Yes |
|
||||
| `length` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | How far to extrude the given sketches. | Yes |
|
||||
| `symmetric` | [`bool`](/docs/kcl-std/types/std-types-bool) | If true, the extrusion will happen symmetrically around the sketch. Otherwise, the extrusion will happen on only one side of the sketch. | No |
|
||||
| `bidirectionalLength` | [`number`](/docs/kcl-std/types/std-types-number) | If specified, will also extrude in the opposite direction to 'distance' to the specified distance. If 'symmetric' is true, this value is ignored. | No |
|
||||
| `tagStart` | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | A named tag for the face at the start of the extrusion, i.e. the original sketch | No |
|
||||
| `tagEnd` | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch | No |
|
||||
| `bidirectionalLength` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | If specified, will also extrude in the opposite direction to 'distance' to the specified distance. If 'symmetric' is true, this value is ignored. | No |
|
||||
| `tagStart` | [`tag`](/docs/kcl-std/types/std-types-tag) | A named tag for the face at the start of the extrusion, i.e. the original sketch. | No |
|
||||
| `tagEnd` | [`tag`](/docs/kcl-std/types/std-types-tag) | A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
[`[Solid]`](/docs/kcl-std/types/std-types-Solid)
|
||||
[`[Solid; 1+]`](/docs/kcl-std/types/std-types-Solid)
|
||||
|
||||
|
||||
### Examples
|
||||
@ -42,10 +46,18 @@ You can provide more than one sketch to extrude, and they will all be extruded i
|
||||
example = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [10, 0])
|
||||
|> arc(angleStart = 120, angleEnd = 0, radius = 5)
|
||||
|> arc(
|
||||
angleStart = 120,
|
||||
angleEnd = 0,
|
||||
radius = 5,
|
||||
)
|
||||
|> line(end = [5, 0])
|
||||
|> line(end = [0, 10])
|
||||
|> bezierCurve(control1 = [-10, 0], control2 = [2, 10], end = [-5, 10])
|
||||
|> bezierCurve(
|
||||
control1 = [-10, 0],
|
||||
control2 = [2, 10],
|
||||
end = [-5, 10],
|
||||
)
|
||||
|> line(end = [-5, -2])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
@ -56,10 +68,18 @@ example = startSketchOn(XZ)
|
||||
```kcl
|
||||
exampleSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [-10, 0])
|
||||
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|
||||
|> arc(
|
||||
angleStart = 120,
|
||||
angleEnd = -60,
|
||||
radius = 5,
|
||||
)
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [5, 0])
|
||||
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])
|
||||
|> bezierCurve(
|
||||
control1 = [-3, 0],
|
||||
control2 = [2, 10],
|
||||
end = [-5, 10],
|
||||
)
|
||||
|> line(end = [-4, 10])
|
||||
|> line(end = [-5, -2])
|
||||
|> close()
|
||||
@ -72,10 +92,18 @@ example = extrude(exampleSketch, length = 10)
|
||||
```kcl
|
||||
exampleSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [-10, 0])
|
||||
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|
||||
|> arc(
|
||||
angleStart = 120,
|
||||
angleEnd = -60,
|
||||
radius = 5,
|
||||
)
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [5, 0])
|
||||
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])
|
||||
|> bezierCurve(
|
||||
control1 = [-3, 0],
|
||||
control2 = [2, 10],
|
||||
end = [-5, 10],
|
||||
)
|
||||
|> line(end = [-4, 10])
|
||||
|> line(end = [-5, -2])
|
||||
|> close()
|
||||
@ -88,10 +116,18 @@ example = extrude(exampleSketch, length = 20, symmetric = true)
|
||||
```kcl
|
||||
exampleSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [-10, 0])
|
||||
|> arc(angleStart = 120, angleEnd = -60, radius = 5)
|
||||
|> arc(
|
||||
angleStart = 120,
|
||||
angleEnd = -60,
|
||||
radius = 5,
|
||||
)
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [5, 0])
|
||||
|> bezierCurve(control1 = [-3, 0], control2 = [2, 10], end = [-5, 10])
|
||||
|> bezierCurve(
|
||||
control1 = [-3, 0],
|
||||
control2 = [2, 10],
|
||||
end = [-5, 10],
|
||||
)
|
||||
|> line(end = [-4, 10])
|
||||
|> line(end = [-5, -2])
|
||||
|> close()
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Get the shared edge between two faces.
|
||||
|
||||
```kcl
|
||||
getCommonEdge(faces: [TagIdentifier]): Uuid
|
||||
getCommonEdge(faces: [tag; 2]): Edge
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ getCommonEdge(faces: [TagIdentifier]): Uuid
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `faces` | [`[TagIdentifier]`](/docs/kcl-lang/types#TagIdentifier) | The tags of the faces you want to find the common edge between | Yes |
|
||||
| `faces` | `[tag; 2]` | The tags of the faces you want to find the common edge between. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
`Uuid`
|
||||
[`Edge`](/docs/kcl-std/types/std-types-Edge) - An edge of a solid.
|
||||
|
||||
|
||||
### Examples
|
||||
@ -29,17 +29,16 @@ getCommonEdge(faces: [TagIdentifier]): Uuid
|
||||
```kcl
|
||||
// Get an edge shared between two faces, created after a chamfer.
|
||||
|
||||
|
||||
scale = 20
|
||||
part001 = startSketchOn(XY)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [0, scale])
|
||||
|> line(end = [scale, 0])
|
||||
|> line(end = [0, -scale])
|
||||
|> close(tag = $line0)
|
||||
|> extrude(length = 20, tagEnd = $end0)
|
||||
// We tag the chamfer to reference it later.
|
||||
|> chamfer(length = 10, tags = [getOppositeEdge(line0)], tag = $chamfer0)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [0, scale])
|
||||
|> line(end = [scale, 0])
|
||||
|> line(end = [0, -scale])
|
||||
|> close(tag = $line0)
|
||||
|> extrude(length = 20, tagEnd = $end0)
|
||||
// We tag the chamfer to reference it later.
|
||||
|> chamfer(length = 10, tags = [getOppositeEdge(line0)], tag = $chamfer0)
|
||||
|
||||
// Get the shared edge between the chamfer and the extrusion.
|
||||
commonEdge = getCommonEdge(faces = [chamfer0, end0])
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -8,7 +8,7 @@ layout: manual
|
||||
Extract the 'x' axis value of the last line segment in the provided 2-d sketch.
|
||||
|
||||
```kcl
|
||||
lastSegX(@sketch: Sketch): number
|
||||
lastSegX(@sketch: Sketch): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ lastSegX(@sketch: Sketch): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Extract the 'y' axis value of the last line segment in the provided 2-d sketch.
|
||||
|
||||
```kcl
|
||||
lastSegY(@sketch: Sketch): number
|
||||
lastSegY(@sketch: Sketch): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ lastSegY(@sketch: Sketch): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | The sketch whose line segment is being queried. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
File diff suppressed because one or more lines are too long
@ -1,39 +1,41 @@
|
||||
---
|
||||
title: "patternCircular2d"
|
||||
subtitle: "Function in std::sketch"
|
||||
excerpt: "Repeat a 2-dimensional sketch some number of times along a partial or complete circle some specified number of times. Each object may additionally be rotated along the circle, ensuring orientation of the solid with respect to the center of the circle is maintained."
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Repeat a 2-dimensional sketch some number of times along a partial or complete circle some specified number of times. Each object may additionally be rotated along the circle, ensuring orientation of the solid with respect to the center of the circle is maintained.
|
||||
|
||||
|
||||
```kcl
|
||||
patternCircular2d(
|
||||
@sketchSet: [Sketch],
|
||||
instances: number,
|
||||
@sketches: [Sketch; 1+],
|
||||
instances: number(_),
|
||||
center: Point2d,
|
||||
arcDegrees: number,
|
||||
rotateDuplicates: bool,
|
||||
arcDegrees?: number(Angle),
|
||||
rotateDuplicates?: bool,
|
||||
useOriginal?: bool,
|
||||
): [Sketch]
|
||||
): [Sketch; 1+]
|
||||
```
|
||||
|
||||
|
||||
Repeat a 2-dimensional sketch some number of times along a partial or
|
||||
complete circle some specified number of times. Each object mayadditionally be rotated along the circle, ensuring orientation of the
|
||||
solid with respect to the center of the circle is maintained.
|
||||
|
||||
### Arguments
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketchSet` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | Which sketch(es) to pattern | Yes |
|
||||
| `instances` | [`number`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
|
||||
| `sketches` | [`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch) | The sketch(es) to duplicate. | Yes |
|
||||
| `instances` | [`number(_)`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
|
||||
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center about which to make the pattern. This is a 2D vector. | Yes |
|
||||
| `arcDegrees` | [`number`](/docs/kcl-std/types/std-types-number) | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | Yes |
|
||||
| `rotateDuplicates` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether or not to rotate the duplicates as they are copied. | Yes |
|
||||
| `useOriginal` | [`bool`](/docs/kcl-std/types/std-types-bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
|
||||
| `arcDegrees` | [`number(Angle)`](/docs/kcl-std/types/std-types-number) | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | No |
|
||||
| `rotateDuplicates` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether or not to rotate the duplicates as they are copied. | No |
|
||||
| `useOriginal` | [`bool`](/docs/kcl-std/types/std-types-bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
[`[Sketch]`](/docs/kcl-std/types/std-types-Sketch)
|
||||
[`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch)
|
||||
|
||||
|
||||
### Examples
|
||||
@ -49,7 +51,7 @@ exampleSketch = startSketchOn(XZ)
|
||||
center = [0, 0],
|
||||
instances = 13,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true,
|
||||
rotateDuplicates = true
|
||||
)
|
||||
|
||||
example = extrude(exampleSketch, length = 1)
|
72
docs/kcl-std/functions/std-sketch-patternLinear2d.md
Normal file
72
docs/kcl-std/functions/std-sketch-patternLinear2d.md
Normal file
File diff suppressed because one or more lines are too long
@ -1,19 +1,19 @@
|
||||
---
|
||||
title: "patternTransform2d"
|
||||
subtitle: "Function in std::sketch"
|
||||
excerpt: "Just like patternTransform, but works on 2D sketches not 3D solids."
|
||||
excerpt: "Just like `patternTransform`, but works on 2D sketches not 3D solids."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Just like patternTransform, but works on 2D sketches not 3D solids.
|
||||
Just like `patternTransform`, but works on 2D sketches not 3D solids.
|
||||
|
||||
```kcl
|
||||
patternTransform2d(
|
||||
@sketches: [Sketch],
|
||||
instances: number,
|
||||
transform: FunctionSource,
|
||||
useOriginal?: bool,
|
||||
): [Sketch]
|
||||
@sketches: [Sketch; 1+],
|
||||
instances: number(_),
|
||||
transform: fn(number(_)): { },
|
||||
useOriginal?: boolean,
|
||||
): [Sketch; 1+]
|
||||
```
|
||||
|
||||
|
||||
@ -22,14 +22,14 @@ patternTransform2d(
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketches` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | The sketch(es) to duplicate | Yes |
|
||||
| `instances` | [`number`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
|
||||
| `transform` | `FunctionSource` | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
|
||||
| `useOriginal` | [`bool`](/docs/kcl-std/types/std-types-bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
|
||||
| `sketches` | [`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch) | The sketch(es) to duplicate. | Yes |
|
||||
| `instances` | [`number(_)`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
|
||||
| `transform` | [`fn(number(_)): { }`](/docs/kcl-std/types/std-types-fn) | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
|
||||
| `useOriginal` | `boolean` | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
[`[Sketch]`](/docs/kcl-std/types/std-types-Sketch)
|
||||
[`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch)
|
||||
|
||||
|
||||
### Examples
|
@ -9,9 +9,9 @@ Create a regular polygon with the specified number of sides that is either inscr
|
||||
|
||||
```kcl
|
||||
polygon(
|
||||
@sketchSurfaceOrGroup: Sketch | Plane | Face,
|
||||
radius: number,
|
||||
numSides: u64,
|
||||
@sketchOrSurface: Sketch | Plane | Face,
|
||||
radius: number(Length),
|
||||
numSides: number(_),
|
||||
center: Point2d,
|
||||
inscribed?: bool,
|
||||
): Sketch
|
||||
@ -23,11 +23,11 @@ polygon(
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketchSurfaceOrGroup` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Plane or surface to sketch on | Yes |
|
||||
| `radius` | [`number`](/docs/kcl-std/types/std-types-number) | The radius of the polygon | Yes |
|
||||
| `numSides` | `u64` | The number of sides in the polygon | Yes |
|
||||
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center point of the polygon | Yes |
|
||||
| `inscribed` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether the polygon is inscribed (true, the default) or circumscribed (false) about a circle with the specified radius | No |
|
||||
| `sketchOrSurface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Plane or surface to sketch on. | Yes |
|
||||
| `radius` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The radius of the polygon. | Yes |
|
||||
| `numSides` | [`number(_)`](/docs/kcl-std/types/std-types-number) | The number of sides in the polygon. | Yes |
|
||||
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center point of the polygon. | Yes |
|
||||
| `inscribed` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether the polygon is inscribed (true, the default) or circumscribed (false) about a circle with the specified radius. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -40,11 +40,11 @@ polygon(
|
||||
// Create a regular hexagon inscribed in a circle of radius 10
|
||||
hex = startSketchOn(XY)
|
||||
|> polygon(
|
||||
radius = 10,
|
||||
numSides = 6,
|
||||
center = [0, 0],
|
||||
inscribed = true,
|
||||
)
|
||||
radius = 10,
|
||||
numSides = 6,
|
||||
center = [0, 0],
|
||||
inscribed = true,
|
||||
)
|
||||
|
||||
example = extrude(hex, length = 5)
|
||||
```
|
||||
@ -55,11 +55,11 @@ example = extrude(hex, length = 5)
|
||||
// Create a square circumscribed around a circle of radius 5
|
||||
square = startSketchOn(XY)
|
||||
|> polygon(
|
||||
radius = 5.0,
|
||||
numSides = 4,
|
||||
center = [10, 10],
|
||||
inscribed = false,
|
||||
)
|
||||
radius = 5.0,
|
||||
numSides = 4,
|
||||
center = [10, 10],
|
||||
inscribed = false,
|
||||
)
|
||||
example = extrude(square, length = 5)
|
||||
```
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the angle (in degrees) of the provided line segment.
|
||||
|
||||
```kcl
|
||||
segAng(@tag: TagIdentifier): number
|
||||
segAng(@tag: tag): number(Angle)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segAng(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Angle)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the ending point of the provided line segment.
|
||||
|
||||
```kcl
|
||||
segEnd(@tag: TagIdentifier): Point2d
|
||||
segEnd(@tag: tag): Point2d
|
||||
```
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ segEnd(@tag: TagIdentifier): Point2d
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -39,9 +39,9 @@ cube = startSketchOn(XY)
|
||||
|
||||
fn cylinder(radius, tag) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> circle(radius = radius, center = segEnd(tag))
|
||||
|> extrude(length = radius)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> circle(radius = radius, center = segEnd(tag) )
|
||||
|> extrude(length = radius)
|
||||
}
|
||||
|
||||
cylinder(radius = 1, tag = line1)
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the ending point of the provided line segment along the 'x' axis.
|
||||
|
||||
```kcl
|
||||
segEndX(@tag: TagIdentifier): number
|
||||
segEndX(@tag: tag): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segEndX(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the ending point of the provided line segment along the 'y' axis.
|
||||
|
||||
```kcl
|
||||
segEndY(@tag: TagIdentifier): number
|
||||
segEndY(@tag: tag): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segEndY(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the length of the provided line segment.
|
||||
|
||||
```kcl
|
||||
segLen(@tag: TagIdentifier): number
|
||||
segLen(@tag: tag): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segLen(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
||||
@ -29,9 +29,16 @@ segLen(@tag: TagIdentifier): number
|
||||
```kcl
|
||||
exampleSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> angledLine(angle = 60, length = 10, tag = $thing)
|
||||
|> angledLine(
|
||||
angle = 60,
|
||||
length = 10,
|
||||
tag = $thing,
|
||||
)
|
||||
|> tangentialArc(angle = -120, radius = 5)
|
||||
|> angledLine(angle = -60, length = segLen(thing))
|
||||
|> angledLine(
|
||||
angle = -60,
|
||||
length = segLen(thing),
|
||||
)
|
||||
|> close()
|
||||
|
||||
example = extrude(exampleSketch, length = 5)
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the starting point of the provided line segment.
|
||||
|
||||
```kcl
|
||||
segStart(@tag: TagIdentifier): Point2d
|
||||
segStart(@tag: tag): Point2d
|
||||
```
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ segStart(@tag: TagIdentifier): Point2d
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -39,9 +39,9 @@ cube = startSketchOn(XY)
|
||||
|
||||
fn cylinder(radius, tag) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> circle(radius = radius, center = segStart(tag))
|
||||
|> extrude(length = radius)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> circle( radius = radius, center = segStart(tag) )
|
||||
|> extrude(length = radius)
|
||||
}
|
||||
|
||||
cylinder(radius = 1, tag = line1)
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the starting point of the provided line segment along the 'x' axis.
|
||||
|
||||
```kcl
|
||||
segStartX(@tag: TagIdentifier): number
|
||||
segStartX(@tag: tag): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segStartX(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
@ -8,7 +8,7 @@ layout: manual
|
||||
Compute the starting point of the provided line segment along the 'y' axis.
|
||||
|
||||
```kcl
|
||||
segStartY(@tag: TagIdentifier): number
|
||||
segStartY(@tag: tag): number(Length)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ segStartY(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
||||
@ -32,7 +32,7 @@ exampleSketch = startSketchOn(XZ)
|
||||
|> line(end = [20, 0])
|
||||
|> line(end = [0, 3], tag = $thing)
|
||||
|> line(end = [-10, 0])
|
||||
|> line(end = [0, 20 - segStartY(thing)])
|
||||
|> line(end = [0, 20-segStartY(thing)])
|
||||
|> line(end = [-10, 0])
|
||||
|> close()
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,7 +8,7 @@ layout: manual
|
||||
Returns the angle coming out of the end of the segment in degrees.
|
||||
|
||||
```kcl
|
||||
tangentToEnd(@tag: TagIdentifier): number
|
||||
tangentToEnd(@tag: tag): number(Angle)
|
||||
```
|
||||
|
||||
|
||||
@ -17,11 +17,11 @@ tangentToEnd(@tag: TagIdentifier): number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier) | The line segment being queried by its tag | Yes |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | The line segment being queried by its tag. | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
[`number`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
[`number(Angle)`](/docs/kcl-std/types/std-types-number) - A number.
|
||||
|
||||
|
||||
### Examples
|
||||
@ -32,7 +32,10 @@ pillSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [20, 0])
|
||||
|> tangentialArc(end = [0, 10], tag = $arc1)
|
||||
|> angledLine(angle = tangentToEnd(arc1), length = 20)
|
||||
|> angledLine(
|
||||
angle = tangentToEnd(arc1),
|
||||
length = 20,
|
||||
)
|
||||
|> tangentialArc(end = [0, -10])
|
||||
|> close()
|
||||
|
||||
@ -47,7 +50,10 @@ pillSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [0, 20])
|
||||
|> tangentialArc(endAbsolute = [10, 20], tag = $arc1)
|
||||
|> angledLine(angle = tangentToEnd(arc1), length = 20)
|
||||
|> angledLine(
|
||||
angle = tangentToEnd(arc1),
|
||||
length = 20,
|
||||
)
|
||||
|> tangentialArc(end = [-10, 0])
|
||||
|> close()
|
||||
|
||||
@ -60,7 +66,10 @@ pillExtrude = extrude(pillSketch, length = 10)
|
||||
rectangleSketch = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> line(end = [10, 0], tag = $seg1)
|
||||
|> angledLine(angle = tangentToEnd(seg1), length = 10)
|
||||
|> angledLine(
|
||||
angle = tangentToEnd(seg1),
|
||||
length = 10,
|
||||
)
|
||||
|> line(end = [0, 10])
|
||||
|> line(end = [-20, 0])
|
||||
|> close()
|
||||
@ -73,7 +82,11 @@ rectangleExtrude = extrude(rectangleSketch, length = 10)
|
||||
```kcl
|
||||
bottom = startSketchOn(XY)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> arc(endAbsolute = [10, 10], interiorAbsolute = [5, 1], tag = $arc1)
|
||||
|> arc(
|
||||
endAbsolute = [10, 10],
|
||||
interiorAbsolute = [5, 1],
|
||||
tag = $arc1,
|
||||
)
|
||||
|> angledLine(angle = tangentToEnd(arc1), length = 20)
|
||||
|> close()
|
||||
```
|
||||
@ -82,7 +95,7 @@ bottom = startSketchOn(XY)
|
||||
|
||||
```kcl
|
||||
circSketch = startSketchOn(XY)
|
||||
|> circle(center = [0, 0], radius = 3, tag = $circ)
|
||||
|> circle(center = [0, 0], radius= 3, tag = $circ)
|
||||
|
||||
triangleSketch = startSketchOn(XY)
|
||||
|> startProfile(at = [-5, 0])
|
File diff suppressed because one or more lines are too long
@ -1,31 +1,36 @@
|
||||
---
|
||||
title: "intersect"
|
||||
subtitle: "Function in std::solid"
|
||||
excerpt: "Intersect returns the shared volume between multiple solids, preserving only overlapping regions."
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Intersect returns the shared volume between multiple solids, preserving only overlapping regions.
|
||||
|
||||
|
||||
```kcl
|
||||
intersect(
|
||||
@solids: [Solid],
|
||||
tolerance?: number,
|
||||
): [Solid]
|
||||
@solids: [Solid; 2+],
|
||||
tolerance?: number(Length),
|
||||
): [Solid; 1+]
|
||||
```
|
||||
|
||||
Intersect computes the geometric intersection of multiple solid bodies, returning a new solid representing the volume that is common to all input solids. This operation is useful for determining shared material regions, verifying fit, and analyzing overlapping geometries in assemblies.
|
||||
Intersect returns the shared volume between multiple solids, preserving only
|
||||
overlapping regions.
|
||||
Intersect computes the geometric intersection of multiple solid bodies,
|
||||
returning a new solid representing the volume that is common to all input
|
||||
solids. This operation is useful for determining shared material regions,
|
||||
verifying fit, and analyzing overlapping geometries in assemblies.
|
||||
|
||||
### Arguments
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `solids` | [`[Solid]`](/docs/kcl-std/types/std-types-Solid) | The solids to intersect. | Yes |
|
||||
| `tolerance` | [`number`](/docs/kcl-std/types/std-types-number) | The tolerance to use for the intersection operation. | No |
|
||||
| `solids` | `[Solid; 2+]` | The solids to intersect. | Yes |
|
||||
| `tolerance` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The tolerance to use for the intersection operation. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
[`[Solid]`](/docs/kcl-std/types/std-types-Solid)
|
||||
[`[Solid; 1+]`](/docs/kcl-std/types/std-types-Solid)
|
||||
|
||||
|
||||
### Examples
|
||||
@ -33,20 +38,19 @@ Intersect computes the geometric intersection of multiple solid bodies, returnin
|
||||
```kcl
|
||||
// Intersect two cubes using the stdlib functions.
|
||||
|
||||
|
||||
fn cube(center, size) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
}
|
||||
|
||||
part001 = cube(center = [0, 0], size = 10)
|
||||
part002 = cube(center = [7, 3], size = 5)
|
||||
|> translate(z = 1)
|
||||
|> translate(z = 1)
|
||||
|
||||
intersectedPart = intersect([part001, part002])
|
||||
```
|
||||
@ -58,20 +62,19 @@ intersectedPart = intersect([part001, part002])
|
||||
// NOTE: This will not work when using codemods through the UI.
|
||||
// Codemods will generate the stdlib function call instead.
|
||||
|
||||
|
||||
fn cube(center, size) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
}
|
||||
|
||||
part001 = cube(center = [0, 0], size = 10)
|
||||
part002 = cube(center = [7, 3], size = 5)
|
||||
|> translate(z = 1)
|
||||
|> translate(z = 1)
|
||||
|
||||
// This is the equivalent of: intersect([part001, part002])
|
||||
intersectedPart = part001 & part002
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -9,9 +9,9 @@ Union two or more solids into a single solid.
|
||||
|
||||
```kcl
|
||||
union(
|
||||
@solids: [Solid],
|
||||
tolerance?: number,
|
||||
): [Solid]
|
||||
@solids: [Solid; 2+],
|
||||
tolerance?: number(Length),
|
||||
): [Solid; 1+]
|
||||
```
|
||||
|
||||
|
||||
@ -20,12 +20,12 @@ union(
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `solids` | [`[Solid]`](/docs/kcl-std/types/std-types-Solid) | The solids to union. | Yes |
|
||||
| `tolerance` | [`number`](/docs/kcl-std/types/std-types-number) | The tolerance to use for the union operation. | No |
|
||||
| `solids` | `[Solid; 2+]` | The solids to union. | Yes |
|
||||
| `tolerance` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The tolerance to use for the union operation. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
[`[Solid]`](/docs/kcl-std/types/std-types-Solid)
|
||||
[`[Solid; 1+]`](/docs/kcl-std/types/std-types-Solid)
|
||||
|
||||
|
||||
### Examples
|
||||
@ -33,20 +33,19 @@ union(
|
||||
```kcl
|
||||
// Union two cubes using the stdlib functions.
|
||||
|
||||
|
||||
fn cube(center, size) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
}
|
||||
|
||||
part001 = cube(center = [0, 0], size = 10)
|
||||
part002 = cube(center = [7, 3], size = 5)
|
||||
|> translate(z = 1)
|
||||
|> translate(z = 1)
|
||||
|
||||
unionedPart = union([part001, part002])
|
||||
```
|
||||
@ -58,20 +57,19 @@ unionedPart = union([part001, part002])
|
||||
// NOTE: This will not work when using codemods through the UI.
|
||||
// Codemods will generate the stdlib function call instead.
|
||||
|
||||
|
||||
fn cube(center, size) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
}
|
||||
|
||||
part001 = cube(center = [0, 0], size = 10)
|
||||
part002 = cube(center = [7, 3], size = 5)
|
||||
|> translate(z = 1)
|
||||
|> translate(z = 1)
|
||||
|
||||
// This is the equivalent of: union([part001, part002])
|
||||
unionedPart = part001 + part002
|
||||
@ -84,23 +82,22 @@ unionedPart = part001 + part002
|
||||
// NOTE: This will not work when using codemods through the UI.
|
||||
// Codemods will generate the stdlib function call instead.
|
||||
|
||||
|
||||
fn cube(center, size) {
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
return startSketchOn(XY)
|
||||
|> startProfile(at = [center[0] - size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
|> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
|> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
|> close()
|
||||
|> extrude(length = 10)
|
||||
}
|
||||
|
||||
part001 = cube(center = [0, 0], size = 10)
|
||||
part002 = cube(center = [7, 3], size = 5)
|
||||
|> translate(z = 1)
|
||||
|> translate(z = 1)
|
||||
|
||||
// This is the equivalent of: union([part001, part002])
|
||||
// Programmers will understand `|` as a union operation, but mechanical engineers
|
||||
// This is the equivalent of: union([part001, part002])
|
||||
// Programmers will understand `|` as a union operation, but mechanical engineers
|
||||
// will understand `+`, we made both work.
|
||||
unionedPart = part001 | part002
|
||||
```
|
@ -14,8 +14,6 @@ mirror2d(
|
||||
): Sketch
|
||||
```
|
||||
|
||||
Only works on unclosed sketches for now.
|
||||
|
||||
Mirror occurs around a local sketch axis rather than a global axis.
|
||||
|
||||
### Arguments
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -9,13 +9,13 @@ layout: manual
|
||||
### Functions
|
||||
|
||||
* [**std**](/docs/kcl-std/modules/std)
|
||||
* [`appearance`](/docs/kcl-std/appearance)
|
||||
* [`assert`](/docs/kcl-std/assert)
|
||||
* [`assertIs`](/docs/kcl-std/assertIs)
|
||||
* [`assert`](/docs/kcl-std/functions/std-assert)
|
||||
* [`assertIs`](/docs/kcl-std/functions/std-assertIs)
|
||||
* [`clone`](/docs/kcl-std/functions/std-clone)
|
||||
* [`helix`](/docs/kcl-std/functions/std-helix)
|
||||
* [`offsetPlane`](/docs/kcl-std/functions/std-offsetPlane)
|
||||
* [`patternLinear2d`](/docs/kcl-std/patternLinear2d)
|
||||
* [**std::appearance**](/docs/kcl-std/modules/std-appearance)
|
||||
* [`appearance::hexString`](/docs/kcl-std/functions/std-appearance-hexString)
|
||||
* [**std::array**](/docs/kcl-std/modules/std-array)
|
||||
* [`map`](/docs/kcl-std/functions/std-array-map)
|
||||
* [`pop`](/docs/kcl-std/functions/std-array-pop)
|
||||
@ -52,57 +52,59 @@ layout: manual
|
||||
* [`arc`](/docs/kcl-std/arc)
|
||||
* [`bezierCurve`](/docs/kcl-std/bezierCurve)
|
||||
* [`circle`](/docs/kcl-std/functions/std-sketch-circle)
|
||||
* [`circleThreePoint`](/docs/kcl-std/circleThreePoint)
|
||||
* [`circleThreePoint`](/docs/kcl-std/functions/std-sketch-circleThreePoint)
|
||||
* [`close`](/docs/kcl-std/close)
|
||||
* [`extrude`](/docs/kcl-std/extrude)
|
||||
* [`getCommonEdge`](/docs/kcl-std/getCommonEdge)
|
||||
* [`getNextAdjacentEdge`](/docs/kcl-std/getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](/docs/kcl-std/getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](/docs/kcl-std/getPreviousAdjacentEdge)
|
||||
* [`extrude`](/docs/kcl-std/functions/std-sketch-extrude)
|
||||
* [`getCommonEdge`](/docs/kcl-std/functions/std-sketch-getCommonEdge)
|
||||
* [`getNextAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge)
|
||||
* [`involuteCircular`](/docs/kcl-std/involuteCircular)
|
||||
* [`lastSegX`](/docs/kcl-std/lastSegX)
|
||||
* [`lastSegY`](/docs/kcl-std/lastSegY)
|
||||
* [`lastSegX`](/docs/kcl-std/functions/std-sketch-lastSegX)
|
||||
* [`lastSegY`](/docs/kcl-std/functions/std-sketch-lastSegY)
|
||||
* [`line`](/docs/kcl-std/line)
|
||||
* [`loft`](/docs/kcl-std/loft)
|
||||
* [`patternCircular2d`](/docs/kcl-std/patternCircular2d)
|
||||
* [`patternTransform2d`](/docs/kcl-std/patternTransform2d)
|
||||
* [`polygon`](/docs/kcl-std/polygon)
|
||||
* [`loft`](/docs/kcl-std/functions/std-sketch-loft)
|
||||
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
|
||||
* [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d)
|
||||
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
|
||||
* [`polygon`](/docs/kcl-std/functions/std-sketch-polygon)
|
||||
* [`profileStart`](/docs/kcl-std/profileStart)
|
||||
* [`profileStartX`](/docs/kcl-std/profileStartX)
|
||||
* [`profileStartY`](/docs/kcl-std/profileStartY)
|
||||
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
|
||||
* [`segAng`](/docs/kcl-std/segAng)
|
||||
* [`segEnd`](/docs/kcl-std/segEnd)
|
||||
* [`segEndX`](/docs/kcl-std/segEndX)
|
||||
* [`segEndY`](/docs/kcl-std/segEndY)
|
||||
* [`segLen`](/docs/kcl-std/segLen)
|
||||
* [`segStart`](/docs/kcl-std/segStart)
|
||||
* [`segStartX`](/docs/kcl-std/segStartX)
|
||||
* [`segStartY`](/docs/kcl-std/segStartY)
|
||||
* [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
|
||||
* [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)
|
||||
* [`segEndX`](/docs/kcl-std/functions/std-sketch-segEndX)
|
||||
* [`segEndY`](/docs/kcl-std/functions/std-sketch-segEndY)
|
||||
* [`segLen`](/docs/kcl-std/functions/std-sketch-segLen)
|
||||
* [`segStart`](/docs/kcl-std/functions/std-sketch-segStart)
|
||||
* [`segStartX`](/docs/kcl-std/functions/std-sketch-segStartX)
|
||||
* [`segStartY`](/docs/kcl-std/functions/std-sketch-segStartY)
|
||||
* [`startProfile`](/docs/kcl-std/startProfile)
|
||||
* [`startSketchOn`](/docs/kcl-std/startSketchOn)
|
||||
* [`subtract2d`](/docs/kcl-std/subtract2d)
|
||||
* [`sweep`](/docs/kcl-std/sweep)
|
||||
* [`tangentToEnd`](/docs/kcl-std/tangentToEnd)
|
||||
* [`sweep`](/docs/kcl-std/functions/std-sketch-sweep)
|
||||
* [`tangentToEnd`](/docs/kcl-std/functions/std-sketch-tangentToEnd)
|
||||
* [`tangentialArc`](/docs/kcl-std/tangentialArc)
|
||||
* [`xLine`](/docs/kcl-std/xLine)
|
||||
* [`yLine`](/docs/kcl-std/yLine)
|
||||
* [**std::solid**](/docs/kcl-std/modules/std-solid)
|
||||
* [`appearance`](/docs/kcl-std/functions/std-solid-appearance)
|
||||
* [`chamfer`](/docs/kcl-std/functions/std-solid-chamfer)
|
||||
* [`fillet`](/docs/kcl-std/functions/std-solid-fillet)
|
||||
* [`hollow`](/docs/kcl-std/functions/std-solid-hollow)
|
||||
* [`intersect`](/docs/kcl-std/intersect)
|
||||
* [`patternCircular3d`](/docs/kcl-std/patternCircular3d)
|
||||
* [`patternLinear3d`](/docs/kcl-std/patternLinear3d)
|
||||
* [`patternTransform`](/docs/kcl-std/patternTransform)
|
||||
* [`intersect`](/docs/kcl-std/functions/std-solid-intersect)
|
||||
* [`patternCircular3d`](/docs/kcl-std/functions/std-solid-patternCircular3d)
|
||||
* [`patternLinear3d`](/docs/kcl-std/functions/std-solid-patternLinear3d)
|
||||
* [`patternTransform`](/docs/kcl-std/functions/std-solid-patternTransform)
|
||||
* [`shell`](/docs/kcl-std/functions/std-solid-shell)
|
||||
* [`subtract`](/docs/kcl-std/subtract)
|
||||
* [`union`](/docs/kcl-std/union)
|
||||
* [`subtract`](/docs/kcl-std/functions/std-solid-subtract)
|
||||
* [`union`](/docs/kcl-std/functions/std-solid-union)
|
||||
* [**std::transform**](/docs/kcl-std/modules/std-transform)
|
||||
* [`mirror2d`](/docs/kcl-std/functions/std-transform-mirror2d)
|
||||
* [`rotate`](/docs/kcl-std/rotate)
|
||||
* [`scale`](/docs/kcl-std/scale)
|
||||
* [`translate`](/docs/kcl-std/translate)
|
||||
* [`rotate`](/docs/kcl-std/functions/std-transform-rotate)
|
||||
* [`scale`](/docs/kcl-std/functions/std-transform-scale)
|
||||
* [`translate`](/docs/kcl-std/functions/std-transform-translate)
|
||||
* [**std::units**](/docs/kcl-std/modules/std-units)
|
||||
* [`units::toCentimeters`](/docs/kcl-std/functions/std-units-toCentimeters)
|
||||
* [`units::toDegrees`](/docs/kcl-std/functions/std-units-toDegrees)
|
||||
@ -128,6 +130,9 @@ layout: manual
|
||||
* [`E`](/docs/kcl-std/consts/std-math-E)
|
||||
* [`PI`](/docs/kcl-std/consts/std-math-PI)
|
||||
* [`TAU`](/docs/kcl-std/consts/std-math-TAU)
|
||||
* [**std::sweep**](/docs/kcl-std/modules/std-sweep)
|
||||
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
|
||||
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)
|
||||
* [**std::turns**](/docs/kcl-std/modules/std-turns)
|
||||
* [`turns::HALF_TURN`](/docs/kcl-std/consts/std-turns-HALF_TURN)
|
||||
* [`turns::QUARTER_TURN`](/docs/kcl-std/consts/std-turns-QUARTER_TURN)
|
||||
|
16
docs/kcl-std/modules/std-appearance.md
Normal file
16
docs/kcl-std/modules/std-appearance.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "appearance"
|
||||
subtitle: "Module in std"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Functions and constants
|
||||
|
||||
* [`appearance::hexString`](/docs/kcl-std/functions/std-appearance-hexString)
|
||||
|
@ -17,38 +17,39 @@ This module contains functions for creating and manipulating sketches, and makin
|
||||
* [`arc`](/docs/kcl-std/arc)
|
||||
* [`bezierCurve`](/docs/kcl-std/bezierCurve)
|
||||
* [`circle`](/docs/kcl-std/functions/std-sketch-circle)
|
||||
* [`circleThreePoint`](/docs/kcl-std/circleThreePoint)
|
||||
* [`circleThreePoint`](/docs/kcl-std/functions/std-sketch-circleThreePoint)
|
||||
* [`close`](/docs/kcl-std/close)
|
||||
* [`extrude`](/docs/kcl-std/extrude)
|
||||
* [`getCommonEdge`](/docs/kcl-std/getCommonEdge)
|
||||
* [`getNextAdjacentEdge`](/docs/kcl-std/getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](/docs/kcl-std/getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](/docs/kcl-std/getPreviousAdjacentEdge)
|
||||
* [`extrude`](/docs/kcl-std/functions/std-sketch-extrude)
|
||||
* [`getCommonEdge`](/docs/kcl-std/functions/std-sketch-getCommonEdge)
|
||||
* [`getNextAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](/docs/kcl-std/functions/std-sketch-getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](/docs/kcl-std/functions/std-sketch-getPreviousAdjacentEdge)
|
||||
* [`involuteCircular`](/docs/kcl-std/involuteCircular)
|
||||
* [`lastSegX`](/docs/kcl-std/lastSegX)
|
||||
* [`lastSegY`](/docs/kcl-std/lastSegY)
|
||||
* [`lastSegX`](/docs/kcl-std/functions/std-sketch-lastSegX)
|
||||
* [`lastSegY`](/docs/kcl-std/functions/std-sketch-lastSegY)
|
||||
* [`line`](/docs/kcl-std/line)
|
||||
* [`loft`](/docs/kcl-std/loft)
|
||||
* [`patternCircular2d`](/docs/kcl-std/patternCircular2d)
|
||||
* [`patternTransform2d`](/docs/kcl-std/patternTransform2d)
|
||||
* [`polygon`](/docs/kcl-std/polygon)
|
||||
* [`loft`](/docs/kcl-std/functions/std-sketch-loft)
|
||||
* [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d)
|
||||
* [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d)
|
||||
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
|
||||
* [`polygon`](/docs/kcl-std/functions/std-sketch-polygon)
|
||||
* [`profileStart`](/docs/kcl-std/profileStart)
|
||||
* [`profileStartX`](/docs/kcl-std/profileStartX)
|
||||
* [`profileStartY`](/docs/kcl-std/profileStartY)
|
||||
* [`revolve`](/docs/kcl-std/functions/std-sketch-revolve)
|
||||
* [`segAng`](/docs/kcl-std/segAng)
|
||||
* [`segEnd`](/docs/kcl-std/segEnd)
|
||||
* [`segEndX`](/docs/kcl-std/segEndX)
|
||||
* [`segEndY`](/docs/kcl-std/segEndY)
|
||||
* [`segLen`](/docs/kcl-std/segLen)
|
||||
* [`segStart`](/docs/kcl-std/segStart)
|
||||
* [`segStartX`](/docs/kcl-std/segStartX)
|
||||
* [`segStartY`](/docs/kcl-std/segStartY)
|
||||
* [`segAng`](/docs/kcl-std/functions/std-sketch-segAng)
|
||||
* [`segEnd`](/docs/kcl-std/functions/std-sketch-segEnd)
|
||||
* [`segEndX`](/docs/kcl-std/functions/std-sketch-segEndX)
|
||||
* [`segEndY`](/docs/kcl-std/functions/std-sketch-segEndY)
|
||||
* [`segLen`](/docs/kcl-std/functions/std-sketch-segLen)
|
||||
* [`segStart`](/docs/kcl-std/functions/std-sketch-segStart)
|
||||
* [`segStartX`](/docs/kcl-std/functions/std-sketch-segStartX)
|
||||
* [`segStartY`](/docs/kcl-std/functions/std-sketch-segStartY)
|
||||
* [`startProfile`](/docs/kcl-std/startProfile)
|
||||
* [`startSketchOn`](/docs/kcl-std/startSketchOn)
|
||||
* [`subtract2d`](/docs/kcl-std/subtract2d)
|
||||
* [`sweep`](/docs/kcl-std/sweep)
|
||||
* [`tangentToEnd`](/docs/kcl-std/tangentToEnd)
|
||||
* [`sweep`](/docs/kcl-std/functions/std-sketch-sweep)
|
||||
* [`tangentToEnd`](/docs/kcl-std/functions/std-sketch-tangentToEnd)
|
||||
* [`tangentialArc`](/docs/kcl-std/tangentialArc)
|
||||
* [`xLine`](/docs/kcl-std/xLine)
|
||||
* [`yLine`](/docs/kcl-std/yLine)
|
||||
|
@ -12,14 +12,15 @@ This module contains functions for modifying solids, e.g., by adding a fillet or
|
||||
|
||||
## Functions and constants
|
||||
|
||||
* [`appearance`](/docs/kcl-std/functions/std-solid-appearance)
|
||||
* [`chamfer`](/docs/kcl-std/functions/std-solid-chamfer)
|
||||
* [`fillet`](/docs/kcl-std/functions/std-solid-fillet)
|
||||
* [`hollow`](/docs/kcl-std/functions/std-solid-hollow)
|
||||
* [`intersect`](/docs/kcl-std/intersect)
|
||||
* [`patternCircular3d`](/docs/kcl-std/patternCircular3d)
|
||||
* [`patternLinear3d`](/docs/kcl-std/patternLinear3d)
|
||||
* [`patternTransform`](/docs/kcl-std/patternTransform)
|
||||
* [`intersect`](/docs/kcl-std/functions/std-solid-intersect)
|
||||
* [`patternCircular3d`](/docs/kcl-std/functions/std-solid-patternCircular3d)
|
||||
* [`patternLinear3d`](/docs/kcl-std/functions/std-solid-patternLinear3d)
|
||||
* [`patternTransform`](/docs/kcl-std/functions/std-solid-patternTransform)
|
||||
* [`shell`](/docs/kcl-std/functions/std-solid-shell)
|
||||
* [`subtract`](/docs/kcl-std/subtract)
|
||||
* [`union`](/docs/kcl-std/union)
|
||||
* [`subtract`](/docs/kcl-std/functions/std-solid-subtract)
|
||||
* [`union`](/docs/kcl-std/functions/std-solid-union)
|
||||
|
||||
|
17
docs/kcl-std/modules/std-sweep.md
Normal file
17
docs/kcl-std/modules/std-sweep.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: "sweep"
|
||||
subtitle: "Module in std"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Functions and constants
|
||||
|
||||
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
|
||||
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)
|
||||
|
@ -13,7 +13,7 @@ This module contains functions for transforming sketches and solids.
|
||||
## Functions and constants
|
||||
|
||||
* [`mirror2d`](/docs/kcl-std/functions/std-transform-mirror2d)
|
||||
* [`rotate`](/docs/kcl-std/rotate)
|
||||
* [`scale`](/docs/kcl-std/scale)
|
||||
* [`translate`](/docs/kcl-std/translate)
|
||||
* [`rotate`](/docs/kcl-std/functions/std-transform-rotate)
|
||||
* [`scale`](/docs/kcl-std/functions/std-transform-scale)
|
||||
* [`translate`](/docs/kcl-std/functions/std-transform-translate)
|
||||
|
||||
|
@ -11,14 +11,16 @@ Contains frequently used constants, functions for interacting with the KittyCAD
|
||||
|
||||
The standard library is organised into modules (listed below), but most things are always available in KCL programs.
|
||||
|
||||
You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL guide]().
|
||||
You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL guide](https://zoo.dev/docs/kcl-book/intro.html).
|
||||
|
||||
## Modules
|
||||
|
||||
* [`appearance::appearance`](/docs/kcl-std/modules/std-appearance)
|
||||
* [`array`](/docs/kcl-std/modules/std-array)
|
||||
* [`math`](/docs/kcl-std/modules/std-math)
|
||||
* [`sketch`](/docs/kcl-std/modules/std-sketch)
|
||||
* [`solid`](/docs/kcl-std/modules/std-solid)
|
||||
* [`sweep::sweep`](/docs/kcl-std/modules/std-sweep)
|
||||
* [`transform`](/docs/kcl-std/modules/std-transform)
|
||||
* [`turns::turns`](/docs/kcl-std/modules/std-turns)
|
||||
* [`types`](/docs/kcl-std/modules/std-types)
|
||||
@ -34,11 +36,9 @@ You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL gui
|
||||
* [`Y`](/docs/kcl-std/consts/std-Y)
|
||||
* [`YZ`](/docs/kcl-std/consts/std-YZ)
|
||||
* [`Z`](/docs/kcl-std/consts/std-Z)
|
||||
* [`appearance`](/docs/kcl-std/appearance)
|
||||
* [`assert`](/docs/kcl-std/assert)
|
||||
* [`assertIs`](/docs/kcl-std/assertIs)
|
||||
* [`assert`](/docs/kcl-std/functions/std-assert)
|
||||
* [`assertIs`](/docs/kcl-std/functions/std-assertIs)
|
||||
* [`clone`](/docs/kcl-std/functions/std-clone)
|
||||
* [`helix`](/docs/kcl-std/functions/std-helix)
|
||||
* [`offsetPlane`](/docs/kcl-std/functions/std-offsetPlane)
|
||||
* [`patternLinear2d`](/docs/kcl-std/patternLinear2d)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
184205
docs/kcl-std/std.json
184205
docs/kcl-std/std.json
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@ tangentialArc(
|
||||
endAbsolute?: Point2d,
|
||||
end?: Point2d,
|
||||
radius?: number,
|
||||
diameter?: number,
|
||||
angle?: number,
|
||||
tag?: TagDeclarator,
|
||||
): Sketch
|
||||
@ -27,7 +28,8 @@ When using radius and angle, draw a curved line segment along part of an imagina
|
||||
| `sketch` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) | Which sketch should this path be added to? | Yes |
|
||||
| `endAbsolute` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | Which absolute point should this arc go to? Incompatible with `end`, `radius`, and `offset`. | No |
|
||||
| `end` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | How far away (along the X and Y axes) should this arc go? Incompatible with `endAbsolute`, `radius`, and `offset`. | No |
|
||||
| `radius` | [`number`](/docs/kcl-std/types/std-types-number) | Radius of the imaginary circle. `angle` must be given. Incompatible with `end` and `endAbsolute`. | No |
|
||||
| `radius` | [`number`](/docs/kcl-std/types/std-types-number) | Radius of the imaginary circle. `angle` must be given. Incompatible with `end` and `endAbsolute` and `diameter`. | No |
|
||||
| `diameter` | [`number`](/docs/kcl-std/types/std-types-number) | Diameter of the imaginary circle. `angle` must be given. Incompatible with `end` and `endAbsolute` and `radius`. | No |
|
||||
| `angle` | [`number`](/docs/kcl-std/types/std-types-number) | Offset of the arc in degrees. `radius` must be given. Incompatible with `end` and `endAbsolute`. | No |
|
||||
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | Create a new tag which refers to this arc | No |
|
||||
|
||||
|
@ -5,7 +5,7 @@ import * as fsp from 'fs/promises'
|
||||
test.describe('Electron app header tests', () => {
|
||||
test(
|
||||
'Open Command Palette button has correct shortcut',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
@ -30,7 +30,7 @@ test.describe('Electron app header tests', () => {
|
||||
|
||||
test(
|
||||
'User settings has correct shortcut',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
test.describe('Authentication tests', () => {
|
||||
test(
|
||||
`The user can sign out and back in`,
|
||||
{ tag: ['@electron'] },
|
||||
{ tag: ['@desktop'] },
|
||||
async ({ page, homePage, signInPage, toolbar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
|
@ -78,11 +78,10 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
|
||||
// Delete a character to break the KCL
|
||||
await editor.openPane()
|
||||
await editor.scrollToText('bracketLeg1Sketch, length = thickness)')
|
||||
await page
|
||||
.getByText('extrude(bracketLeg1Sketch, length = thickness)')
|
||||
.click()
|
||||
await page.keyboard.press('Backspace')
|
||||
await editor.scrollToText('extrude(%, length = width)')
|
||||
await page.getByText('extrude(%, length = width)').click()
|
||||
|
||||
await page.keyboard.press(')')
|
||||
|
||||
// Ensure that a badge appears on the button
|
||||
await expect(codePaneButtonHolder).toContainText('notification')
|
||||
@ -99,16 +98,11 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// Ensure that a badge appears on the button
|
||||
await expect(codePaneButtonHolder).toContainText('notification')
|
||||
// Ensure we have no errors in the gutter.
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// Open the code pane
|
||||
await editor.openPane()
|
||||
|
||||
// Go to our problematic code again (missing closing paren!)
|
||||
await editor.scrollToText('extrude(bracketLeg1Sketch, length = thickness')
|
||||
// Go to our problematic code again
|
||||
await editor.scrollToText('extrude(%, length = w')
|
||||
|
||||
// Ensure that a badge appears on the button
|
||||
await expect(codePaneButtonHolder).toContainText('notification')
|
||||
@ -134,8 +128,6 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Ensure badge is present
|
||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
||||
await expect(codePaneButtonHolder).toContainText('notification', {
|
||||
@ -158,10 +150,14 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
await expect(
|
||||
page
|
||||
.getByText(
|
||||
'Modeling command failed: [ApiError { error_code: InternalEngine, message: "Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis" }]'
|
||||
'Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis'
|
||||
)
|
||||
.first()
|
||||
).toBeVisible()
|
||||
|
||||
// Make sure ApiError is not on the page.
|
||||
// This ensures we didn't nest the json
|
||||
await expect(page.getByText('ApiError')).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
|
||||
@ -179,7 +175,7 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
// await scene.settled(cmdBar)
|
||||
|
||||
// Ensure badge is present
|
||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
||||
@ -233,11 +229,54 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
.first()
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test('KCL errors with functions show hints for the entire backtrace', async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
editor,
|
||||
toolbar,
|
||||
}) => {
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const code = `fn check(@x) {
|
||||
return assert(x, isGreaterThan = 0)
|
||||
}
|
||||
|
||||
fn middle(@x) {
|
||||
return check(x)
|
||||
}
|
||||
|
||||
middle(1)
|
||||
middle(0)
|
||||
`
|
||||
await test.step('Set the code with a KCL error', async () => {
|
||||
await toolbar.openPane('code')
|
||||
await editor.replaceCode('', code)
|
||||
})
|
||||
// This shows all the diagnostics in a way that doesn't require the mouse
|
||||
// pointer hovering over a coordinate, which would be brittle.
|
||||
await test.step('Open CodeMirror diagnostics list', async () => {
|
||||
// Ensure keyboard focus is in the editor.
|
||||
await page.getByText('fn check(').click()
|
||||
await page.keyboard.press('ControlOrMeta+Shift+M')
|
||||
})
|
||||
await expect(
|
||||
page.getByText(`assert failed: Expected 0 to be greater than 0 but it wasn't
|
||||
assert()
|
||||
check()
|
||||
middle()`)
|
||||
).toBeVisible()
|
||||
// There should be one hint inside middle() and one at the top level.
|
||||
await expect(page.getByText('Part of the error backtrace')).toHaveCount(2)
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
'Opening multiple panes persists when switching projects',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
// Setup multiple projects.
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -308,7 +347,7 @@ test(
|
||||
|
||||
test(
|
||||
'external change of file contents are reflected in editor',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const PROJECT_DIR_NAME = 'lee-was-here'
|
||||
const { dir: projectsDir } = await context.folderSetupFn(async (dir) => {
|
||||
|
@ -36,7 +36,10 @@ test.describe('Command bar tests', () => {
|
||||
await u.closeDebugPanel()
|
||||
|
||||
// Click the line of code for xLine.
|
||||
await page.getByText(`close()`).click() // TODO remove this and reinstate // await topHorzSegmentClick()
|
||||
await page.getByText(`startProfile(at = [-10, -10])`).click()
|
||||
|
||||
// Wait for the selection to register (TODO: we need a definitive way to wait for this)
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
await toolbar.extrudeButton.click()
|
||||
await cmdBar.expectState({
|
||||
@ -45,10 +48,10 @@ test.describe('Command bar tests', () => {
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
Length: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -56,7 +59,7 @@ test.describe('Command bar tests', () => {
|
||||
stage: 'review',
|
||||
commandName: 'Extrude',
|
||||
headerArguments: {
|
||||
Sketches: '1 segment',
|
||||
Profiles: '1 profile',
|
||||
Length: '5',
|
||||
},
|
||||
})
|
||||
@ -286,7 +289,7 @@ test.describe('Command bar tests', () => {
|
||||
await cmdBar.cmdOptions.getByText('Extrude').click()
|
||||
|
||||
// Assert that we're on the selection step
|
||||
await expect(page.getByRole('button', { name: 'sketches' })).toBeDisabled()
|
||||
await expect(page.getByRole('button', { name: 'Profiles' })).toBeDisabled()
|
||||
// Select a face
|
||||
await page.mouse.move(700, 200)
|
||||
await page.mouse.click(700, 200)
|
||||
@ -399,7 +402,6 @@ test.describe('Command bar tests', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await page.goto(page.url() + targetURL)
|
||||
expect(page.url()).toContain(targetURL)
|
||||
})
|
||||
|
||||
await test.step(`Submit the command`, async () => {
|
||||
@ -410,7 +412,7 @@ test.describe('Command bar tests', () => {
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: '',
|
||||
Name: 'test',
|
||||
Name: 'main.kcl',
|
||||
Code: '1 line',
|
||||
},
|
||||
highlightedHeaderArg: 'method',
|
||||
@ -421,7 +423,7 @@ test.describe('Command bar tests', () => {
|
||||
commandName: 'Import file from URL',
|
||||
headerArguments: {
|
||||
Method: 'New project',
|
||||
Name: 'test',
|
||||
Name: 'main.kcl',
|
||||
Code: '1 line',
|
||||
},
|
||||
})
|
||||
@ -463,7 +465,6 @@ test.describe('Command bar tests', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await page.goto(page.url() + targetURL)
|
||||
expect(page.url()).toContain(targetURL)
|
||||
})
|
||||
|
||||
await test.step(`Submit the command`, async () => {
|
||||
@ -474,7 +475,7 @@ test.describe('Command bar tests', () => {
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: '',
|
||||
Name: 'test',
|
||||
Name: 'main.kcl',
|
||||
Code: '1 line',
|
||||
},
|
||||
highlightedHeaderArg: 'method',
|
||||
@ -487,7 +488,7 @@ test.describe('Command bar tests', () => {
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: 'Existing project',
|
||||
Name: 'test',
|
||||
Name: 'main.kcl',
|
||||
ProjectName: '',
|
||||
Code: '1 line',
|
||||
},
|
||||
@ -500,7 +501,7 @@ test.describe('Command bar tests', () => {
|
||||
headerArguments: {
|
||||
Method: 'Existing project',
|
||||
ProjectName: 'testProjectDir',
|
||||
Name: 'test',
|
||||
Name: 'main.kcl',
|
||||
Code: '1 line',
|
||||
},
|
||||
})
|
||||
@ -510,7 +511,7 @@ test.describe('Command bar tests', () => {
|
||||
await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
|
||||
await editor.expectEditor.toContain('extrusionDistance = 12')
|
||||
await toolbar.openPane('files')
|
||||
await toolbar.expectFileTreeState(['main.kcl', 'test.kcl'])
|
||||
await toolbar.expectFileTreeState(['main-1.kcl', 'main.kcl'])
|
||||
})
|
||||
})
|
||||
|
||||
@ -518,7 +519,7 @@ test.describe('Command bar tests', () => {
|
||||
`Zoom to fit to shared model on web`,
|
||||
{ tag: ['@web'] },
|
||||
async ({ page, scene }) => {
|
||||
if (process.env.PLATFORM !== 'web') {
|
||||
if (process.env.TARGET !== 'web') {
|
||||
// This test is web-only
|
||||
// TODO: re-enable on CI as part of a new @web test suite
|
||||
return
|
||||
@ -661,4 +662,56 @@ c = 3 + a`
|
||||
`a = 5b = a * amyParameter001 = ${newValue}c = 3 + a`
|
||||
)
|
||||
})
|
||||
|
||||
test('Command palette can be opened via query parameter', async ({
|
||||
page,
|
||||
homePage,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.goto(`${page.url()}/?cmd=app.theme&groupId=settings`)
|
||||
await homePage.expectState({
|
||||
projectCards: [],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
commandName: 'Settings · app · theme',
|
||||
currentArgKey: 'value',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Level: 'user',
|
||||
Value: '',
|
||||
},
|
||||
highlightedHeaderArg: 'value',
|
||||
})
|
||||
})
|
||||
|
||||
test('Text-to-CAD command can be closed with escape while in prompt', async ({
|
||||
page,
|
||||
homePage,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await homePage.expectState({
|
||||
projectCards: [],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.textToCadBtn.click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
commandName: 'Text-to-CAD Create',
|
||||
currentArgKey: 'prompt',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Method: 'New project',
|
||||
NewProjectName: 'untitled',
|
||||
Prompt: '',
|
||||
},
|
||||
highlightedHeaderArg: 'prompt',
|
||||
})
|
||||
await page.keyboard.press('Escape')
|
||||
await cmdBar.toBeClosed()
|
||||
await cmdBar.expectState({
|
||||
stage: 'commandBarClosed',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test(
|
||||
'export works on the first try',
|
||||
{ tag: ['@electron', '@macos', '@windows', '@skipLocalEngine'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows', '@skipLocalEngine'] },
|
||||
async ({ page, context, scene, tronApp, cmdBar }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
@ -58,12 +58,6 @@ test(
|
||||
await expect(submitButton).toBeVisible()
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Expect it to succeed
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
@ -71,8 +65,9 @@ test(
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await page.waitForTimeout(1_000)
|
||||
const count = await successToastMessage.count()
|
||||
await expect(count).toBeGreaterThanOrEqual(1)
|
||||
|
||||
// Check for the exported file
|
||||
const firstFileFullPath = path.resolve(
|
||||
@ -141,7 +136,9 @@ test(
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await page.waitForTimeout(1_000)
|
||||
const count = await successToastMessage.count()
|
||||
await expect(count).toBeGreaterThanOrEqual(1)
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Check for the exported file=
|
||||
|
@ -1001,7 +1001,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`@settings(defaultLengthUnit = in)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfile(%, at = [3.14, 12])
|
||||
|> startProfile(%, at = [0, 12])
|
||||
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
||||
)
|
||||
|
||||
@ -1076,7 +1076,7 @@ sketch001 = startSketchOn(XZ)
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`@settings(defaultLengthUnit = in)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfile(%, at = [3.14, 12])
|
||||
|> startProfile(%, at = [0, 12])
|
||||
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
||||
)
|
||||
})
|
||||
@ -1131,6 +1131,8 @@ sketch001 = startSketchOn(XZ)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
await page.getByText('startProfile(at = [4.61, -14.01])').click()
|
||||
// Wait for the selection to register (TODO: we need a definitive way to wait for this)
|
||||
await page.waitForTimeout(200)
|
||||
await toolbar.extrudeButton.click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
@ -1138,7 +1140,7 @@ sketch001 = startSketchOn(XZ)
|
||||
currentArgKey: 'length',
|
||||
currentArgValue: '5',
|
||||
headerArguments: {
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Length: '',
|
||||
},
|
||||
highlightedHeaderArg: 'length',
|
||||
@ -1148,7 +1150,7 @@ sketch001 = startSketchOn(XZ)
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Length: '5',
|
||||
},
|
||||
commandName: 'Extrude',
|
||||
@ -1335,7 +1337,7 @@ sketch001 = startSketchOn(XZ)
|
||||
|
||||
test(
|
||||
`Can import a local OBJ file`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, context }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'cube')
|
||||
@ -1533,7 +1535,6 @@ sketch001 = startSketchOn(XZ)
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.expectPixelColor(
|
||||
TEST_COLORS.DARK_MODE_BKGD,
|
||||
@ -1589,4 +1590,38 @@ sketch001 = startSketchOn(XZ)
|
||||
await expect(page.getByTestId('center-rectangle')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test('syntax errors still show when reopening KCL pane', async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// Wait for connection, this is especially important for this test, because safeParse is invoked when
|
||||
// connection is established which would interfere with the test if it happened during later steps.
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Code with no error
|
||||
await u.codeLocator.fill(`x = 7`)
|
||||
await page.waitForTimeout(200) // allow some time for the error to show potentially
|
||||
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
|
||||
|
||||
// Code with error
|
||||
await u.codeLocator.fill(`x 7`)
|
||||
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(1)
|
||||
|
||||
// Close and reopen KCL code panel
|
||||
await u.closeKclCodePanel()
|
||||
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0) // error disappears on close
|
||||
await u.openKclCodePanel()
|
||||
|
||||
// Verify error is still visible
|
||||
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(1)
|
||||
})
|
||||
})
|
||||
|
@ -57,7 +57,7 @@ sketch003 = startSketchOn(plane001)
|
||||
test.describe('Feature Tree pane', () => {
|
||||
test(
|
||||
'User can go to definition and go to function definition',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, homePage, scene, editor, toolbar, cmdBar, page }) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
@ -150,7 +150,7 @@ test.describe('Feature Tree pane', () => {
|
||||
|
||||
test(
|
||||
`User can edit sketch (but not on offset plane yet) from the feature tree`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, homePage, scene, editor, toolbar, page }) => {
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
|
@ -13,7 +13,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
test.describe('integrations tests', () => {
|
||||
test(
|
||||
'Creating a new file or switching file while in sketchMode should exit sketchMode',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, context, homePage, scene, editor, toolbar, cmdBar }) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
@ -100,7 +100,7 @@ test.describe('when using the file tree to', () => {
|
||||
|
||||
test(
|
||||
`rename ${fromFile} to ${toFile}, and doesn't crash on reload and settings load`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
const { panesOpen, pasteCodeInEditor, renameFile, editorTextMatches } =
|
||||
await getUtils(page, test)
|
||||
@ -142,7 +142,7 @@ test.describe('when using the file tree to', () => {
|
||||
|
||||
test(
|
||||
`create many new files of the same name, incrementing their names`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
const { panesOpen, createNewFile } = await getUtils(page, test)
|
||||
|
||||
@ -174,7 +174,7 @@ test.describe('when using the file tree to', () => {
|
||||
|
||||
test(
|
||||
'create a new file with the same name as an existing file cancels the operation',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, homePage, scene, editor, toolbar }, testInfo) => {
|
||||
const projectName = 'cube'
|
||||
const mainFile = 'main.kcl'
|
||||
@ -238,9 +238,29 @@ test.describe('when using the file tree to', () => {
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
`create new folders and that doesn't trigger a navigation`,
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({ page, homePage, scene, toolbar, cmdBar }) => {
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.openPane('files')
|
||||
const { createNewFolder } = await getUtils(page, test)
|
||||
|
||||
await createNewFolder('folder')
|
||||
|
||||
await createNewFolder('folder.kcl')
|
||||
|
||||
await test.step(`Postcondition: folders are created and we didn't navigate`, async () => {
|
||||
await toolbar.expectFileTreeState(['folder', 'folder.kcl', 'main.kcl'])
|
||||
await expect(toolbar.fileName).toHaveText('main.kcl')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'deleting all files recreates a default main.kcl with no code',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
const { panesOpen, pasteCodeInEditor, deleteFile, editorTextMatches } =
|
||||
await getUtils(page, test)
|
||||
@ -271,7 +291,7 @@ test.describe('when using the file tree to', () => {
|
||||
test(
|
||||
'loading small file, then large, then back to small',
|
||||
{
|
||||
tag: '@electron',
|
||||
tag: '@desktop',
|
||||
},
|
||||
async ({ page }, testInfo) => {
|
||||
const {
|
||||
@ -341,7 +361,7 @@ test.describe('when using the file tree to', () => {
|
||||
test.describe('Renaming in the file tree', () => {
|
||||
test(
|
||||
'A file you have open',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -430,7 +450,7 @@ test.describe('Renaming in the file tree', () => {
|
||||
|
||||
test(
|
||||
'A file you do not have open',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -516,7 +536,7 @@ test.describe('Renaming in the file tree', () => {
|
||||
|
||||
test(
|
||||
`A folder you're not inside`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -598,7 +618,7 @@ test.describe('Renaming in the file tree', () => {
|
||||
|
||||
test(
|
||||
`A folder you are inside`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, context }, testInfo) => {
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -701,7 +721,7 @@ test.describe('Renaming in the file tree', () => {
|
||||
test.describe('Deleting items from the file pane', () => {
|
||||
test(
|
||||
`delete file when main.kcl exists, navigate to main.kcl`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, context }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = join(dir, 'testProject')
|
||||
@ -766,7 +786,7 @@ test.describe('Deleting items from the file pane', () => {
|
||||
|
||||
test(
|
||||
`Delete folder we are not in, don't navigate`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -820,7 +840,7 @@ test.describe('Deleting items from the file pane', () => {
|
||||
|
||||
test(
|
||||
`Delete folder we are in, navigate to main.kcl`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
|
||||
@ -886,7 +906,7 @@ test.describe('Deleting items from the file pane', () => {
|
||||
// Copied from tests above.
|
||||
test(
|
||||
`external deletion of project navigates back home`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const TEST_PROJECT_NAME = 'Test Project'
|
||||
const { dir: projectsDirName } = await context.folderSetupFn(
|
||||
@ -950,7 +970,7 @@ test.describe('Deleting items from the file pane', () => {
|
||||
// Similar to the above
|
||||
test(
|
||||
`external deletion of file in sub-directory updates the file tree and recreates it on code editor typing`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const TEST_PROJECT_NAME = 'Test Project'
|
||||
const { dir: projectsDirName } = await context.folderSetupFn(
|
||||
@ -1025,7 +1045,7 @@ test.describe('Deleting items from the file pane', () => {
|
||||
test.describe('Undo and redo do not keep history when navigating between files', () => {
|
||||
test(
|
||||
`open a file, change something, open a different file, hitting undo should do nothing`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = join(dir, 'testProject')
|
||||
@ -1092,7 +1112,7 @@ test.describe('Undo and redo do not keep history when navigating between files',
|
||||
|
||||
test(
|
||||
`open a file, change something, undo it, open a different file, hitting redo should do nothing`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = join(dir, 'testProject')
|
||||
@ -1192,7 +1212,7 @@ test.describe('Undo and redo do not keep history when navigating between files',
|
||||
|
||||
test(
|
||||
`cloned file has an incremented name and same contents`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, context, homePage }, testInfo) => {
|
||||
const { panesOpen, cloneFile } = await getUtils(page, test)
|
||||
|
||||
|
@ -105,14 +105,19 @@ export class CmdBarFixture {
|
||||
expectState = async (expected: CmdBarSerialised) => {
|
||||
return expect.poll(() => this._serialiseCmdBar()).toEqual(expected)
|
||||
}
|
||||
/** The method will use buttons OR press enter randomly to progress the cmdbar,
|
||||
* this could have unexpected results depending on what's focused
|
||||
*
|
||||
* TODO: This method assumes the user has a valid input to the current stage,
|
||||
/**
|
||||
* This method is used to progress the command bar to the next step, defaulting to clicking the next button.
|
||||
* Optionally, with the `shouldUseKeyboard` parameter, it will hit `Enter` to progress.
|
||||
* * TODO: This method assumes the user has a valid input to the current stage,
|
||||
* and assumes we are past the `pickCommand` step.
|
||||
*/
|
||||
progressCmdBar = async (shouldFuzzProgressMethod = true) => {
|
||||
progressCmdBar = async (shouldUseKeyboard = false) => {
|
||||
await this.page.waitForTimeout(2000)
|
||||
if (shouldUseKeyboard) {
|
||||
await this.page.keyboard.press('Enter')
|
||||
return
|
||||
}
|
||||
|
||||
const arrowButton = this.page.getByRole('button', {
|
||||
name: 'arrow right Continue',
|
||||
})
|
||||
@ -146,15 +151,19 @@ export class CmdBarFixture {
|
||||
await this.cmdBarOpenBtn.click()
|
||||
await expect(this.page.getByPlaceholder('Search commands')).toBeVisible()
|
||||
if (selectCmd === 'promptToEdit') {
|
||||
const promptEditCommand = this.page.getByText(
|
||||
'Use Zoo AI to edit your parts and code.'
|
||||
)
|
||||
const promptEditCommand = this.selectOption({ name: 'Text-to-CAD Edit' })
|
||||
await expect(promptEditCommand.first()).toBeVisible()
|
||||
await promptEditCommand.first().scrollIntoViewIfNeeded()
|
||||
await promptEditCommand.first().click()
|
||||
}
|
||||
}
|
||||
|
||||
closeCmdBar = async () => {
|
||||
const cmdBarCloseBtn = this.page.getByTestId('command-bar-close-button')
|
||||
await cmdBarCloseBtn.click()
|
||||
await expect(this.cmdBarElement).not.toBeVisible()
|
||||
}
|
||||
|
||||
get cmdSearchInput() {
|
||||
return this.page.getByTestId('cmd-bar-search')
|
||||
}
|
||||
@ -298,4 +307,32 @@ export class CmdBarFixture {
|
||||
`Monitoring text-to-cad API requests. Output will be saved to: ${outputPath}`
|
||||
)
|
||||
}
|
||||
|
||||
async toBeOpened() {
|
||||
// Check that the command bar is opened
|
||||
await expect(this.cmdBarElement).toBeVisible({ timeout: 10_000 })
|
||||
}
|
||||
|
||||
async toBeClosed() {
|
||||
// Check that the command bar is closed
|
||||
await expect(this.cmdBarElement).not.toBeVisible({ timeout: 10_000 })
|
||||
}
|
||||
|
||||
async expectArgValue(value: string) {
|
||||
// Check the placeholder project name exists
|
||||
const actualArgument = await this.cmdBarElement
|
||||
.getByTestId('cmd-bar-arg-value')
|
||||
.inputValue()
|
||||
const expectedArgument = value
|
||||
expect(actualArgument).toBe(expectedArgument)
|
||||
}
|
||||
|
||||
async expectCommandName(value: string) {
|
||||
// Check the placeholder project name exists
|
||||
const actual = await this.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const expected = value
|
||||
expect(actual).toBe(expected)
|
||||
}
|
||||
}
|
||||
|
@ -394,7 +394,7 @@ const fixturesBasedOnProcessEnvPlatform = {
|
||||
},
|
||||
}
|
||||
|
||||
if (process.env.PLATFORM === 'web') {
|
||||
if (process.env.TARGET === 'web') {
|
||||
Object.assign(fixturesBasedOnProcessEnvPlatform, fixturesForWeb)
|
||||
} else {
|
||||
Object.assign(fixturesBasedOnProcessEnvPlatform, fixturesForElectron)
|
||||
|
@ -24,7 +24,9 @@ export class HomePageFixture {
|
||||
projectTextName!: Locator
|
||||
sortByDateBtn!: Locator
|
||||
sortByNameBtn!: Locator
|
||||
appHeader!: Locator
|
||||
tutorialBtn!: Locator
|
||||
textToCadBtn!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
@ -44,7 +46,9 @@ export class HomePageFixture {
|
||||
|
||||
this.sortByDateBtn = this.page.getByTestId('home-sort-by-modified')
|
||||
this.sortByNameBtn = this.page.getByTestId('home-sort-by-name')
|
||||
this.appHeader = this.page.getByTestId('app-header')
|
||||
this.tutorialBtn = this.page.getByTestId('home-tutorial-button')
|
||||
this.textToCadBtn = this.page.getByTestId('home-text-to-cad')
|
||||
}
|
||||
|
||||
private _serialiseSortBy = async (): Promise<
|
||||
@ -119,10 +123,19 @@ export class HomePageFixture {
|
||||
await projectCard.click()
|
||||
}
|
||||
|
||||
goToModelingScene = async (name: string = 'testDefault') => {
|
||||
/** Returns the project name in case caller has used the default and needs it */
|
||||
goToModelingScene = async (name = 'testDefault') => {
|
||||
// On web this is a no-op. There is no project view.
|
||||
if (process.env.PLATFORM === 'web') return
|
||||
if (process.env.TARGET === 'web') return ''
|
||||
|
||||
await this.createAndGoToProject(name)
|
||||
return name
|
||||
}
|
||||
|
||||
isNativeFileMenuCreated = async () => {
|
||||
await expect(this.appHeader).toHaveAttribute(
|
||||
'data-native-file-menu',
|
||||
'true'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ export class SceneFixture {
|
||||
public networkToggleConnected!: Locator
|
||||
public engineConnectionsSpinner!: Locator
|
||||
public startEditSketchBtn!: Locator
|
||||
public appHeader!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
@ -57,6 +58,7 @@ export class SceneFixture {
|
||||
this.startEditSketchBtn = page
|
||||
.getByRole('button', { name: 'Start Sketch' })
|
||||
.or(page.getByRole('button', { name: 'Edit Sketch' }))
|
||||
this.appHeader = this.page.getByTestId('app-header')
|
||||
}
|
||||
private _serialiseScene = async (): Promise<SceneSerialised> => {
|
||||
const camera = await this.getCameraInfo()
|
||||
@ -280,6 +282,13 @@ export class SceneFixture {
|
||||
await expect(buttonToTest).toBeVisible()
|
||||
await buttonToTest.click()
|
||||
}
|
||||
|
||||
isNativeFileMenuCreated = async () => {
|
||||
await expect(this.appHeader).toHaveAttribute(
|
||||
'data-native-file-menu',
|
||||
'true'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function isColourArray(
|
||||
|
@ -5,7 +5,7 @@ import * as fsp from 'fs/promises'
|
||||
test.describe('Import UI tests', () => {
|
||||
test(
|
||||
'shows toast when trying to sketch on imported face, and hovering over imported geometry should NOT highlight any code',
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({ context, page, homePage, toolbar, scene, editor, cmdBar }) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const projectDir = path.join(dir, 'import-test')
|
||||
|
@ -61,6 +61,7 @@ class MyAPIReporter implements Reporter {
|
||||
const payload = {
|
||||
// Required information
|
||||
project: 'https://github.com/KittyCAD/modeling-app',
|
||||
suite: process.env.CI_SUITE || 'e2e',
|
||||
branch: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || '',
|
||||
commit: process.env.CI_COMMIT_SHA || process.env.GITHUB_SHA || '',
|
||||
test: test.titlePath().slice(2).join(' › '),
|
||||
|
@ -6,7 +6,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test(
|
||||
'When machine-api server not found butt is disabled and shows the reason',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'bracket')
|
||||
@ -43,7 +43,7 @@ test(
|
||||
|
||||
test(
|
||||
'When machine-api server not found home screen & project status shows the reason',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'bracket')
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,6 @@ test.describe('Onboarding tests', () => {
|
||||
homePage,
|
||||
toolbar,
|
||||
editor,
|
||||
scene,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
@ -62,7 +61,6 @@ test.describe('Onboarding tests', () => {
|
||||
await editor.expectEditor.toContain('@settings(defaultLengthUnit = in)', {
|
||||
shouldNormalise: true,
|
||||
})
|
||||
await scene.connectionEstablished()
|
||||
})
|
||||
|
||||
await test.step('Go home and verify we still see the tutorial button, then begin it.', async () => {
|
||||
@ -132,9 +130,7 @@ test.describe('Onboarding tests', () => {
|
||||
})
|
||||
|
||||
await test.step('Dismiss the onboarding', async () => {
|
||||
await postDismissToast.waitFor({ state: 'hidden' })
|
||||
await page.keyboard.press('Escape')
|
||||
await expect(postDismissToast).toBeVisible()
|
||||
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
||||
await expect.poll(() => page.url()).not.toContain('/onboarding')
|
||||
})
|
||||
@ -162,13 +158,10 @@ test.describe('Onboarding tests', () => {
|
||||
await test.step('Gets to the onboarding start', async () => {
|
||||
await expect(toolbar.projectName).toContainText('tutorial-project')
|
||||
await expect(tutorialWelcomeHeading).toBeVisible()
|
||||
await scene.connectionEstablished()
|
||||
})
|
||||
|
||||
await test.step('Dismiss the onboarding', async () => {
|
||||
await postDismissToast.waitFor({ state: 'hidden' })
|
||||
await page.keyboard.press('Escape')
|
||||
await expect(postDismissToast).toBeVisible()
|
||||
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
||||
await expect.poll(() => page.url()).not.toContain('/onboarding')
|
||||
})
|
||||
|
@ -43,7 +43,7 @@ async function insertPartIntoAssembly(
|
||||
test.describe('Point-and-click assemblies tests', () => {
|
||||
test(
|
||||
`Insert kcl parts into assembly as whole module import`,
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({
|
||||
context,
|
||||
page,
|
||||
@ -70,22 +70,28 @@ test.describe('Point-and-click assemblies tests', () => {
|
||||
await test.step('Setup parts and expect empty assembly scene', async () => {
|
||||
const projectName = 'assembly'
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, projectName)
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
const projDir = path.join(dir, projectName)
|
||||
const nestedProjDir = path.join(dir, projectName, 'nested', 'twice')
|
||||
await fsp.mkdir(projDir, { recursive: true })
|
||||
await fsp.mkdir(nestedProjDir, { recursive: true })
|
||||
await Promise.all([
|
||||
fsp.copyFile(
|
||||
executorInputPath('cylinder.kcl'),
|
||||
path.join(bracketDir, 'cylinder.kcl')
|
||||
path.join(projDir, 'cylinder.kcl')
|
||||
),
|
||||
fsp.copyFile(
|
||||
executorInputPath('cylinder.kcl'),
|
||||
path.join(nestedProjDir, 'main.kcl')
|
||||
),
|
||||
fsp.copyFile(
|
||||
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
|
||||
path.join(bracketDir, 'bracket.kcl')
|
||||
path.join(projDir, 'bracket.kcl')
|
||||
),
|
||||
fsp.copyFile(
|
||||
testsInputPath('cube.step'),
|
||||
path.join(bracketDir, 'cube.step')
|
||||
path.join(projDir, 'cube.step')
|
||||
),
|
||||
fsp.writeFile(path.join(bracketDir, 'main.kcl'), ''),
|
||||
fsp.writeFile(path.join(projDir, 'main.kcl'), ''),
|
||||
])
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
@ -167,13 +173,32 @@ test.describe('Point-and-click assemblies tests', () => {
|
||||
await expect(
|
||||
page.getByText('This file is already imported')
|
||||
).toBeVisible()
|
||||
await cmdBar.closeCmdBar()
|
||||
})
|
||||
|
||||
await test.step('Insert a nested kcl part', async () => {
|
||||
await insertPartIntoAssembly(
|
||||
'nested/twice/main.kcl',
|
||||
'main',
|
||||
toolbar,
|
||||
cmdBar,
|
||||
page
|
||||
)
|
||||
await toolbar.openPane('code')
|
||||
await page.waitForTimeout(10000)
|
||||
await editor.expectEditor.toContain(
|
||||
`
|
||||
import "nested/twice/main.kcl" as main
|
||||
`,
|
||||
{ shouldNormalise: true }
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
`Can still translate, rotate, and delete inserted parts even with non standard code`,
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({
|
||||
context,
|
||||
page,
|
||||
@ -369,7 +394,7 @@ test.describe('Point-and-click assemblies tests', () => {
|
||||
|
||||
test(
|
||||
`Insert the bracket part into an assembly and transform it`,
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({
|
||||
context,
|
||||
page,
|
||||
@ -560,7 +585,7 @@ test.describe('Point-and-click assemblies tests', () => {
|
||||
|
||||
test(
|
||||
`Insert foreign parts into assembly and delete them`,
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({
|
||||
context,
|
||||
page,
|
||||
@ -711,7 +736,7 @@ test.describe('Point-and-click assemblies tests', () => {
|
||||
|
||||
test(
|
||||
'Assembly gets reexecuted when imported models are updated externally',
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({ context, page, homePage, scene, toolbar, cmdBar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
@ -801,7 +826,7 @@ foreign
|
||||
|
||||
test(
|
||||
`Point-and-click clone`,
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({
|
||||
context,
|
||||
page,
|
||||
|
@ -78,8 +78,8 @@ test.describe('Point-and-click tests', () => {
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: { Sketches: '', Length: '' },
|
||||
highlightedHeaderArg: 'sketches',
|
||||
headerArguments: { Profiles: '', Length: '' },
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Extrude',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -87,7 +87,7 @@ test.describe('Point-and-click tests', () => {
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'length',
|
||||
currentArgValue: '5',
|
||||
headerArguments: { Sketches: '1 face', Length: '' },
|
||||
headerArguments: { Profiles: '1 profile', Length: '' },
|
||||
highlightedHeaderArg: 'length',
|
||||
commandName: 'Extrude',
|
||||
})
|
||||
@ -98,7 +98,7 @@ test.describe('Point-and-click tests', () => {
|
||||
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: { Sketches: '1 face', Length: '5' },
|
||||
headerArguments: { Profiles: '1 profile', Length: '5' },
|
||||
commandName: 'Extrude',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -1634,15 +1634,15 @@ sketch002 = startSketchOn(plane001)
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: { Sketches: '' },
|
||||
highlightedHeaderArg: 'sketches',
|
||||
headerArguments: { Profiles: '' },
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Loft',
|
||||
})
|
||||
await selectSketches()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: { Sketches: '2 faces' },
|
||||
headerArguments: { Profiles: '2 profiles' },
|
||||
commandName: 'Loft',
|
||||
})
|
||||
await cmdBar.submit()
|
||||
@ -1658,14 +1658,14 @@ sketch002 = startSketchOn(plane001)
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: { Sketches: '' },
|
||||
highlightedHeaderArg: 'sketches',
|
||||
headerArguments: { Profiles: '' },
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Loft',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: { Sketches: '2 faces' },
|
||||
headerArguments: { Profiles: '2 profiles' },
|
||||
commandName: 'Loft',
|
||||
})
|
||||
await cmdBar.submit()
|
||||
@ -1766,7 +1766,7 @@ loft001 = loft([sketch001, sketch002])
|
||||
sketch001 = startSketchOn(YZ)
|
||||
profile001 = circle(sketch001, center = [0, 0], radius = 500)
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
profile002 = startProfile(sketch002, at = [0, 0])
|
||||
|> xLine(length = -500)
|
||||
|> tangentialArc(endAbsolute = [-2000, 500])`,
|
||||
},
|
||||
@ -1782,7 +1782,7 @@ profile001 = startProfile(sketch001, at = [-400, -400])
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
profile002 = startProfile(sketch002, at = [0, 0])
|
||||
|> xLine(length = -500)
|
||||
|> tangentialArc(endAbsolute = [-2000, 500])`,
|
||||
},
|
||||
@ -1810,9 +1810,9 @@ sketch002 = startSketchOn(XZ)
|
||||
testPoint.x - 50,
|
||||
testPoint.y
|
||||
)
|
||||
const sweepDeclaration = 'sweep001 = sweep(profile001, path = sketch002)'
|
||||
const sweepDeclaration = 'sweep001 = sweep(profile001, path = profile002)'
|
||||
const editedSweepDeclaration =
|
||||
'sweep001 = sweep(profile001, path = sketch002, sectional = true)'
|
||||
'sweep001 = sweep(profile001, path = profile002, sectional = true)'
|
||||
|
||||
await test.step(`Look for sketch001`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
@ -1830,10 +1830,10 @@ sketch002 = startSketchOn(XZ)
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
stage: 'arguments',
|
||||
})
|
||||
await clickOnSketch1()
|
||||
@ -1844,7 +1844,7 @@ sketch002 = startSketchOn(XZ)
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'path',
|
||||
@ -1857,7 +1857,7 @@ sketch002 = startSketchOn(XZ)
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'path',
|
||||
@ -1867,13 +1867,17 @@ sketch002 = startSketchOn(XZ)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
headerArguments: {
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Path: '1 segment',
|
||||
Sectional: '',
|
||||
},
|
||||
stage: 'review',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
// Confirm we can submit from the review step with just `Enter`
|
||||
await cmdBar.progressCmdBar(true)
|
||||
await cmdBar.expectState({
|
||||
stage: 'commandBarClosed',
|
||||
})
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
@ -1931,63 +1935,51 @@ sketch002 = startSketchOn(XZ)
|
||||
})
|
||||
})
|
||||
|
||||
test(`Sweep point-and-click failing validation`, async ({
|
||||
test(`Sweep point-and-click helix`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `@settings(defaultLengthUnit = in)
|
||||
sketch001 = startSketchOn(YZ)
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = 500
|
||||
)
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> xLine(length = -500)
|
||||
|> line(endAbsolute = [-2000, 500])
|
||||
`
|
||||
const circleCode = `circle(sketch001, center = [0, -1], radius = .1)`
|
||||
const initialCode = `helix001 = helix(
|
||||
axis = X,
|
||||
radius = 1,
|
||||
length = 10,
|
||||
revolutions = 10,
|
||||
angleStart = 0,
|
||||
ccw = false,
|
||||
)
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = ${circleCode}`
|
||||
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
|
||||
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 700, y: 250 }
|
||||
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const [clickOnSketch2] = scene.makeMouseHelpers(
|
||||
testPoint.x - 50,
|
||||
testPoint.y
|
||||
)
|
||||
|
||||
await test.step(`Look for sketch001`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
await scene.expectPixelColor([53, 53, 53], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step(`Go through the command bar flow and fail validation with a toast`, async () => {
|
||||
await test.step(`Add sweep through the command bar flow`, async () => {
|
||||
await toolbar.openPane('feature-tree')
|
||||
await toolbar.sweepButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
stage: 'arguments',
|
||||
})
|
||||
await clickOnSketch1()
|
||||
await editor.scrollToText(circleCode)
|
||||
await page.getByText(circleCode).click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
@ -1995,17 +1987,45 @@ sketch002 = startSketchOn(XZ)
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Sketches: '1 face',
|
||||
Profiles: '1 profile',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'path',
|
||||
stage: 'arguments',
|
||||
})
|
||||
const helix = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||
await helix.click()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
currentArgKey: 'path',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sectional: '',
|
||||
Profiles: '1 profile',
|
||||
Path: '',
|
||||
},
|
||||
highlightedHeaderArg: 'path',
|
||||
stage: 'arguments',
|
||||
})
|
||||
await clickOnSketch2()
|
||||
await cmdBar.progressCmdBar()
|
||||
await expect(
|
||||
page.getByText('Unable to sweep with the current selection. Reason:')
|
||||
).toBeVisible()
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
headerArguments: {
|
||||
Profiles: '1 profile',
|
||||
Path: '1 helix',
|
||||
Sectional: '',
|
||||
},
|
||||
stage: 'review',
|
||||
})
|
||||
await cmdBar.progressCmdBar(true)
|
||||
await editor.expectEditor.toContain(sweepDeclaration)
|
||||
})
|
||||
|
||||
await test.step('Delete sweep via feature tree selection', async () => {
|
||||
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
|
||||
await sweep.click()
|
||||
await page.keyboard.press('Delete')
|
||||
await editor.expectEditor.not.toContain(sweepDeclaration)
|
||||
})
|
||||
})
|
||||
|
||||
@ -3627,67 +3647,6 @@ profile001 = startProfile(sketch001, at = [-20, 20])
|
||||
})
|
||||
})
|
||||
|
||||
test(`Shell dry-run validation rejects sweeps`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn(YZ)
|
||||
|> circle(
|
||||
center = [0, 0],
|
||||
radius = 500
|
||||
)
|
||||
sketch002 = startSketchOn(XZ)
|
||||
|> startProfile(at = [0, 0])
|
||||
|> xLine(length = -2000)
|
||||
sweep001 = sweep(sketch001, path = sketch002)
|
||||
`
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 500, y: 250 }
|
||||
const [clickOnSweep] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
|
||||
await test.step(`Confirm sweep exists`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
await scene.expectPixelColor([231, 231, 231], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step(`Go through the Shell flow and fail validation with a toast`, async () => {
|
||||
await toolbar.shellButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Selection: '',
|
||||
Thickness: '',
|
||||
},
|
||||
highlightedHeaderArg: 'selection',
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await clickOnSweep()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await expect(
|
||||
page.getByText('Unable to shell with the current selection. Reason:')
|
||||
).toBeVisible()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Revolve point and click workflows', () => {
|
||||
test('Base case workflow, auto spam continue in command bar', async ({
|
||||
context,
|
||||
@ -3736,7 +3695,7 @@ tag=$rectangleSegmentC002,
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// select line of code
|
||||
const codeToSelection = `segAng(rectangleSegmentA002) - 90,`
|
||||
const codeToSelection = `startProfile(at = [-66.77, 84.81])`
|
||||
// revolve
|
||||
await editor.scrollToText(codeToSelection)
|
||||
await page.getByText(codeToSelection).click()
|
||||
@ -4679,10 +4638,10 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
Length: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Extrude',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -4691,7 +4650,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'length',
|
||||
currentArgValue: '5',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
Length: '',
|
||||
},
|
||||
highlightedHeaderArg: 'length',
|
||||
@ -4702,7 +4661,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
Length: '1',
|
||||
},
|
||||
commandName: 'Extrude',
|
||||
@ -4773,11 +4732,11 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
Path: '',
|
||||
Sectional: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Sweep',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -4786,7 +4745,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'path',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
Path: '',
|
||||
Sectional: '',
|
||||
},
|
||||
@ -4799,7 +4758,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
Path: '1 segment',
|
||||
Sectional: '',
|
||||
},
|
||||
@ -4870,11 +4829,11 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'sketches',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '',
|
||||
Profiles: '',
|
||||
AxisOrEdge: '',
|
||||
Angle: '',
|
||||
},
|
||||
highlightedHeaderArg: 'sketches',
|
||||
highlightedHeaderArg: 'Profiles',
|
||||
commandName: 'Revolve',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -4883,7 +4842,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'axisOrEdge',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
AxisOrEdge: '',
|
||||
Angle: '',
|
||||
},
|
||||
@ -4899,7 +4858,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
currentArgKey: 'angle',
|
||||
currentArgValue: '360',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
AxisOrEdge: 'Edge',
|
||||
Edge: '1 segment',
|
||||
Angle: '',
|
||||
@ -4912,7 +4871,7 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Sketches: '2 faces',
|
||||
Profiles: '2 profiles',
|
||||
AxisOrEdge: 'Edge',
|
||||
Edge: '1 segment',
|
||||
Angle: '180',
|
||||
@ -4943,4 +4902,34 @@ path001 = startProfile(sketch001, at = [0, 0])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test(`Point and click codemods can't run on KCL errors`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const badCode = `sketch001 = startSketchOn(XZ)
|
||||
profile001 = circle(sketch001, center = [0, 0], radius = 1)
|
||||
extrude001 = extrude(profile001 length = 1)`
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, badCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
await test.step(`Start Sketch is disabled`, async () => {
|
||||
await expect(toolbar.startSketchBtn).not.toBeEnabled()
|
||||
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
|
||||
})
|
||||
|
||||
await test.step(`Helix is disabled`, async () => {
|
||||
await expect(toolbar.helixButton).not.toBeEnabled()
|
||||
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -11,12 +11,13 @@ import {
|
||||
getPlaywrightDownloadDir,
|
||||
getUtils,
|
||||
isOutOfViewInScrollContainer,
|
||||
runningOnWindows,
|
||||
} from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test(
|
||||
'projects reload if a new one is created, deleted, or renamed externally',
|
||||
{ tag: ['@electron', '@macos', '@windows'] },
|
||||
{ tag: ['@desktop', '@macos', '@windows'] },
|
||||
async ({ context, page }, testInfo) => {
|
||||
let externalCreatedProjectName = 'external-created-project'
|
||||
|
||||
@ -62,7 +63,7 @@ test(
|
||||
|
||||
test(
|
||||
'click help/keybindings from home page',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
@ -80,7 +81,7 @@ test(
|
||||
|
||||
test(
|
||||
'click help/keybindings from project page',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
@ -111,7 +112,7 @@ test(
|
||||
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in different project with errors, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page, editor }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
@ -183,7 +184,7 @@ test(
|
||||
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in different project that is empty, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
@ -243,7 +244,7 @@ test(
|
||||
|
||||
test(
|
||||
'open a file in a project works and renders, open empty file, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
@ -309,7 +310,7 @@ test(
|
||||
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in the same project with errors, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
@ -381,7 +382,7 @@ test(
|
||||
|
||||
test(
|
||||
'when code with error first loads you get errors in console',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, editor }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(path.join(dir, 'broken-code'), { recursive: true })
|
||||
@ -415,7 +416,7 @@ test.describe('Can export from electron app', () => {
|
||||
for (const method of exportMethods) {
|
||||
test(
|
||||
`Can export using ${method}`,
|
||||
{ tag: ['@electron', '@skipLocalEngine'] },
|
||||
{ tag: ['@desktop', '@skipLocalEngine'] },
|
||||
async ({ scene, cmdBar, context, page, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
@ -506,7 +507,7 @@ test.describe('Can export from electron app', () => {
|
||||
})
|
||||
test(
|
||||
'Rename and delete projects, also spam arrow keys when renaming',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/router-template-slate`, { recursive: true })
|
||||
@ -722,7 +723,7 @@ test(
|
||||
|
||||
test(
|
||||
'pressing "delete" on home screen should do nothing',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, homePage }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/router-template-slate`, { recursive: true })
|
||||
@ -752,7 +753,7 @@ test(
|
||||
test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Rename from project page`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_rename`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -814,7 +815,7 @@ test.describe(`Project management commands`, () => {
|
||||
|
||||
test(
|
||||
`Delete from project page`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_delete`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -868,7 +869,7 @@ test.describe(`Project management commands`, () => {
|
||||
)
|
||||
test(
|
||||
`Rename from home page`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, homePage, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_rename`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -926,7 +927,7 @@ test.describe(`Project management commands`, () => {
|
||||
)
|
||||
test(
|
||||
`Delete from home page`,
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_delete`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -1102,7 +1103,7 @@ test(`Create a few projects using the default project name`, async ({
|
||||
|
||||
test(
|
||||
'File in the file pane should open with a single click',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, homePage, page }, testInfo) => {
|
||||
const projectName = 'router-template-slate'
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -1144,7 +1145,7 @@ test(
|
||||
|
||||
test(
|
||||
'Nested directories in project without main.kcl do not create main.kcl',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
let testDir: string | undefined
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
@ -1201,7 +1202,7 @@ test(
|
||||
|
||||
test(
|
||||
'Deleting projects, can delete individual project, can still create projects after deleting all',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const projectData = [
|
||||
['router-template-slate', 'cylinder.kcl'],
|
||||
@ -1279,7 +1280,7 @@ test(
|
||||
|
||||
test(
|
||||
'Can load a file with CRLF line endings',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const routerTemplateDir = path.join(dir, 'router-template-slate')
|
||||
@ -1311,7 +1312,7 @@ test(
|
||||
|
||||
test(
|
||||
'Can sort projects on home page',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const projectData = [
|
||||
['router-template-slate', 'cylinder.kcl'],
|
||||
@ -1418,7 +1419,7 @@ test(
|
||||
|
||||
test(
|
||||
'When the project folder is empty, user can create new project and open it.',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page }, testInfo) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
@ -1514,7 +1515,7 @@ extrude001 = extrude(sketch001, length = 200)`)
|
||||
|
||||
test(
|
||||
'Opening a project should successfully load the stream, (regression test that this also works when switching between projects)',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, cmdBar, homePage, scene }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(path.join(dir, 'router-template-slate'), {
|
||||
@ -1627,7 +1628,7 @@ test(
|
||||
|
||||
test(
|
||||
'You can change the root projects directory and nothing is lost',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page, tronApp, homePage }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
@ -1734,7 +1735,7 @@ test(
|
||||
|
||||
test(
|
||||
'Search projects on desktop home',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
const projectData = [
|
||||
['basic bracket', 'focusrite_scarlett_mounting_bracket.kcl'],
|
||||
@ -1790,7 +1791,7 @@ test(
|
||||
|
||||
test(
|
||||
'file pane is scrollable when there are many files',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = path.join(dir, 'testProject')
|
||||
@ -1891,7 +1892,7 @@ test(
|
||||
|
||||
test(
|
||||
'select all in code editor does not actually select all, just what is visible (regression)',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
// rust/kcl-lib/e2e/executor/inputs/mike_stress_test.kcl
|
||||
@ -1949,7 +1950,7 @@ test(
|
||||
|
||||
test(
|
||||
'Settings persist across restarts',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
await test.step('We can change a user setting like theme', async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
@ -1979,10 +1980,9 @@ test(
|
||||
}
|
||||
)
|
||||
|
||||
// Flaky
|
||||
test(
|
||||
'Original project name persist after onboarding',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ page, toolbar }, testInfo) => {
|
||||
const nextButton = page.getByTestId('onboarding-next')
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
@ -2022,7 +2022,7 @@ test(
|
||||
|
||||
test(
|
||||
'project name with foreign characters should open',
|
||||
{ tag: '@electron' },
|
||||
{ tag: '@desktop' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'العربية')
|
||||
@ -2064,3 +2064,126 @@ test(
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'import from nested directory',
|
||||
{ tag: ['@desktop', '@windows', '@macos'] },
|
||||
async ({ scene, cmdBar, context, page }) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
const nestedDir = path.join(bracketDir, 'nested')
|
||||
await fsp.mkdir(nestedDir, { recursive: true })
|
||||
|
||||
await fsp.copyFile(
|
||||
executorInputPath('cylinder-inches.kcl'),
|
||||
path.join(nestedDir, 'main.kcl')
|
||||
)
|
||||
await fsp.writeFile(
|
||||
path.join(bracketDir, 'main.kcl'),
|
||||
runningOnWindows()
|
||||
? `import 'nested\\main.kcl' as thing\n\nthing`
|
||||
: `import 'nested/main.kcl' as thing\n\nthing`
|
||||
)
|
||||
})
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
const u = await getUtils(page)
|
||||
|
||||
const pointOnModel = { x: 630, y: 280 }
|
||||
|
||||
await test.step('Opening the bracket project should load the stream', async () => {
|
||||
// expect to see the text bracket
|
||||
await expect(page.getByText('bracket')).toBeVisible()
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).toBeEnabled({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'segment position changes persist after dragging and reopening project',
|
||||
{ tag: '@desktop' },
|
||||
async ({ scene, cmdBar, context, page, editor, toolbar }, testInfo) => {
|
||||
const projectName = 'segment-drag-test'
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const projectDir = path.join(dir, projectName)
|
||||
await fsp.mkdir(projectDir, { recursive: true })
|
||||
await fsp.writeFile(
|
||||
path.join(projectDir, 'main.kcl'),
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
profile001 = startProfile(sketch001, at = [0, 0])
|
||||
|> line(end = [0, 6])
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [-8, -5])
|
||||
`
|
||||
)
|
||||
})
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 600 })
|
||||
const u = await getUtils(page)
|
||||
|
||||
await test.step('Opening the project and entering sketch mode', async () => {
|
||||
await expect(page.getByText(projectName)).toBeVisible()
|
||||
await page.getByText(projectName).click()
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// go to sketch mode
|
||||
await (await toolbar.getFeatureTreeOperation('Sketch', 0)).dblclick()
|
||||
|
||||
// Without this, "add axis n grid" action runs after editing the sketch and invokes codeManager.writeToFile()
|
||||
// so we wait for that action to run first before we start editing the sketch and making sure it's saving
|
||||
// because of those edits.
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
||||
const changedLine = 'line(end = [-6.54, -4.99])'
|
||||
|
||||
await test.step('Dragging the line endpoint to modify it', async () => {
|
||||
// Get the last line's endpoint position
|
||||
const lineEnd = await u.getBoundingBox('[data-overlay-index="3"]')
|
||||
|
||||
await page.mouse.move(lineEnd.x, lineEnd.y - 5)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(lineEnd.x + 80, lineEnd.y)
|
||||
await page.mouse.up()
|
||||
|
||||
await editor.expectEditor.toContain(changedLine)
|
||||
|
||||
// Exit sketch mode
|
||||
await page.keyboard.press('Escape')
|
||||
await page.waitForTimeout(100)
|
||||
})
|
||||
|
||||
await test.step('Going back to dashboard', async () => {
|
||||
await page.getByTestId('app-logo').click()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step('Reopening the project and verifying changes are saved', async () => {
|
||||
await page.getByText(projectName).click()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Check if new line coordinates were saved
|
||||
await editor.expectEditor.toContain(changedLine)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user