Compare commits

..

2 Commits

Author SHA1 Message Date
d453110768 Merge branch 'main' into franknoirot/adhoc/lengthen-code-timeout-onboarding-tests 2025-04-10 12:13:29 -04:00
c2e1b50bde Lengthen timeout for onboarding code to appear
These tests work without fail locally so I have to believe this is due
to some slowness in startup on MacOS.
2025-04-10 12:07:59 -04:00
826 changed files with 71690 additions and 135620 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM
skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.package-lock.json,**/package-lock.json,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo,./src/lib/machine-api.d.ts skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo

View File

@ -7,11 +7,11 @@ if [[ ! -f "test-results/.last-run.json" ]]; then
# If no last run artifact, than run Playwright normally # If no last run artifact, than run Playwright normally
echo "run playwright normally" echo "run playwright normally"
if [[ "$3" == *ubuntu* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron:ubuntu -- --shard=$1/$2 || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --shard=$1/$2 || true
elif [[ "$3" == *windows* ]]; then elif [[ "$3" == *windows* ]]; then
npm run test:playwright:electron:windows -- --shard=$1/$2 || true yarn test:playwright:electron:windows -- --shard=$1/$2 || true
elif [[ "$3" == *macos* ]]; then elif [[ "$3" == *macos* ]]; then
npm run test:playwright:electron:macos -- --shard=$1/$2 || true yarn test:playwright:electron:macos -- --shard=$1/$2 || true
else else
echo "Do not run Playwright. Unable to detect os runtime." echo "Do not run Playwright. Unable to detect os runtime."
exit 1 exit 1
@ -31,11 +31,11 @@ while [[ $retry -le $max_retries ]]; do
echo "retried=true" >>$GITHUB_OUTPUT echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry" echo "run playwright with last failed tests and retry $retry"
if [[ "$3" == *ubuntu* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:playwright:electron:ubuntu -- --last-failed || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --last-failed || true
elif [[ "$3" == *windows* ]]; then elif [[ "$3" == *windows* ]]; then
npm run test:playwright:electron:windows -- --last-failed || true yarn test:playwright:electron:windows -- --last-failed || true
elif [[ "$3" == *macos* ]]; then elif [[ "$3" == *macos* ]]; then
npm run test:playwright:electron:macos -- --last-failed || true yarn test:playwright:electron:macos -- --last-failed || true
else else
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run playwright. Unable to detect os runtime."
exit 1 exit 1

View File

@ -13,9 +13,9 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
run: npm install run: yarn
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
run: | run: |
@ -32,7 +32,7 @@ jobs:
with: with:
workspaces: rust workspaces: rust
- name: build wasm - name: build wasm
run: npm run build:wasm run: yarn build:wasm
# Upload the WASM bundle as an artifact # Upload the WASM bundle as an artifact

View File

@ -29,9 +29,9 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- id: filter - id: filter
name: Check for Rust changes name: Check for Rust changes
@ -90,20 +90,20 @@ jobs:
- name: Run build:wasm - name: Run build:wasm
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
run: "npm run build:wasm" run: "yarn build:wasm"
- name: Set nightly version, product name, release notes, and icons - name: Set nightly version, product name, release notes, and icons
if: ${{ env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
run: | run: |
export VERSION=${GITHUB_REF_NAME#nightly-v} export VERSION=${GITHUB_REF_NAME#nightly-v}
npm run files:set-version yarn files:set-version
npm run files:flip-to-nightly yarn files:flip-to-nightly
- name: Set release version - name: Set release version
if: ${{ env.IS_RELEASE == 'true' }} if: ${{ env.IS_RELEASE == 'true' }}
run: | run: |
export VERSION=${GITHUB_REF_NAME#v} export VERSION=${GITHUB_REF_NAME#v}
npm run files:set-version yarn files:set-version
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@ -172,9 +172,16 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' # Set this to npm, npm or pnpm. cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: npm install - name: yarn install
# Windows is picky sometimes and fails on fetch. Step takes about ~30s
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 2
max_attempts: 3
command: yarn install
- name: Prepare certificate and variables (Windows only) - name: Prepare certificate and variables (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }} if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
@ -200,20 +207,13 @@ jobs:
smctl.exe keypair ls smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe smksp_cert_sync.exe
smctl windows certsync
# This last line `smctl windows certsync` was added after windows codesign failures started happening
# with nightly-v25.4.10. It looks like `smksp_cert_sync.exe` used to do the sync to the local cert store,
# but stopped doing it overnight. This extra call that I randomly got from this azure-related doc page
# https://docs.digicert.com/en/digicert-keylocker/code-signing/sign-with-third-party-signing-tools/windows-applications/sign-azure-apps-with-signtool-using-ksp-library.html#sync-certificates--windows-only--618365
# seems to be doing that extra sync that we need for scripts/sign-win.js to work.
# TODO: we still need to make sign-win.js errors fail the workflow, see issue #6276
shell: cmd shell: cmd
- name: Build the app (debug) - name: Build the app (debug)
if: ${{ env.IS_RELEASE == 'false' && env.IS_NIGHTLY == 'false' }} if: ${{ env.IS_RELEASE == 'false' && env.IS_NIGHTLY == 'false' }}
# electron-builder doesn't have a concept of release vs debug, # electron-builder doesn't have a concept of release vs debug,
# this is just not doing any codesign or release yml generation, and points to dev infra # this is just not doing any codesign or release yml generation, and points to dev infra
run: npm run tronb:package:dev run: yarn tronb:package:dev
- name: Build the app (release) - name: Build the app (release)
if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
@ -226,7 +226,14 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }} WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: npm run tronb:package:prod DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod
- name: List artifacts in out/ - name: List artifacts in out/
run: ls -R out run: ls -R out
@ -281,7 +288,14 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }} WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: npm run tronb:package:prod DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }} if: ${{ env.IS_RELEASE == 'true' }}
@ -364,7 +378,7 @@ jobs:
NOTES: ${{ needs.prepare-files.outputs.notes }} NOTES: ${{ needs.prepare-files.outputs.notes }}
PUB_DATE: ${{ github.event.repository.updated_at }} PUB_DATE: ${{ github.event.repository.updated_at }}
WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }} WEBSITE_DIR: ${{ env.IS_NIGHTLY == 'true' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Design%20Studio%20%28Nightly%29' || 'Zoo%20Design%20Studio' }} URL_CODED_NAME: ${{ env.IS_NIGHTLY == 'true' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
run: | run: |
RELEASE_DIR=https://${WEBSITE_DIR} RELEASE_DIR=https://${WEBSITE_DIR}
jq --null-input \ jq --null-input \
@ -421,7 +435,7 @@ jobs:
export TAG="nightly-${VERSION}" export TAG="nightly-${VERSION}"
export PREVIOUS_TAG=$(git tag --list --sort=-committerdate "nightly-v[0-9]*" | head -n2 | tail -n1) export PREVIOUS_TAG=$(git tag --list --sort=-committerdate "nightly-v[0-9]*" | head -n2 | tail -n1)
export NOTES=$(./scripts/get-nightly-changelog.sh) export NOTES=$(./scripts/get-nightly-changelog.sh)
npm run files:set-notes yarn files:set-notes
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
if: ${{ env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
@ -446,4 +460,4 @@ jobs:
- name: Invalidate bucket cache on latest*.yml and last_download.json files - name: Invalidate bucket cache on latest*.yml and last_download.json files
if: ${{ env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
run: npm run files:invalidate-bucket:nightly run: yarn files:invalidate-bucket:nightly

View File

@ -5,7 +5,6 @@ on:
types: [opened, synchronize] types: [opened, synchronize]
paths: paths:
- 'src/lib/exampleKcl.ts' - 'src/lib/exampleKcl.ts'
- 'public/kcl-samples/bracket/main.kcl'
permissions: permissions:
contents: read contents: read
@ -23,11 +22,11 @@ jobs:
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:
script: | script: |
const message = '`public/kcl-samples/bracket/main.kcl` or `src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.'; const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
const issue_number = context.payload.pull_request.number; const issue_number = context.payload.pull_request.number;
const owner = context.repo.owner; const owner = context.repo.owner;
const repo = context.repo.repo; const repo = context.repo.repo;
const { data: comments } = await github.rest.issues.listComments({ const { data: comments } = await github.rest.issues.listComments({
owner, owner,
repo, repo,
@ -44,4 +43,4 @@ jobs:
issue_number, issue_number,
body: message, body: message,
}); });
} }

View File

@ -11,7 +11,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
npm-unit-test: yarn-unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -19,11 +19,14 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
working-directory: packages/codemirror-lang-kcl
- run: npm run tsc --workspace=packages/codemirror-lang-kcl - run: yarn tsc
working-directory: packages/codemirror-lang-kcl
- name: run unit tests - name: run unit tests
run: npm run test --workspace=packages/codemirror-lang-kcl run: yarn test
working-directory: packages/codemirror-lang-kcl

View File

@ -97,11 +97,11 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm install run: yarn
- name: Download Wasm Cache - name: Download Wasm Cache
id: download-wasm id: download-wasm
@ -154,7 +154,7 @@ jobs:
- name: Build Wasm - name: Build Wasm
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash shell: bash
run: npm run build:wasm run: yarn build:wasm
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
@ -197,12 +197,12 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
id: deps-install id: deps-install
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm install run: yarn
- name: Cache Playwright Browsers - name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
@ -210,32 +210,27 @@ jobs:
with: with:
path: | path: |
~/.cache/ms-playwright/ ~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Browsers - name: Install Playwright Browsers
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm run playwright install --with-deps run: yarn playwright install --with-deps
- name: build web - name: build web
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm run tronb:vite:dev run: yarn tronb:vite:dev
- name: Run ubuntu/chrome snapshots - name: Run ubuntu/chrome snapshots
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
uses: nick-fields/retry@v3.0.2 uses: nick-fields/retry@v3.0.2
with: with:
shell: bash shell: bash
command: npm run test:snapshots command: yarn test:snapshots
timeout_minutes: 30 timeout_minutes: 30
max_attempts: 3 max_attempts: 3
env: env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }} snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
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 }}
TARGET: web
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
@ -321,12 +316,12 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
id: deps-install id: deps-install
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm install run: yarn
- name: Cache Playwright Browsers - name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
@ -334,15 +329,15 @@ jobs:
with: with:
path: | path: |
~/.cache/ms-playwright/ ~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Browsers - name: Install Playwright Browsers
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm run playwright install --with-deps run: yarn playwright install --with-deps
- name: Build web - name: Build web
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: npm run tronb:vite:dev run: yarn tronb:vite:dev
- name: Start Vector - name: Start Vector
if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }} if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }}
@ -370,11 +365,6 @@ jobs:
env: env:
FAIL_ON_CONSOLE_ERRORS: true FAIL_ON_CONSOLE_ERRORS: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} 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 }}
TARGET: desktop
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }} if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}

View File

@ -21,10 +21,10 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- run: npm run generate:machine-api - run: yarn generate:machine-api
- run: npm run fmt || true - run: yarn fmt
- name: check for changes - name: check for changes
id: git-check id: git-check
run: | run: |

View File

@ -56,19 +56,21 @@ jobs:
node-version-file: ".nvmrc" node-version-file: ".nvmrc"
- name: Install dependencies - name: Install dependencies
run: | run: |
npm install yarn install
cd rust/kcl-language-server
yarn install
- name: Run tests - name: Run tests
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npm run build yarn build
npm run test-compile yarn test-compile
ls -la dist ls -la dist
xvfb-run -a npm run test xvfb-run -a yarn test
if: runner.os == 'Linux' if: runner.os == 'Linux'
- name: Run tests - name: Run tests
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npm run test yarn test
if: runner.os != 'Linux' if: runner.os != 'Linux'
build-release: build-release:
strategy: strategy:
@ -181,20 +183,19 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install yarn install
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') if: startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} npx vsce package -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
- name: Package Extension (nightly) - name: Package Extension (nightly)
if: startsWith(github.event.ref, 'refs/tags/') == false if: startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release npx vsce package -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
- name: remove server - name: remove server
if: matrix.target == 'x86_64-unknown-linux-gnu' if: matrix.target == 'x86_64-unknown-linux-gnu'
@ -206,13 +207,13 @@ jobs:
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix npx vsce package -o ../build/kcl-language-server-no-server.vsix
- name: Package Extension (no server, nightly) - name: Package Extension (no server, nightly)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix --pre-release npx vsce package -o ../build/kcl-language-server-no-server.vsix --pre-release
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -243,8 +244,8 @@ jobs:
lld \ lld \
musl-dev \ musl-dev \
nodejs \ nodejs \
npm \ yarn \
yarn npm
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -271,20 +272,19 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install yarn install
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') if: startsWith(github.event.ref, 'refs/tags/')
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 npx vsce package -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64
- name: Package Extension (release) - name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') == false if: startsWith(github.event.ref, 'refs/tags/') == false
run: | run: |
cd rust/kcl-language-server cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release npx vsce package -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4

View File

@ -1,55 +0,0 @@
name: Test Nix Flake
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
nix-flake-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix flake check for all platforms
run: |
nix flake check --all-systems
nix-build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-linux
run: nix build .
nix-build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: nix build . for x86_64-darwin
run: nix build .

View File

@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Find tag workflow id - name: Find tag workflow id
id: tag_workflow_id id: tag_workflow_id
@ -105,7 +105,7 @@ jobs:
- name: Override release notes - name: Override release notes
env: env:
NOTES: ${{ github.event.release.body }} NOTES: ${{ github.event.release.body }}
run: npm run files:set-notes run: yarn files:set-notes
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.8' uses: 'google-github-actions/auth@v2.1.8'
@ -126,7 +126,7 @@ jobs:
destination: 'dl.kittycad.io/releases/modeling-app' destination: 'dl.kittycad.io/releases/modeling-app'
- name: Invalidate bucket cache on latest*.yml and last_download.json files - name: Invalidate bucket cache on latest*.yml and last_download.json files
run: npm run files:invalidate-bucket run: yarn files:invalidate-bucket
- name: Upload release files to Github - name: Upload release files to Github
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}

View File

@ -16,18 +16,18 @@ permissions:
actions: read actions: read
jobs: jobs:
npm-fmt-check: yarn-fmt-check:
runs-on: 'ubuntu-22.04' runs-on: 'ubuntu-22.04'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- run: npm run fmt:check - run: yarn fmt-check
npm-build-wasm: yarn-build-wasm:
# Build the wasm blob once on the fastest runner. # Build the wasm blob once on the fastest runner.
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64 runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps: steps:
@ -36,10 +36,10 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- name: Install dependencies - name: Install dependencies
run: npm install run: yarn install
- name: Use correct Rust toolchain - name: Use correct Rust toolchain
shell: bash shell: bash
@ -62,7 +62,7 @@ jobs:
- name: Build Wasm - name: Build Wasm
shell: bash shell: bash
run: npm run build:wasm run: yarn build:wasm
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@ -76,17 +76,17 @@ jobs:
path: | path: |
rust/kcl-lib/bindings/* rust/kcl-lib/bindings/*
npm-tsc: yarn-tsc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -104,19 +104,19 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run tsc - run: yarn tsc
npm-lint: yarn-lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -134,19 +134,19 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run lint - run: yarn lint
npm-circular-dependencies: yarn-circular-dependencies:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -164,7 +164,7 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run circular-deps:diff - run: yarn circular-deps:diff
python-codespell: python-codespell:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
@ -179,18 +179,18 @@ jobs:
- name: Run codespell - name: Run codespell
run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration. run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
npm-unit-test-kcl-samples: yarn-unit-test-kcl-samples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with: with:
tool: wasm-pack tool: wasm-pack
@ -211,31 +211,31 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg - run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser - name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps run: yarn playwright install chromium --with-deps
- name: run unit tests for kcl samples - name: run unit tests for kcl samples
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run test:unit:kcl-samples run: yarn test:unit:kcl-samples
env: env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
npm-unit-test: yarn-unit-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: npm-build-wasm needs: yarn-build-wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'npm' cache: 'yarn'
- run: npm install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with: with:
tool: wasm-pack tool: wasm-pack
@ -256,16 +256,16 @@ jobs:
mkdir rust/kcl-lib/bindings mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/ cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg - run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser - name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps run: yarn playwright install chromium --with-deps
- name: Run unit tests - name: Run unit tests
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }} if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a npm run test:unit run: xvfb-run -a yarn test:unit
env: env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}

View File

@ -27,7 +27,7 @@ jobs:
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- run: npm install - run: yarn install
- name: Push tag - name: Push tag
run: | run: |

3
.gitignore vendored
View File

@ -26,12 +26,10 @@ yarn-error.log*
.idea .idea
.vscode .vscode
.helix .helix
result
# rust # rust
rust/target rust/target
rust/kcl-lib/bindings rust/kcl-lib/bindings
rust/kcl-language-server/server
public/kcl_wasm_lib_bg.wasm public/kcl_wasm_lib_bg.wasm
rust/lcov.info rust/lcov.info
rust/kcl-wasm-lib/pkg rust/kcl-wasm-lib/pkg
@ -84,4 +82,3 @@ dist
venv venv
.vscode-test .vscode-test
.biome/

View File

@ -1,4 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh" . "$(dirname -- "$0")/_/husky.sh"
npm run fmt-check yarn fmt-check

1
.npmrc
View File

@ -1 +0,0 @@
legacy-peer-deps=true

View File

@ -17,26 +17,31 @@ WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else else
CARGO ?= ~/.cargo/bin/cargo CARGO ?= ~/.cargo/bin/cargo
WASM_PACK ?= ~/.cargo/bin/wasm-pack WASM_PACK ?= ~/.cargo/bin/wasm-pack
endif endif
.PHONY: install .PHONY: install
install: node_modules/.package-lock.json $(CARGO) $(WASM_PACK) ## Install dependencies install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependencies
node_modules/.package-lock.json: package.json package-lock.json node_modules/.yarn-integrity: package.json yarn.lock
npm install yarn install
ifdef POWERSHELL
@ type nul > $@
else
@ touch $@
endif
$(CARGO): $(CARGO):
ifdef WINDOWS ifdef WINDOWS
npm run install:rust:windows yarn install:rust:windows
else else
npm run install:rust yarn install:rust
endif endif
$(WASM_PACK): $(WASM_PACK):
ifdef WINDOWS ifdef WINDOWS
npm run install:wasm-pack:cargo yarn install:wasm-pack:cargo
else else
npm run install:wasm-pack:sh yarn install:wasm-pack:sh
endif endif
############################################################################### ###############################################################################
@ -60,16 +65,16 @@ build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES) public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS ifdef WINDOWS
npm run build:wasm:dev:windows yarn build:wasm:dev:windows
else else
npm run build:wasm:dev yarn build:wasm:dev
endif endif
build/index.html: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES) build/index.html: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
npm run build:local yarn build:local
.vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES) .vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
npm run tronb:vite:dev yarn tronb:vite:dev
############################################################################### ###############################################################################
# CHECK # CHECK
@ -79,12 +84,12 @@ check: format lint
.PHONY: format .PHONY: format
format: install ## Format the code format: install ## Format the code
npm run fmt yarn fmt
.PHONY: lint .PHONY: lint
lint: install ## Lint the code lint: install ## Lint the code
npm run tsc yarn tsc
npm run lint yarn lint
############################################################################### ###############################################################################
# RUN # RUN
@ -96,11 +101,11 @@ run: run-$(TARGET)
.PHONY: run-web .PHONY: run-web
run-web: install build-web ## Start the web app run-web: install build-web ## Start the web app
npm run start yarn start
.PHONY: run-desktop .PHONY: run-desktop
run-desktop: install build-desktop ## Start the desktop app run-desktop: install build-desktop ## Start the desktop app
npm run tron:start yarn tron:start
############################################################################### ###############################################################################
# TEST # TEST
@ -115,7 +120,7 @@ test: test-unit test-e2e
.PHONY: test-unit .PHONY: test-unit
test-unit: install ## Run the unit tests test-unit: install ## Run the unit tests
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 ) @ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
npm run test:unit yarn test:unit
.PHONY: test-e2e .PHONY: test-e2e
test-e2e: test-e2e-$(TARGET) test-e2e: test-e2e-$(TARGET)
@ -124,17 +129,17 @@ test-e2e: test-e2e-$(TARGET)
test-e2e-web: install build-web ## Run the web e2e tests test-e2e-web: install build-web ## Run the web e2e tests
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 ) @ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
ifdef E2E_GREP ifdef E2E_GREP
npm run chrome:test -- --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES) yarn chrome:test --headed --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else else
npm run chrome:test -- --headed --workers='100%' yarn chrome:test --headed --workers='100%'
endif endif
.PHONY: test-e2e-desktop .PHONY: test-e2e-desktop
test-e2e-desktop: install build-desktop ## Run the desktop e2e tests test-e2e-desktop: install build-desktop ## Run the desktop e2e tests
ifdef E2E_GREP ifdef E2E_GREP
npm run test:playwright:electron -- --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES) yarn test:playwright:electron --grep="$(E2E_GREP)" --max-failures=$(E2E_FAILURES)
else else
npm run test:playwright:electron -- --workers='100%' yarn test:playwright:electron --workers='100%'
endif endif
############################################################################### ###############################################################################
@ -169,5 +174,5 @@ endif
# It should work for you other Linux users. # It should work for you other Linux users.
lee-electron-test: lee-electron-test:
Xephyr -br -ac -noreset -screen 1200x500 :2 & Xephyr -br -ac -noreset -screen 1200x500 :2 &
DISPLAY=:2 NODE_ENV=development PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ npm run tron:test -g "when using the file tree" DISPLAY=:2 NODE_ENV=development PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn tron:test -g "when using the file tree"
killall Xephyr killall Xephyr

126
README.md
View File

@ -62,39 +62,39 @@ fnm use
Install the NPM dependencies with: Install the NPM dependencies with:
``` ```
npm install yarn install
``` ```
This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We have package scripts to run rustup, see `package.json` for reference: This project uses a lot of Rust compiled to [WASM](https://webassembly.org/) within it. We have package scripts to run rustup, see `package.json` for reference:
``` ```
# macOS/Linux # macOS/Linux
npm run install:rust yarn install:rust
npm run install:wasm-pack:sh yarn install:wasm-pack:sh
# Windows # Windows
npm run install:rust:windows yarn install:rust:windows
npm run install:wasm-pack:cargo yarn install:wasm-pack:cargo
``` ```
Then to build the WASM layer, run: Then to build the WASM layer, run:
``` ```
# macOS/Linux # macOS/Linux
npm run build:wasm yarn build:wasm
# Windows # Windows
npm run build:wasm:windows yarn build:wasm:windows
``` ```
Or if you have the `gh` cli installed and want to download the latest main wasm bundle. Note that on Windows, you need to associate .ps1 files with PowerShell, which can be done via the right click menu, selecting `C:\Program Files\PowerShell\7\pwsh.exe`, and you can install tools like `gh` via `npm run install:tools:windows`. Or if you have the `gh` cli installed and want to download the latest main wasm bundle. Note that on Windows, you need to associate .ps1 files with PowerShell, which can be done via the right click menu, selecting `C:\Program Files\PowerShell\7\pwsh.exe`, and you can install tools like `gh` via `yarn install:tools:windows`.
``` ```
# macOS/Linux # macOS/Linux
npm run fetch:wasm yarn fetch:wasm
# Windows # Windows
npm run fetch:wasm:windows yarn fetch:wasm:windows
``` ```
That will build the WASM binary and put in the `public` dir (though gitignored). That will build the WASM binary and put in the `public` dir (though gitignored).
@ -102,7 +102,7 @@ That will build the WASM binary and put in the `public` dir (though gitignored).
Finally, to run the web app only, run: Finally, to run the web app only, run:
``` ```
npm start yarn start
``` ```
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again. If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
@ -122,17 +122,17 @@ Third-Party Cookies".
## Desktop ## Desktop
To spin up the desktop app, `npm install` and `npm run build:wasm` need to have been done before hand then: To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then:
``` ```
npm run tron:start yarn tron:start
``` ```
This will start the application and hot-reload on changes. This will start the application and hot-reload on changes.
Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows). Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows).
To package the app for your platform with electron-builder, run `npm run tronb:package:dev` (or `npm run tronb:package:prod` to point to the .env.production variables). To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables).
## Checking out commits / Bisecting ## Checking out commits / Bisecting
@ -141,9 +141,9 @@ Which commands from setup are one off vs. need to be run every time?
The following will need to be run when checking out a new commit and guarantees the build is not stale: The following will need to be run when checking out a new commit and guarantees the build is not stale:
```bash ```bash
npm install yarn install
npm run build:wasm yarn build:wasm
npm start # or npm run build:local && npm run serve for slower but more production-like build yarn start # or yarn build:local && yarn serve for slower but more production-like build
``` ```
## Before submitting a PR ## Before submitting a PR
@ -153,10 +153,10 @@ Before you submit a contribution PR to this repo, please ensure that:
- There is a corresponding issue for the changes you want to make, so that discussion of approach can be had before work begins. - There is a corresponding issue for the changes you want to make, so that discussion of approach can be had before work begins.
- You have separated out refactoring commits from feature commits as much as possible - You have separated out refactoring commits from feature commits as much as possible
- You have run all of the following commands locally: - You have run all of the following commands locally:
- `npm run fmt` - `yarn fmt`
- `npm run tsc` - `yarn tsc`
- `npm run test` - `yarn test`
- Here they are all together: `npm run fmt && npm run tsc && npm run test` - Here they are all together: `yarn fmt && yarn tsc && yarn test`
## Release a new version ## Release a new version
@ -250,29 +250,55 @@ You will need a `./e2e/playwright/playwright-secrets.env` file:
$ touch ./e2e/playwright/playwright-secrets.env $ touch ./e2e/playwright/playwright-secrets.env
$ cat ./e2e/playwright/playwright-secrets.env $ cat ./e2e/playwright/playwright-secrets.env
token=<dev.zoo.dev/account/api-tokens> token=<dev.zoo.dev/account/api-tokens>
snapshottoken=<zoo.dev/account/api-tokens> snapshottoken=<your-snapshot-token>
``` ```
or use `export` to set the environment variables `token` and `snapshottoken`.
#### Snapshot tests (Google Chrome on Ubuntu only) For a portable way to run Playwright you'll need Docker.
Only Ubunu and Google Chrome is supported for the set of tests evaluating screenshot snapshots. #### Generic example
If you don't run Ubuntu locally or in a VM, you may use a GitHub Codespace.
After that, open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-x.xx.x
``` ```
npm run playwright -- install chrome
npm run test:snapshots
```
You may use `-- --update-snapshots` as needed.
#### Electron flow tests (Chromium on Ubuntu, macOS, Windows) and in another terminal, run:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" <test suite>
```
#### Specific example
open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-1.46.0
```
and in another terminal, run:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" e2e/playwright/command-bar-tests.spec.ts
```
run a specific test change the test from `test('...` to `test.only('...`
(note if you commit this, the tests will instantly fail without running any of the tests)
**Gotcha**: running the docker container with a mismatched image against your `./node_modules/playwright` will cause a failure. Make sure the versions are matched and up to date.
run headed
``` ```
npm run playwright -- install chromium yarn playwright test --headed
npm run test:playwright:electron:local
``` ```
You may use `-- -g "my test"` to match specific test titles, or `-- path/to/file.spec.ts` for a test file.
#### Debugger run with step through debugger
```
PWDEBUG=1 yarn playwright test
```
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying. However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code. With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
@ -282,7 +308,7 @@ Or comment out browsers in `playwright.config.ts`.
note chromium has encoder compat issues which is why were testing against the branded 'Google Chrome' note chromium has encoder compat issues which is why were testing against the branded 'Google Chrome'
You may consider using the VSCode extension, it's useful for running individual threads, but some some reason the "record a test" is locked to chromium with we can't use. A work around is to us the CI `npm run playwright codegen -b wk --load-storage ./store localhost:3000` You may consider using the VSCode extension, it's useful for running individual threads, but some some reason the "record a test" is locked to chromium with we can't use. A work around is to us the CI `yarn playwright codegen -b wk --load-storage ./store localhost:3000`
<details> <details>
<summary> <summary>
@ -325,21 +351,21 @@ However because much of our tests involve clicking in the stream at specific loc
If you already haven't, run the following: If you already haven't, run the following:
``` ```
npm yarn
npm run build:wasm yarn build:wasm
npm start yarn start
``` ```
and finally: and finally:
``` ```
npm run test:unit yarn test:unit
``` ```
For individual testing: For individual testing:
``` ```
npm run test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false yarn test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false
``` ```
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro) tests, in interactive mode by default. Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro) tests, in interactive mode by default.
@ -413,16 +439,16 @@ Part of the CI CD pipeline performs static analysis on the code. Use the followi
The following set of commands should get us closer to one and done commands to instantly retest issues. The following set of commands should get us closer to one and done commands to instantly retest issues.
``` ```
npm run test-setup yarn test-setup
``` ```
> Gotcha, are packages up to date and is the wasm built? > Gotcha, are packages up to date and is the wasm built?
``` ```
npm run tsc yarn tsc
npm run fmt:check yarn fmt-check
npm run lint yarn lint
npm run test:unit:local yarn test:unit:local
``` ```
> Gotcha: Our unit tests have integration tests in them. You need to run a localhost server to run the unit tests. > Gotcha: Our unit tests have integration tests in them. You need to run a localhost server to run the unit tests.
@ -434,10 +460,10 @@ npm run test:unit:local
These E2E tests run in electron. There are tests that are skipped if they are ran in a windows, linux, or macos environment. We can use playwright tags to implement test skipping. These E2E tests run in electron. There are tests that are skipped if they are ran in a windows, linux, or macos environment. We can use playwright tags to implement test skipping.
``` ```
npm run test:playwright:electron:local yarn test:playwright:electron:local
npm run test:playwright:electron:windows:local yarn test:playwright:electron:windows:local
npm run test:playwright:electron:macos:local yarn test:playwright:electron:macos:local
npm run test:playwright:electron:ubuntu:local yarn test:playwright:electron:ubuntu:local
``` ```
> Why does it say local? The CI CD commands that run in the pipeline cannot be ran locally. A single command will not properly setup the testing environment locally. > Why does it say local? The CI CD commands that run in the pipeline cannot be ran locally. A single command will not properly setup the testing environment locally.

View File

@ -1,48 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error"
},
"suspicious": {
"noExplicitAny": "warn"
},
"style": {
"useBlockStatements": "error",
"useShorthandArrayType": "error"
}
}
},
"formatter": {
"enabled": true,
"indentWidth": 2,
"indentStyle": "space",
"lineWidth": 80,
"formatWithErrors": true
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"jsxQuoteStyle": "double",
"trailingCommas": "es5",
"semicolons": "asNeeded"
},
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"css": {
"parser": {
"cssModules": true
}
},
"files": {
"ignore": ["**/*.json"]
}
}

View File

@ -28,11 +28,11 @@ angledLine(
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes |
| `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes | | `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes |
| `length` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given. | No | | `length` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `lengthX` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given. | No | | `lengthX` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `lengthY` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given. | No | | `lengthY` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteX` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given. | No | | `endAbsoluteX` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteY` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `endAbsoluteX`, `endAbsoluteY` can be given. | No | | `endAbsoluteY` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No | | [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No |
### Returns ### Returns

View File

@ -10,10 +10,8 @@ Draw an angled line from the current origin, constructing a line segment such th
```js ```js
angledLineThatIntersects( angledLineThatIntersects(
data: AngledLineThatIntersectsData,
sketch: Sketch, sketch: Sketch,
angle: number,
intersectTag: TagIdentifier,
offset?: number,
tag?: TagDeclarator, tag?: TagDeclarator,
): Sketch ): Sketch
``` ```
@ -23,11 +21,9 @@ angledLineThatIntersects(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes | | `data` | [`AngledLineThatIntersectsData`](/docs/kcl/types/AngledLineThatIntersectsData) | Data for drawing an angled line that intersects with a given line. | Yes |
| `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
| `intersectTag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The tag of the line to intersect with | Yes | | [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
| `offset` | [`number`](/docs/kcl/types/number) | The offset from the intersecting line. Defaults to 0. | No |
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No |
### Returns ### Returns
@ -42,7 +38,11 @@ exampleSketch = startSketchOn(XZ)
|> line(endAbsolute = [5, 10]) |> line(endAbsolute = [5, 10])
|> line(endAbsolute = [-10, 10], tag = $lineToIntersect) |> line(endAbsolute = [-10, 10], tag = $lineToIntersect)
|> line(endAbsolute = [0, 20]) |> line(endAbsolute = [0, 20])
|> angledLineThatIntersects(angle = 80, intersectTag = lineToIntersect, offset = 10) |> angledLineThatIntersects({
angle = 80,
intersectTag = lineToIntersect,
offset = 10
}, %)
|> close() |> close()
example = extrude(exampleSketch, length = 10) example = extrude(exampleSketch, length = 10)

File diff suppressed because one or more lines are too long

View File

@ -24,8 +24,8 @@ atan2(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `y` | [`number`](/docs/kcl/types/number) | Y | Yes | | `y` | [`number`](/docs/kcl/types/number) | | Yes |
| `x` | [`number`](/docs/kcl/types/number) | X | Yes | | `x` | [`number`](/docs/kcl/types/number) | | Yes |
### Returns ### Returns
@ -37,7 +37,7 @@ atan2(
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(atan2(y = 1.25, x = 2)), length = 20) |> angledLine(angle = toDegrees(atan2(1.25, 2)), length = 20)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -80,7 +80,7 @@ part001 = cube([0, 0], 20)
// We tag the chamfer to reference it later. // We tag the chamfer to reference it later.
|> chamfer(length = 10, tags = [getOppositeEdge(line1)], tag = $chamfer1) |> chamfer(length = 10, tags = [getOppositeEdge(line1)], tag = $chamfer1)
sketch001 = startSketchOn(part001, face = chamfer1) sketch001 = startSketchOn(part001, chamfer1)
|> startProfileAt([10, 10], %) |> startProfileAt([10, 10], %)
|> line(end = [2, 0]) |> line(end = [2, 0])
|> line(end = [0, 2]) |> line(end = [0, 2])

View File

@ -9,8 +9,6 @@ layout: manual
### `std` ### `std`
- [`END`](/docs/kcl/consts/std-END)
- [`START`](/docs/kcl/consts/std-START)
- [`X`](/docs/kcl/consts/std-X) - [`X`](/docs/kcl/consts/std-X)
- [`XY`](/docs/kcl/consts/std-XY) - [`XY`](/docs/kcl/consts/std-XY)
- [`XZ`](/docs/kcl/consts/std-XZ) - [`XZ`](/docs/kcl/consts/std-XZ)

View File

@ -1,15 +0,0 @@
---
title: "std::END"
excerpt: "Identifies the ending face of an extrusion. I.e., the new face created by an extrusion."
layout: manual
---
Identifies the ending face of an extrusion. I.e., the new face created by an extrusion.
```js
std::END: string = 'end'
```

View File

@ -1,15 +0,0 @@
---
title: "std::START"
excerpt: "Identifies the starting face of an extrusion. I.e., the face which is extruded."
layout: manual
---
Identifies the starting face of an extrusion. I.e., the face which is extruded.
```js
std::START: string = 'start'
```

View File

@ -65,15 +65,15 @@ case = startSketchOn(-XZ)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close() |> close()
|> extrude(length = 65) |> extrude(length = 65)
thing1 = startSketchOn(case, face = END) thing1 = startSketchOn(case, 'end')
|> circle(center = [-size / 2, -size / 2], radius = 25) |> circle(center = [-size / 2, -size / 2], radius = 25)
|> extrude(length = 50) |> extrude(length = 50)
thing2 = startSketchOn(case, face = END) thing2 = startSketchOn(case, 'end')
|> circle(center = [size / 2, -size / 2], radius = 25) |> circle(center = [size / 2, -size / 2], radius = 25)
|> extrude(length = 50) |> extrude(length = 50)

80
docs/kcl/import.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -24,14 +24,12 @@ layout: manual
* **std** * **std**
* [`Axis2d`](kcl/types/Axis2d) * [`Axis2d`](kcl/types/Axis2d)
* [`Axis3d`](kcl/types/Axis3d) * [`Axis3d`](kcl/types/Axis3d)
* [`END`](kcl/consts/std-END)
* [`Edge`](kcl/types/Edge) * [`Edge`](kcl/types/Edge)
* [`Face`](kcl/types/Face) * [`Face`](kcl/types/Face)
* [`Helix`](kcl/types/Helix) * [`Helix`](kcl/types/Helix)
* [`Plane`](kcl/types/Plane) * [`Plane`](kcl/types/Plane)
* [`Point2d`](kcl/types/Point2d) * [`Point2d`](kcl/types/Point2d)
* [`Point3d`](kcl/types/Point3d) * [`Point3d`](kcl/types/Point3d)
* [`START`](kcl/consts/std-START)
* [`Sketch`](kcl/types/Sketch) * [`Sketch`](kcl/types/Sketch)
* [`Solid`](kcl/types/Solid) * [`Solid`](kcl/types/Solid)
* [`X`](kcl/consts/std-X) * [`X`](kcl/consts/std-X)
@ -79,8 +77,6 @@ layout: manual
* [`helix`](kcl/std-helix) * [`helix`](kcl/std-helix)
* [`hole`](kcl/hole) * [`hole`](kcl/hole)
* [`hollow`](kcl/hollow) * [`hollow`](kcl/hollow)
* [`intersect`](kcl/intersect)
* [`involuteCircular`](kcl/involuteCircular)
* [`lastSegX`](kcl/lastSegX) * [`lastSegX`](kcl/lastSegX)
* [`lastSegY`](kcl/lastSegY) * [`lastSegY`](kcl/lastSegY)
* [`legAngX`](kcl/legAngX) * [`legAngX`](kcl/legAngX)
@ -127,14 +123,14 @@ layout: manual
* [`sqrt`](kcl/sqrt) * [`sqrt`](kcl/sqrt)
* [`startProfileAt`](kcl/startProfileAt) * [`startProfileAt`](kcl/startProfileAt)
* [`startSketchOn`](kcl/startSketchOn) * [`startSketchOn`](kcl/startSketchOn)
* [`subtract`](kcl/subtract)
* [`sweep`](kcl/sweep) * [`sweep`](kcl/sweep)
* [`tangentToEnd`](kcl/tangentToEnd) * [`tangentToEnd`](kcl/tangentToEnd)
* [`tangentialArc`](kcl/tangentialArc) * [`tangentialArc`](kcl/tangentialArc)
* [`tangentialArcTo`](kcl/tangentialArcTo)
* [`tangentialArcToRelative`](kcl/tangentialArcToRelative)
* [`toDegrees`](kcl/toDegrees) * [`toDegrees`](kcl/toDegrees)
* [`toRadians`](kcl/toRadians) * [`toRadians`](kcl/toRadians)
* [`translate`](kcl/translate) * [`translate`](kcl/translate)
* [`union`](kcl/union)
* [`xLine`](kcl/xLine) * [`xLine`](kcl/xLine)
* [`yLine`](kcl/yLine) * [`yLine`](kcl/yLine)
* **std::math** * **std::math**

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -37,7 +37,7 @@ line(
```js ```js
triangle = startSketchOn(XZ) triangle = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
// The END argument means it ends at exactly [10, 0]. // The 'end' argument means it ends at exactly [10, 0].
// This is an absolute measurement, it is NOT relative to // This is an absolute measurement, it is NOT relative to
// the start of the sketch. // the start of the sketch.
|> line(endAbsolute = [10, 0]) |> line(endAbsolute = [10, 0])

View File

@ -20,7 +20,7 @@ offsetPlane(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `plane` | [`PlaneData`](/docs/kcl/types/PlaneData) | The plane (e.g. XY) which this new plane is created from. | Yes | | `plane` | [`PlaneData`](/docs/kcl/types/PlaneData) | The plane (e.g. 'XY') which this new plane is created from. | Yes |
| `offset` | [`number`](/docs/kcl/types/number) | Distance from the standard plane this new plane will be created at. | Yes | | `offset` | [`number`](/docs/kcl/types/number) | Distance from the standard plane this new plane will be created at. | Yes |
### Returns ### Returns

View File

@ -57,15 +57,15 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close(%) |> close(%)
|> extrude(length = 65) |> extrude(length = 65)
thing1 = startSketchOn(case, face = END) thing1 = startSketchOn(case, 'end')
|> circle(center = [-size / 2, -size / 2], radius = 25) |> circle(center = [-size / 2, -size / 2], radius = 25)
|> extrude(length = 50) |> extrude(length = 50)
thing2 = startSketchOn(case, face = END) thing2 = startSketchOn(case, 'end')
|> circle(center = [size / 2, -size / 2], radius = 25) |> circle(center = [size / 2, -size / 2], radius = 25)
|> extrude(length = 50) |> extrude(length = 50)
@ -88,11 +88,11 @@ case = startSketchOn(XY)
|> startProfileAt([-size, -size], %) |> startProfileAt([-size, -size], %)
|> line(end = [2 * size, 0]) |> line(end = [2 * size, 0])
|> line(end = [0, 2 * size]) |> line(end = [0, 2 * size])
|> tangentialArc(endAbsolute = [-size, size]) |> tangentialArcTo([-size, size], %)
|> close(%) |> close(%)
|> extrude(length = 65) |> extrude(length = 65)
thing1 = startSketchOn(case, face = END) thing1 = startSketchOn(case, 'end')
|> circle(center = [-size / 2, -size / 2], radius = 25) |> circle(center = [-size / 2, -size / 2], radius = 25)
|> extrude(length = 50) |> extrude(length = 50)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ segLen(tag: TagIdentifier): number
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10, tag = $thing) |> angledLine(angle = 60, length = 10, tag = $thing)
|> tangentialArc(angle = -120, radius = 5) |> tangentialArc({ offset = -120, radius = 5 }, %)
|> angledLine(angle = -60, length = segLen(thing)) |> angledLine(angle = -60, length = segLen(thing))
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -18,8 +18,8 @@ The point is if you want to export the result of a sketch on a face, you only ne
```js ```js
startSketchOn( startSketchOn(
planeOrSolid: SketchData, data: SketchData,
face?: FaceTag, tag?: FaceTag,
): SketchSurface ): SketchSurface
``` ```
@ -28,8 +28,8 @@ startSketchOn(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `planeOrSolid` | [`SketchData`](/docs/kcl/types/SketchData) | The plane or solid to sketch on | Yes | | `data` | [`SketchData`](/docs/kcl/types/SketchData) | Data for start sketch on. You can start a sketch on a plane or an solid. | Yes |
| `face` | [`FaceTag`](/docs/kcl/types/FaceTag) | Identify a face of a solid if a solid is specified as the input argument (`plane_or_solid`) | No | | [`tag`](/docs/kcl/types/tag) | [`FaceTag`](/docs/kcl/types/FaceTag) | A tag for a face. | No |
### Returns ### Returns
@ -48,7 +48,7 @@ exampleSketch = startSketchOn(XY)
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)
exampleSketch002 = startSketchOn(example, face = END) exampleSketch002 = startSketchOn(example, 'end')
|> startProfileAt([1, 1], %) |> startProfileAt([1, 1], %)
|> line(end = [8, 0]) |> line(end = [8, 0])
|> line(end = [0, 8]) |> line(end = [0, 8])
@ -57,7 +57,7 @@ exampleSketch002 = startSketchOn(example, face = END)
example002 = extrude(exampleSketch002, length = 5) example002 = extrude(exampleSketch002, length = 5)
exampleSketch003 = startSketchOn(example002, face = END) exampleSketch003 = startSketchOn(example002, 'end')
|> startProfileAt([2, 2], %) |> startProfileAt([2, 2], %)
|> line(end = [6, 0]) |> line(end = [6, 0])
|> line(end = [0, 6]) |> line(end = [0, 6])
@ -82,7 +82,7 @@ exampleSketch = startSketchOn(XY)
example = extrude(exampleSketch, length = 5, tagEnd = $end01) example = extrude(exampleSketch, length = 5, tagEnd = $end01)
exampleSketch002 = startSketchOn(example, face = end01) exampleSketch002 = startSketchOn(example, end01)
|> startProfileAt([1, 1], %) |> startProfileAt([1, 1], %)
|> line(end = [8, 0]) |> line(end = [8, 0])
|> line(end = [0, 8]) |> line(end = [0, 8])
@ -91,7 +91,7 @@ exampleSketch002 = startSketchOn(example, face = end01)
example002 = extrude(exampleSketch002, length = 5, tagEnd = $end02) example002 = extrude(exampleSketch002, length = 5, tagEnd = $end02)
exampleSketch003 = startSketchOn(example002, face = end02) exampleSketch003 = startSketchOn(example002, end02)
|> startProfileAt([2, 2], %) |> startProfileAt([2, 2], %)
|> line(end = [6, 0]) |> line(end = [6, 0])
|> line(end = [0, 6]) |> line(end = [0, 6])
@ -113,7 +113,7 @@ exampleSketch = startSketchOn(XY)
example = extrude(exampleSketch, length = 10) example = extrude(exampleSketch, length = 10)
exampleSketch002 = startSketchOn(example, face = sketchingFace) exampleSketch002 = startSketchOn(example, sketchingFace)
|> startProfileAt([1, 1], %) |> startProfileAt([1, 1], %)
|> line(end = [8, 0]) |> line(end = [8, 0])
|> line(end = [0, 8]) |> line(end = [0, 8])
@ -122,7 +122,7 @@ exampleSketch002 = startSketchOn(example, face = sketchingFace)
example002 = extrude(exampleSketch002, length = 10) example002 = extrude(exampleSketch002, length = 10)
exampleSketch003 = startSketchOn(example002, face = sketchingFace002) exampleSketch003 = startSketchOn(example002, sketchingFace002)
|> startProfileAt([-8, 12], %) |> startProfileAt([-8, 12], %)
|> line(end = [0, 6]) |> line(end = [0, 6])
|> line(end = [6, 0]) |> line(end = [6, 0])
@ -148,7 +148,7 @@ exampleSketch = startSketchOn(XY)
example = revolve(exampleSketch, axis = Y, angle = 180) example = revolve(exampleSketch, axis = Y, angle = 180)
exampleSketch002 = startSketchOn(example, face = END) exampleSketch002 = startSketchOn(example, 'end')
|> startProfileAt([4.5, -5], %) |> startProfileAt([4.5, -5], %)
|> line(end = [0, 5]) |> line(end = [0, 5])
|> line(end = [5, 0]) |> line(end = [5, 0])
@ -182,7 +182,7 @@ example = revolve(
tagEnd = $end01, tagEnd = $end01,
) )
exampleSketch002 = startSketchOn(example, face = end01) exampleSketch002 = startSketchOn(example, end01)
|> startProfileAt([4.5, -5], %) |> startProfileAt([4.5, -5], %)
|> line(end = [0, 5]) |> line(end = [0, 5])
|> line(end = [5, 0]) |> line(end = [5, 0])
@ -196,10 +196,12 @@ example002 = extrude(exampleSketch002, length = 5)
```js ```js
a1 = startSketchOn({ a1 = startSketchOn({
origin = { x = 0, y = 0, z = 0 }, plane = {
xAxis = { x = 1, y = 0, z = 0 }, origin = { x = 0, y = 0, z = 0 },
yAxis = { x = 0, y = 1, z = 0 }, xAxis = { x = 1, y = 0, z = 0 },
zAxis = { x = 0, y = 0, z = 1 } yAxis = { x = 0, y = 1, z = 0 },
zAxis = { x = 0, y = 0, z = 1 }
}
}) })
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [100.0, 0]) |> line(end = [100.0, 0])

View File

@ -11,11 +11,11 @@ Create a helix.
```js ```js
helix( helix(
revolutions: number(_), revolutions: number(_),
angleStart: number(Angle), angleStart: number(deg),
ccw?: bool, ccw?: bool,
radius?: number(Length), radius?: number(mm),
axis?: Axis3d | Edge, axis?: Axis3d | Edge,
length?: number(Length), length?: number(mm),
cylinder?: Solid, cylinder?: Solid,
): Helix ): Helix
``` ```
@ -26,11 +26,11 @@ helix(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `revolutions` | `number(_)` | Number of revolutions. | Yes | | `revolutions` | `number(_)` | Number of revolutions. | Yes |
| `angleStart` | `number(Angle)` | Start angle (in degrees). | Yes | | `angleStart` | `number(deg)` | Start angle (in degrees). | Yes |
| `ccw` | [`bool`](/docs/kcl/types/bool) | Is the helix rotation counter clockwise? The default is `false`. | No | | `ccw` | [`bool`](/docs/kcl/types/bool) | Is the helix rotation counter clockwise? The default is `false`. | No |
| `radius` | `number(Length)` | Radius of the helix. | No | | `radius` | `number(mm)` | Radius of the helix. | No |
| `axis` | `Axis3d | Edge` | Axis to use for the helix. | No | | `axis` | `Axis3d | Edge` | Axis to use for the helix. | No |
| `length` | `number(Length)` | Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used. | No | | `length` | `number(mm)` | Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used. | No |
| `cylinder` | [`Solid`](/docs/kcl/types/Solid) | Cylinder to create the helix on. | No | | `cylinder` | [`Solid`](/docs/kcl/types/Solid) | Cylinder to create the helix on. | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Compute the cosine of a number (in radians).
```js ```js
cos(@num: number(Angle)): number(_) cos(@num: number(rad)): number(_)
``` ```
@ -17,7 +17,7 @@ cos(@num: number(Angle)): number(_)
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `num` | `number(Angle)` | | Yes | | `num` | `number(rad)` | | Yes |
### Returns ### Returns

View File

@ -11,9 +11,9 @@ cartesian (x/y/z grid) coordinates.
```js ```js
polar( polar(
angle: number(Angle), angle: number(deg),
length: number(Length), length: number(mm),
): Point2d ): [number(mm); 2]
``` ```
@ -21,12 +21,12 @@ polar(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `angle` | `number(Angle)` | | Yes | | `angle` | `number(deg)` | | Yes |
| `length` | `number(Length)` | | Yes | | `length` | `number(mm)` | | Yes |
### Returns ### Returns
[`Point2d`](/docs/kcl/types/Point2d) `[number(mm); 2]`
### Examples ### Examples

View File

@ -9,7 +9,7 @@ Compute the sine of a number (in radians).
```js ```js
sin(@num: number(Angle)): number(_) sin(@num: number(rad)): number(_)
``` ```
@ -17,7 +17,7 @@ sin(@num: number(Angle)): number(_)
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `num` | `number(Angle)` | | Yes | | `num` | `number(rad)` | | Yes |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Compute the tangent of a number (in radians).
```js ```js
tan(@num: number(Angle)): number(_) tan(@num: number(rad)): number(_)
``` ```
@ -17,7 +17,7 @@ tan(@num: number(Angle)): number(_)
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `num` | `number(Angle)` | | Yes | | `num` | `number(rad)` | | Yes |
### Returns ### Returns

View File

@ -21,10 +21,10 @@ revolved around the same axis.
revolve( revolve(
@sketches: [Sketch; 1+], @sketches: [Sketch; 1+],
axis: Axis2d | Edge, axis: Axis2d | Edge,
angle?: number(Angle), angle?: number(deg),
tolerance?: number(Length), tolerance?: number(mm),
symmetric?: bool, symmetric?: bool,
bidirectionalAngle?: number(Angle), bidirectionalAngle?: number(deg),
tagStart?: tag, tagStart?: tag,
tagEnd?: tag, tagEnd?: tag,
): Solid ): Solid
@ -37,10 +37,10 @@ revolve(
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketches` | `[Sketch; 1+]` | The sketch or set of sketches that should be revolved | Yes | | `sketches` | `[Sketch; 1+]` | The sketch or set of sketches that should be revolved | Yes |
| `axis` | `Axis2d | Edge` | Axis of revolution. | Yes | | `axis` | `Axis2d | Edge` | Axis of revolution. | Yes |
| `angle` | `number(Angle)` | Angle to revolve (in degrees). Default is 360. | No | | `angle` | `number(deg)` | Angle to revolve (in degrees). Default is 360. | No |
| `tolerance` | `number(Length)` | Tolerance for the revolve operation. | No | | `tolerance` | `number(mm)` | Tolerance for the revolve operation. | No |
| `symmetric` | [`bool`](/docs/kcl/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 | | `symmetric` | [`bool`](/docs/kcl/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 |
| `bidirectionalAngle` | `number(Angle)` | If specified, will also revolve in the opposite direction to 'angle' to the specified angle. If 'symmetric' is true, this value is ignored. | No | | `bidirectionalAngle` | `number(deg)` | If specified, will also revolve in the opposite direction to 'angle' to the specified angle. If 'symmetric' is true, this value is ignored. | No |
| `tagStart` | [`tag`](/docs/kcl/types/tag) | A named tag for the face at the start of the revolve, i.e. the original sketch. | No | | `tagStart` | [`tag`](/docs/kcl/types/tag) | A named tag for the face at the start of the revolve, i.e. the original sketch. | No |
| `tagEnd` | [`tag`](/docs/kcl/types/tag) | A named tag for the face at the end of the revolve. | No | | `tagEnd` | [`tag`](/docs/kcl/types/tag) | A named tag for the face at the end of the revolve. | No |
@ -108,7 +108,7 @@ part001 = startSketchOn(XY)
|> close() |> close()
|> revolve(axis = Y, angle = 180) |> revolve(axis = Y, angle = 180)
part002 = startSketchOn(part001, face = END) part002 = startSketchOn(part001, 'end')
|> startProfileAt([4.5, -5], %) |> startProfileAt([4.5, -5], %)
|> line(end = [0, 5]) |> line(end = [0, 5])
|> line(end = [5, 0]) |> line(end = [5, 0])
@ -128,7 +128,7 @@ box = startSketchOn(XY)
|> close() |> close()
|> extrude(length = 20) |> extrude(length = 20)
sketch001 = startSketchOn(box, face = END) sketch001 = startSketchOn(box, "END")
|> circle( center = [10,10], radius = 4 ) |> circle( center = [10,10], radius = 4 )
|> revolve( |> revolve(
angle = -90, angle = -90,
@ -147,7 +147,7 @@ box = startSketchOn(XY)
|> close() |> close()
|> extrude(length = 20) |> extrude(length = 20)
sketch001 = startSketchOn(box, face = END) sketch001 = startSketchOn(box, "END")
|> circle( center = [10,10], radius = 4 ) |> circle( center = [10,10], radius = 4 )
|> revolve( |> revolve(
angle = 90, angle = 90,
@ -166,7 +166,7 @@ box = startSketchOn(XY)
|> close() |> close()
|> extrude(length = 20) |> extrude(length = 20)
sketch001 = startSketchOn(box, face = END) sketch001 = startSketchOn(box, "END")
|> circle( center = [10,10], radius = 4 ) |> circle( center = [10,10], radius = 4 )
|> revolve( |> revolve(
angle = 90, angle = 90,

View File

@ -13,7 +13,7 @@ the provided (x, y) origin point.
circle( circle(
@sketch_or_surface: Sketch | Plane | Face, @sketch_or_surface: Sketch | Plane | Face,
center: Point2d, center: Point2d,
radius: number(Length), radius: number,
tag?: tag, tag?: tag,
): Sketch ): Sketch
``` ```
@ -25,7 +25,7 @@ circle(
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) OR [`Plane`](/docs/kcl/types/Plane) OR [`Face`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes | | `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) OR [`Plane`](/docs/kcl/types/Plane) OR [`Face`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `center` | [`Point2d`](/docs/kcl/types/Point2d) | The center of the circle. | Yes | | `center` | [`Point2d`](/docs/kcl/types/Point2d) | The center of the circle. | Yes |
| `radius` | `number(Length)` | The radius of the circle. | Yes | | `radius` | [`number`](/docs/kcl/types/number) | The radius of the circle. | Yes |
| [`tag`](/docs/kcl/types/tag) | [`tag`](/docs/kcl/types/tag) | Create a new tag which refers to this circle. | No | | [`tag`](/docs/kcl/types/tag) | [`tag`](/docs/kcl/types/tag) | Create a new tag which refers to this circle. | No |
### Returns ### Returns

View File

@ -103,14 +103,14 @@ example = extrude(sketch001, length = 10)
sketch0011 = startSketchOn(XY) sketch0011 = startSketchOn(XY)
|> startProfileAt([6.77, 0], %) |> startProfileAt([6.77, 0], %)
|> yLine(length = 1.27) |> yLine(length = 1.27)
|> tangentialArc(endAbsolute = [5.96, 2.37]) |> tangentialArcTo([5.96, 2.37], %)
|> tangentialArc(endAbsolute = [-6.2, 2.44]) |> tangentialArcTo([-6.2, 2.44], %)
|> tangentialArc(endAbsolute = [-6.6, 1.82]) |> tangentialArcTo([-6.6, 1.82], %)
|> yLine(length = -1.82) |> yLine(length = -1.82)
|> mirror2d( axis = X ) |> mirror2d( axis = X )
|> extrude(length = 10) |> extrude(length = 10)
sketch002 = startSketchOn(sketch0011, face = END) sketch002 = startSketchOn(sketch0011, 'END')
|> circle( center = [-0.01, 1.58], radius = 1.2 ) |> circle( center = [-0.01, 1.58], radius = 1.2 )
|> extrude(length = 1.2) |> extrude(length = 1.2)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -31,9 +31,9 @@ tangentToEnd(tag: TagIdentifier): number
pillSketch = startSketchOn(XZ) pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> tangentialArc(end = [0, 10], tag = $arc1) |> tangentialArcToRelative([0, 10], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine(angle = tangentToEnd(arc1), length = 20)
|> tangentialArc(end = [0, -10]) |> tangentialArcToRelative([0, -10], %)
|> close() |> close()
pillExtrude = extrude(pillSketch, length = 10) pillExtrude = extrude(pillSketch, length = 10)
@ -46,9 +46,9 @@ pillExtrude = extrude(pillSketch, length = 10)
pillSketch = startSketchOn(XZ) pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [0, 20]) |> line(end = [0, 20])
|> tangentialArc(endAbsolute = [10, 20], tag = $arc1) |> tangentialArcTo([10, 20], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine(angle = tangentToEnd(arc1), length = 20)
|> tangentialArc(end = [-10, 0]) |> tangentialArcToRelative([-10, 0], %)
|> close() |> close()
pillExtrude = extrude(pillSketch, length = 10) pillExtrude = extrude(pillSketch, length = 10)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,46 @@
---
title: "AngledLineData"
excerpt: "Data to draw an angled line."
layout: manual
---
Data to draw an angled line.
**This schema accepts any of the following:**
An angle and length with explicitly named parameters
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line (in degrees). | No |
| `length` |[`number`](/docs/kcl/types/number)| The length of the line. | No |
----
An angle and length given as a pair
**Type:** `array`
`[number, number]`
----

View File

@ -16,8 +16,8 @@ Data for drawing an angled line that intersects with a given line.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `angle` |`TyF64`| The angle of the line. | No | | `angle` |[`number`](/docs/kcl/types/number)| The angle of the line. | No |
| `intersectTag` |[`TagIdentifier`](/docs/kcl/types#tag-identifier)| The tag of the line to intersect with. | No | | `intersectTag` |[`TagIdentifier`](/docs/kcl/types#tag-identifier)| The tag of the line to intersect with. | No |
| `offset` |`TyF64`| The offset from the intersecting line. | No | | `offset` |[`number`](/docs/kcl/types/number)| The offset from the intersecting line. | No |

View File

@ -0,0 +1,22 @@
---
title: "AngledLineToData"
excerpt: "Data to draw an angled line to a point."
layout: manual
---
Data to draw an angled line to a point.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line. | No |
| `to` |[`number`](/docs/kcl/types/number)| The point to draw to. | No |

View File

@ -23,9 +23,9 @@ Angles and radius with an optional tag.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `angleStart` |`TyF64`| The start angle. | No | | `angleStart` |[`number`](/docs/kcl/types/number) (**maximum:** 360.0) (**minimum:** -360.0)| The start angle. | No |
| `angleEnd` |`TyF64`| The end angle. | No | | `angleEnd` |[`number`](/docs/kcl/types/number) (**maximum:** 360.0) (**minimum:** -360.0)| The end angle. | No |
| `radius` |`TyF64`| The radius. | No | | `radius` |[`number`](/docs/kcl/types/number)| The radius. | No |
---- ----
@ -41,9 +41,9 @@ Center, to and radius with an optional tag.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `center` |`[, `TyF64`, `TyF64`]`| The center. | No | | `center` |`[number, number]`| The center. | No |
| `to` |`[, `TyF64`, `TyF64`]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `radius` |`TyF64`| The radius. | No | | `radius` |[`number`](/docs/kcl/types/number)| The radius. | No |
---- ----

View File

@ -16,7 +16,7 @@ Data to draw a three point arc (arcTo).
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `end` |`[, `TyF64`, `TyF64`]`| End point of the arc. A point in 3D space | No | | `end` |`[number, number]`| End point of the arc. A point in 3D space | No |
| `interior` |`[, `TyF64`, `TyF64`]`| Interior point of the arc. A point in 3D space | No | | `interior` |`[number, number]`| Interior point of the arc. A point in 3D space | No |

View File

@ -16,8 +16,8 @@ Data to draw a bezier curve.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` |`[, `TyF64`, `TyF64`]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `control1` |`[, `TyF64`, `TyF64`]`| The first control point. | No | | `control1` |`[number, number]`| The first control point. | No |
| `control2` |`[, `TyF64`, `TyF64`]`| The second control point. | No | | `control2` |`[number, number]`| The second control point. | No |

View File

@ -26,7 +26,7 @@ A fillet.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `fillet`| | No | | `type` |enum: `fillet`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the engine command that called this fillet. | No | | `id` |[`string`](/docs/kcl/types/string)| The id of the engine command that called this fillet. | No |
| `radius` |`TyF64`| | No | | `radius` |[`number`](/docs/kcl/types/number)| | No |
| `edgeId` |[`string`](/docs/kcl/types/string)| The engine id of the edge to fillet. | No | | `edgeId` |[`string`](/docs/kcl/types/string)| The engine id of the edge to fillet. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No |
@ -46,7 +46,7 @@ A chamfer.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `chamfer`| | No | | `type` |enum: `chamfer`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the engine command that called this chamfer. | No | | `id` |[`string`](/docs/kcl/types/string)| The id of the engine command that called this chamfer. | No |
| `length` |`TyF64`| | No | | `length` |[`number`](/docs/kcl/types/number)| | No |
| `edgeId` |[`string`](/docs/kcl/types/string)| The engine id of the edge to chamfer. | No | | `edgeId` |[`string`](/docs/kcl/types/string)| The engine id of the edge to chamfer. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No |

View File

@ -252,7 +252,7 @@ Data for an imported geometry.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ImportedGeometry`| | No | | `type` |enum: [`ImportedGeometry`](/docs/kcl/types/ImportedGeometry)| | No |
| `id` |[`string`](/docs/kcl/types/string)| The ID of the imported geometry. | No | | `id` |[`string`](/docs/kcl/types/string)| The ID of the imported geometry. | No |
| `value` |`[` [`string`](/docs/kcl/types/string) `]`| The original file paths. | No | | `value` |`[` [`string`](/docs/kcl/types/string) `]`| The original file paths. | No |

View File

@ -130,21 +130,6 @@ A unit of length.
| `type` |enum: `Yards`| | No | | `type` |enum: `Yards`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Unknown`| | No |
---- ----
@ -193,21 +178,6 @@ A unit of angle.
| `type` |enum: `Radians`| | No | | `type` |enum: `Radians`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Unknown`| | No |
---- ----

View File

@ -7,7 +7,7 @@ layout: manual
A point in two dimensional space. A point in two dimensional space.
```kcl ```kcl
type Point2d = [number(Length); 2] type Point2d = [number; 2]
``` ```
[`Point2d`](/docs/kcl/types/Point2d) is an alias for a two-element array of [number](/docs/kcl/types/number)s. To write a value [`Point2d`](/docs/kcl/types/Point2d) is an alias for a two-element array of [number](/docs/kcl/types/number)s. To write a value

View File

@ -7,7 +7,7 @@ layout: manual
A point in three dimensional space. A point in three dimensional space.
```kcl ```kcl
type Point3d = [number(Length); 3] type Point3d = [number; 3]
``` ```
[`Point3d`](/docs/kcl/types/Point3d) is an alias for a three-element array of [number](/docs/kcl/types/number)s. To write a value [`Point3d`](/docs/kcl/types/Point3d) is an alias for a three-element array of [number](/docs/kcl/types/number)s. To write a value

View File

@ -16,9 +16,9 @@ Data for drawing a polygon
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `radius` |`TyF64`| The radius of the polygon | No | | `radius` |[`number`](/docs/kcl/types/number)| The radius of the polygon | No |
| `numSides` |`integer`| The number of sides in the polygon | No | | `numSides` |`integer`| The number of sides in the polygon | No |
| `center` |`[, `TyF64`, `TyF64`]`| The center point of the polygon | No | | `center` |`[number, number]`| The center point of the polygon | No |
| `inscribed` |`boolean`| Whether the polygon is inscribed (true) or circumscribed (false) about a circle with the specified radius | No | | `inscribed` |`boolean`| Whether the polygon is inscribed (true) or circumscribed (false) about a circle with the specified radius | No |

View File

@ -16,7 +16,7 @@ Data to draw a tangential arc.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `radius` |`TyF64`| Radius of the arc. Not to be confused with Raiders of the Lost Ark. | No | | `radius` |[`number`](/docs/kcl/types/number)| Radius of the arc. Not to be confused with Raiders of the Lost Ark. | No |
| `offset` |`TyF64`| Offset of the arc, in degrees. | No | | `offset` |[`number`](/docs/kcl/types/number)| Offset of the arc, in degrees. | No |

View File

@ -43,21 +43,6 @@ A unit of angle.
---- ----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Unknown`| | No |
----

View File

@ -103,21 +103,6 @@ A unit of length.
---- ----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Unknown`| | No |
----

File diff suppressed because one or more lines are too long

View File

@ -66,17 +66,15 @@ async function doBasicSketch(
await page.waitForTimeout(500) await page.waitForTimeout(500)
if (openPanes.includes('code')) { if (openPanes.includes('code')) {
await expect( await expect(u.codeLocator)
u.codeLocator .toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|> xLine(length = ${commonPoints.num1})`) |> xLine(length = ${commonPoints.num1})`)
} }
await page.waitForTimeout(500) await page.waitForTimeout(500)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
if (openPanes.includes('code')) { if (openPanes.includes('code')) {
await expect( await expect(u.codeLocator)
u.codeLocator .toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt commonPoints.startAt
}, sketch001) }, sketch001)
|> xLine(length = ${commonPoints.num1}) |> xLine(length = ${commonPoints.num1})
@ -87,9 +85,8 @@ async function doBasicSketch(
await page.waitForTimeout(200) await page.waitForTimeout(200)
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
if (openPanes.includes('code')) { if (openPanes.includes('code')) {
await expect( await expect(u.codeLocator)
u.codeLocator .toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt commonPoints.startAt
}, sketch001) }, sketch001)
|> xLine(length = ${commonPoints.num1}) |> xLine(length = ${commonPoints.num1})
@ -145,9 +142,8 @@ async function doBasicSketch(
// Open the code pane. // Open the code pane.
await u.openKclCodePanel() await u.openKclCodePanel()
await expect( await expect(u.codeLocator)
u.codeLocator .toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
).toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt commonPoints.startAt
}, sketch001) }, sketch001)
|> xLine(length = ${commonPoints.num1}, tag = $seg01) |> xLine(length = ${commonPoints.num1}, tag = $seg01)

View File

@ -1,6 +1,6 @@
import { join } from 'path' import { bracket } from '@src/lib/exampleKcl'
import { bracket } from '@e2e/playwright/fixtures/bracket'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { join } from 'path'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from '@e2e/playwright/storageStates' import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from '@e2e/playwright/storageStates'
import { import {

View File

@ -1,6 +1,6 @@
import path, { join } from 'path'
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants' import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import path, { join } from 'path'
import { import {
executorInputPath, executorInputPath,

View File

@ -1,5 +1,5 @@
import path from 'path'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import path from 'path'
import { import {
executorInputPath, executorInputPath,

View File

@ -1,6 +1,6 @@
import { join } from 'path'
import { uuidv4 } from '@src/lib/utils' import { uuidv4 } from '@src/lib/utils'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { join } from 'path'
import { import {
TEST_COLORS, TEST_COLORS,
@ -82,7 +82,7 @@ sketch001 = startSketchOn(XY)
.poll(() => .poll(() =>
page.locator('[data-receive-command-type="scene_clear_all"]').count() page.locator('[data-receive-command-type="scene_clear_all"]').count()
) )
.toBe(2) .toBe(1)
await expect await expect
.poll(() => page.locator('[data-message-type="execution-done"]').count()) .poll(() => page.locator('[data-message-type="execution-done"]').count())
.toBe(2) .toBe(2)
@ -106,7 +106,7 @@ sketch001 = startSketchOn(XY)
).toHaveCount(3) ).toHaveCount(3)
await expect( await expect(
page.locator('[data-receive-command-type="scene_clear_all"]') page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(2) ).toHaveCount(1)
}) })
test('ensure we use the cache, and do not clear on append', async ({ test('ensure we use the cache, and do not clear on append', async ({
@ -133,7 +133,7 @@ sketch001 = startSketchOn(XY)
await u.openDebugPanel() await u.openDebugPanel()
await expect( await expect(
page.locator('[data-receive-command-type="scene_clear_all"]') page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(2) ).toHaveCount(1)
await expect( await expect(
page.locator('[data-message-type="execution-done"]') page.locator('[data-message-type="execution-done"]')
).toHaveCount(2) ).toHaveCount(2)
@ -161,7 +161,7 @@ sketch001 = startSketchOn(XY)
).toHaveCount(3) ).toHaveCount(3)
await expect( await expect(
page.locator('[data-receive-command-type="scene_clear_all"]') page.locator('[data-receive-command-type="scene_clear_all"]')
).toHaveCount(2) ).toHaveCount(1)
}) })
test('if you click the format button it formats your code', async ({ test('if you click the format button it formats your code', async ({
@ -409,9 +409,8 @@ sketch_001 = startSketchOn(XY)
// Hit alt+shift+f to format the code // Hit alt+shift+f to format the code
await page.keyboard.press('Alt+Shift+KeyF') await page.keyboard.press('Alt+Shift+KeyF')
await expect( await expect(page.locator('.cm-content'))
page.locator('.cm-content') .toHaveText(`sketch001 = startSketchOn(XY)
).toHaveText(`sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> line(end = [0, 20]) |> line(end = [0, 20])
@ -463,9 +462,8 @@ sketch_001 = startSketchOn(XY)
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel() await u.closeDebugPanel()
await expect( await expect(page.locator('.cm-content'))
page.locator('.cm-content') .toHaveText(`sketch_001 = startSketchOn(XY)
).toHaveText(`sketch_001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> line(end = [0, 20]) |> line(end = [0, 20])
@ -733,7 +731,7 @@ sketch_001 = startSketchOn(XY)
|> close() |> close()
|> extrude(length = 10) |> extrude(length = 10)
sketch001 = startSketchOn(box, face = revolveAxis) sketch001 = startSketchOn(box, revolveAxis)
|> startProfileAt([5, 10], %) |> startProfileAt([5, 10], %)
|> line(end = [0, -10]) |> line(end = [0, -10])
|> line(end = [2, 0]) |> line(end = [2, 0])
@ -922,7 +920,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -5.38]) |> tangentialArcTo([24.95, -5.38], %)
|> close()` |> close()`
) )
}) })
@ -971,7 +969,7 @@ sketch001 = startSketchOn(XZ)
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArc(endAbsolute = [24.95, -5.38]) |> close()extrude001 = extrude(sketch001, length = 5)` `sketch001 = startSketchOn(XZ) |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArcTo([24.95, -5.38], %) |> close()extrude001 = extrude(sketch001, length = 5)`
) )
// Now hit undo // Now hit undo
@ -980,12 +978,11 @@ sketch001 = startSketchOn(XZ)
await page.keyboard.up('Control') await page.keyboard.up('Control')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect( await expect(page.locator('.cm-content'))
page.locator('.cm-content') .toHaveText(`sketch001 = startSketchOn(XZ)
).toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -5.38]) |> tangentialArcTo([24.95, -5.38], %)
|> close()`) |> close()`)
}) })
@ -1001,7 +998,7 @@ sketch001 = startSketchOn(XZ)
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)` |> extrude(length = 5)`
) )
@ -1075,7 +1072,7 @@ sketch001 = startSketchOn(XZ)
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
// drag tangentialArc handle // drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]') const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 }, sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
@ -1092,7 +1089,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [27.6, -3.05]) |> tangentialArcTo([27.6, -3.05], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1107,7 +1104,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1122,7 +1119,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1138,7 +1135,7 @@ sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArcTo([24.95, -0.38], %)
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
@ -1147,7 +1144,7 @@ sketch001 = startSketchOn(XZ)
) )
test( test(
`Can import a local OBJ file`, `Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ page, context }, testInfo) => { async ({ page, context }, testInfo) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
@ -1197,7 +1194,7 @@ sketch001 = startSketchOn(XZ)
.toBeLessThan(15) .toBeLessThan(15)
}) })
await test.step(`Write the import function line`, async () => { await test.step(`Write the import function line`, async () => {
await u.codeLocator.fill(`import 'cube.obj'\ncube`) await u.codeLocator.fill(`import('cube.obj')`)
await page.waitForTimeout(800) await page.waitForTimeout(800)
}) })
await test.step(`Reset the camera before checking`, async () => { await test.step(`Reset the camera before checking`, async () => {

View File

@ -1,5 +1,5 @@
import { join } from 'path'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import { join } from 'path'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
@ -44,7 +44,7 @@ const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close(%) |> close(%)
extrude001 = extrude(sketch001, length = 10) extrude001 = extrude(sketch001, length = 10)
sketch002 = startSketchOn(extrude001, face = rectangleSegmentB001) sketch002 = startSketchOn(extrude001, rectangleSegmentB001)
|> circle( |> circle(
center = [-1, 2], center = [-1, 2],
radius = .5 radius = .5
@ -194,7 +194,7 @@ test.describe('Feature Tree pane', () => {
highlightedCode: '', highlightedCode: '',
diagnostics: [], diagnostics: [],
activeLines: [ activeLines: [
'sketch002=startSketchOn(extrude001,face=rectangleSegmentB001)', 'sketch002=startSketchOn(extrude001,rectangleSegmentB001)',
], ],
}) })
await toolbar.exitSketchBtn.click() await toolbar.exitSketchBtn.click()

View File

@ -1,7 +1,7 @@
import * as fs from 'fs'
import { join } from 'path'
import { FILE_EXT } from '@src/lib/constants' import { FILE_EXT } from '@src/lib/constants'
import * as fs from 'fs'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import { join } from 'path'
import { import {
createProject, createProject,

View File

@ -1,16 +0,0 @@
import fs from 'fs'
import path from 'path'
export const bracket = fs.readFileSync(
path.resolve(
__dirname,
'..',
'..',
'..',
'public',
'kcl-samples',
'bracket',
'main.kcl'
),
'utf8'
)

View File

@ -1,9 +1,9 @@
import * as fs from 'fs'
import * as path from 'path'
import type { Locator, Page, Request, Route, TestInfo } from '@playwright/test' import type { Locator, Page, Request, Route, TestInfo } from '@playwright/test'
import { expect } from '@playwright/test' import { expect } from '@playwright/test'
import * as fs from 'fs'
import * as path from 'path'
export type CmdBarSerialised = type CmdBarSerialised =
| { | {
stage: 'commandBarClosed' stage: 'commandBarClosed'
} }

View File

@ -7,11 +7,11 @@ import type {
} from '@playwright/test' } from '@playwright/test'
import { _electron as electron } from '@playwright/test' import { _electron as electron } from '@playwright/test'
import fs from 'node:fs'
import path from 'path'
import { SETTINGS_FILE_NAME } from '@src/lib/constants' import { SETTINGS_FILE_NAME } from '@src/lib/constants'
import type { DeepPartial } from '@src/lib/types' import type { DeepPartial } from '@src/lib/types'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import fs from 'node:fs'
import path from 'path'
import type { Settings } from '@rust/kcl-lib/bindings/Settings' import type { Settings } from '@rust/kcl-lib/bindings/Settings'

View File

@ -99,6 +99,7 @@ export class HomePageFixture {
createAndGoToProject = async (projectTitle = 'untitled') => { createAndGoToProject = async (projectTitle = 'untitled') => {
await this.projectsLoaded() await this.projectsLoaded()
await this.projectButtonNew.click() await this.projectButtonNew.click()
await this.projectTextName.click()
await this.projectTextName.fill(projectTitle) await this.projectTextName.fill(projectTitle)
await this.projectButtonContinue.click() await this.projectButtonContinue.click()
} }

View File

@ -44,7 +44,6 @@ export class SceneFixture {
public page: Page public page: Page
public streamWrapper!: Locator public streamWrapper!: Locator
public networkToggleConnected!: Locator public networkToggleConnected!: Locator
public engineConnectionsSpinner!: Locator
public startEditSketchBtn!: Locator public startEditSketchBtn!: Locator
constructor(page: Page) { constructor(page: Page) {
@ -53,7 +52,6 @@ export class SceneFixture {
this.networkToggleConnected = page this.networkToggleConnected = page
.getByTestId('network-toggle-ok') .getByTestId('network-toggle-ok')
.or(page.getByTestId('network-toggle-other')) .or(page.getByTestId('network-toggle-other'))
this.engineConnectionsSpinner = page.getByTestId(`loading-engine`)
this.startEditSketchBtn = page this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' }) .getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' })) .or(page.getByRole('button', { name: 'Edit Sketch' }))
@ -230,15 +228,13 @@ export class SceneFixture {
connectionEstablished = async () => { connectionEstablished = async () => {
const timeout = 30000 const timeout = 30000
await expect(this.networkToggleConnected).toBeVisible({ timeout }) await expect(this.networkToggleConnected).toBeVisible({ timeout })
await expect(this.engineConnectionsSpinner).not.toBeVisible()
} }
settled = async (cmdBar: CmdBarFixture) => { settled = async (cmdBar: CmdBarFixture) => {
const u = await getUtils(this.page) const u = await getUtils(this.page)
await expect(this.startEditSketchBtn).not.toBeDisabled({ timeout: 15_000 }) await expect(this.startEditSketchBtn).not.toBeDisabled()
await expect(this.startEditSketchBtn).toBeVisible() await expect(this.startEditSketchBtn).toBeVisible()
await expect(this.engineConnectionsSpinner).not.toBeVisible()
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
await cmdBar.chooseCommand('Settings · app · show debug panel') await cmdBar.chooseCommand('Settings · app · show debug panel')

View File

@ -27,7 +27,6 @@ export class ToolbarFixture {
offsetPlaneButton!: Locator offsetPlaneButton!: Locator
helixButton!: Locator helixButton!: Locator
startSketchBtn!: Locator startSketchBtn!: Locator
insertButton!: Locator
lineBtn!: Locator lineBtn!: Locator
tangentialArcBtn!: Locator tangentialArcBtn!: Locator
circleBtn!: Locator circleBtn!: Locator
@ -45,7 +44,7 @@ export class ToolbarFixture {
featureTreePane!: Locator featureTreePane!: Locator
gizmo!: Locator gizmo!: Locator
gizmoDisabled!: Locator gizmoDisabled!: Locator
loadButton!: Locator insertButton!: Locator
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
@ -60,7 +59,6 @@ export class ToolbarFixture {
this.offsetPlaneButton = page.getByTestId('plane-offset') this.offsetPlaneButton = page.getByTestId('plane-offset')
this.helixButton = page.getByTestId('helix') this.helixButton = page.getByTestId('helix')
this.startSketchBtn = page.getByTestId('sketch') this.startSketchBtn = page.getByTestId('sketch')
this.insertButton = page.getByTestId('insert')
this.lineBtn = page.getByTestId('line') this.lineBtn = page.getByTestId('line')
this.tangentialArcBtn = page.getByTestId('tangential-arc') this.tangentialArcBtn = page.getByTestId('tangential-arc')
this.circleBtn = page.getByTestId('circle-center') this.circleBtn = page.getByTestId('circle-center')
@ -70,7 +68,6 @@ export class ToolbarFixture {
this.fileTreeBtn = page.locator('[id="files-button-holder"]') this.fileTreeBtn = page.locator('[id="files-button-holder"]')
this.createFileBtn = page.getByTestId('create-file-button') this.createFileBtn = page.getByTestId('create-file-button')
this.treeInputField = page.getByTestId('tree-input-field') this.treeInputField = page.getByTestId('tree-input-field')
this.loadButton = page.getByTestId('load-external-model-pane-button')
this.filePane = page.locator('#files-pane') this.filePane = page.locator('#files-pane')
this.featureTreePane = page.locator('#feature-tree-pane') this.featureTreePane = page.locator('#feature-tree-pane')
@ -82,6 +79,8 @@ export class ToolbarFixture {
// element or two different elements can represent these states. // element or two different elements can represent these states.
this.gizmo = page.getByTestId('gizmo') this.gizmo = page.getByTestId('gizmo')
this.gizmoDisabled = page.getByTestId('gizmo-disabled') this.gizmoDisabled = page.getByTestId('gizmo-disabled')
this.insertButton = page.getByTestId('insert-pane-button')
} }
get logoLink() { get logoLink() {
@ -205,11 +204,6 @@ export class ToolbarFixture {
).toBeVisible() ).toBeVisible()
await this.page.getByTestId('dropdown-three-point-arc').click() await this.page.getByTestId('dropdown-three-point-arc').click()
} }
selectLine = async () => {
await this.page
.getByRole('button', { name: 'line Line', exact: true })
.click()
}
async closePane(paneId: SidebarType) { async closePane(paneId: SidebarType) {
return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX) return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)

View File

@ -1,9 +1,9 @@
import path from 'path'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import path from 'path'
test.describe('Import UI tests', () => { 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', async ({ test('shows toast when trying to sketch on imported face', async ({
context, context,
page, page,
homePage, homePage,
@ -44,8 +44,8 @@ profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02) |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close() |> close()
extrude001 = extrude(profile001, length = 100) extrude001 = extrude(profile001, length = 100)
sketch003 = startSketchOn(extrude001, face = seg02) sketch003 = startSketchOn(extrude001, seg02)
sketch002 = startSketchOn(extrude001, face = seg01)` sketch002 = startSketchOn(extrude001, seg01)`
) )
}) })
@ -93,6 +93,7 @@ sketch002 = startSketchOn(extrude001, face = seg01)`
await toolbar.startSketchPlaneSelection() await toolbar.startSketchPlaneSelection()
// Click on a face from the imported model // Click on a face from the imported model
// await new Promise(() => {})
await importedFaceClick() await importedFaceClick()
// Verify toast appears with correct content // Verify toast appears with correct content

View File

@ -1,64 +0,0 @@
import type { Reporter, TestCase, TestResult } from '@playwright/test/reporter'
class MyAPIReporter implements Reporter {
onTestEnd(test: TestCase, result: TestResult): void {
if (!process.env.TAB_API_URL || !process.env.TAB_API_KEY) {
return
}
const payload = {
// Required information
project: 'https://github.com/KittyCAD/modeling-app',
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(' '),
status: result.status,
// Optional information
duration: result.duration / 1000,
message: result.error?.stack,
target: process.env.TARGET || null,
platform: process.env.RUNNER_OS || process.platform,
// Extra test and result data
annotations: test.annotations.map((a) => a.type), // e.g. 'fail' or 'fixme'
retry: result.retry,
tags: test.tags, // e.g. '@snapshot' or '@skipWin'
// Extra environment variables
CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
CI_PR_NUMBER: process.env.CI_PR_NUMBER || null,
GITHUB_BASE_REF: process.env.GITHUB_BASE_REF || null,
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || null,
GITHUB_HEAD_REF: process.env.GITHUB_HEAD_REF || null,
GITHUB_REF_NAME: process.env.GITHUB_REF_NAME || null,
GITHUB_REF: process.env.GITHUB_REF || null,
GITHUB_SHA: process.env.GITHUB_SHA || null,
GITHUB_WORKFLOW: process.env.GITHUB_WORKFLOW || null,
RUNNER_ARCH: process.env.RUNNER_ARCH || null,
}
void (async () => {
try {
const response = await fetch(`${process.env.TAB_API_URL}/api/results`, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json',
'X-API-Key': process.env.TAB_API_KEY || '',
}),
body: JSON.stringify(payload),
})
if (!response.ok && !process.env.CI) {
console.error(
'TAB API - Failed to send test result:',
await response.text()
)
}
} catch {
if (!process.env.CI) {
console.error('TAB API - Unable to send test result')
}
}
})()
}
}
export default MyAPIReporter

View File

@ -1,5 +1,5 @@
import { join } from 'path'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { join } from 'path'
import { executorInputPath } from '@e2e/playwright/test-utils' import { executorInputPath } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'

View File

@ -1,13 +1,12 @@
import { join } from 'path'
import { PROJECT_SETTINGS_FILE_NAME } from '@src/lib/constants' import { PROJECT_SETTINGS_FILE_NAME } from '@src/lib/constants'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import { join } from 'path'
import type { NamedView } from '@rust/kcl-lib/bindings/NamedView' import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
import { import {
createProject, createProject,
perProjectSettingsToToml, perProjectsettingsToToml,
runningOnWindows,
tomlToPerProjectSettings, tomlToPerProjectSettings,
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
@ -58,11 +57,11 @@ function tomlStringOverWriteNamedViewUuids(toml: string): string {
settings.settings.app.named_views = remappedNamedViews settings.settings.app.named_views = remappedNamedViews
} }
} }
return perProjectSettingsToToml(settings) return perProjectsettingsToToml(settings)
} }
test.describe('Named view tests', () => { test.describe('Named view tests', () => {
test.skip(runningOnWindows(), 'Windows line endings break snapshot matching') test.skip() // TODO: Jace is working on these
test('Verify project.toml is not created', async ({ page }, testInfo) => { test('Verify project.toml is not created', async ({ page }, testInfo) => {
// Create project and load it // Create project and load it
const projectName = 'named-views' const projectName = 'named-views'
@ -106,9 +105,6 @@ test.describe('Named view tests', () => {
PROJECT_SETTINGS_FILE_NAME PROJECT_SETTINGS_FILE_NAME
) )
const toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Expect project.toml to be generated on disk since a named view was created // Expect project.toml to be generated on disk since a named view was created
await expect(async () => { await expect(async () => {
let exists = await fileExists(tempProjectSettingsFilePath) let exists = await fileExists(tempProjectSettingsFilePath)
@ -124,7 +120,7 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created.toml') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass() }).toPass()
}) })
test('Verify named view gets deleted', async ({ test('Verify named view gets deleted', async ({
@ -134,6 +130,7 @@ test.describe('Named view tests', () => {
}, testInfo) => { }, testInfo) => {
const projectName = 'named-views' const projectName = 'named-views'
const myNamedView1 = 'uuid1' const myNamedView1 = 'uuid1'
const myNamedView2 = 'uuid2'
// Create project and go into the project // Create project and go into the project
await createProject({ name: projectName, page }) await createProject({ name: projectName, page })
@ -145,9 +142,6 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView1) await cmdBar.argumentInput.fill(myNamedView1)
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
let toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Generate file paths for project.toml // Generate file paths for project.toml
const projectDirName = testInfo.outputPath('electron-test-projects-dir') const projectDirName = testInfo.outputPath('electron-test-projects-dir')
const tempProjectSettingsFilePath = join( const tempProjectSettingsFilePath = join(
@ -170,27 +164,24 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created.toml') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass() }).toPass()
// Delete a named view // Delete a named view
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
await cmdBar.chooseCommand('delete named view') await cmdBar.chooseCommand('delete named view')
cmdBar.selectOption({ name: myNamedView1 }) cmdBar.selectOption({ name: myNamedView2 })
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
toastMessage = page.getByText('Named view uuid1 removed.')
await expect(toastMessage).toBeInViewport()
await expect(async () => { await expect(async () => {
// Read project.toml into memory again since we deleted a named view // Read project.toml into memory again since we deleted a named view
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
tomlString = tomlStringOverWriteNamedViewUuids(tomlString) tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
// Write the entire tomlString to a snapshot. // // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted.toml') expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
}).toPass() }).toPass()
}) })
test('Verify named view gets loaded', async ({ test('Verify named view gets loaded', async ({
@ -211,9 +202,6 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView) await cmdBar.argumentInput.fill(myNamedView)
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
let toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Generate file paths for project.toml // Generate file paths for project.toml
const projectDirName = testInfo.outputPath('electron-test-projects-dir') const projectDirName = testInfo.outputPath('electron-test-projects-dir')
const tempProjectSettingsFilePath = join( const tempProjectSettingsFilePath = join(
@ -236,7 +224,7 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created.toml') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass() }).toPass()
// Create a load a named view // Create a load a named view
@ -270,19 +258,26 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView1) await cmdBar.argumentInput.fill(myNamedView1)
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
let toastMessage = page.getByText('Named view uuid1 created.') await page.waitForTimeout(1000)
await expect(toastMessage).toBeInViewport()
await scene.moveCameraTo({ x: 608, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }) const orbitMouseStart = { x: 800, y: 130 }
await page.waitForTimeout(2500) const orbitMouseEnd = { x: 0, y: 130 }
await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y)
await page.mouse.down({ button: 'middle' })
await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, {
steps: 3,
})
await page.mouse.up({ button: 'middle' })
await page.waitForTimeout(1000)
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
await cmdBar.chooseCommand('create named view') await cmdBar.chooseCommand('create named view')
await cmdBar.argumentInput.fill(myNamedView2) await cmdBar.argumentInput.fill(myNamedView2)
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
toastMessage = page.getByText('Named view uuid2 created.') // Wait a moment for the project.toml to get written to disk with the new view point
await expect(toastMessage).toBeInViewport() await page.waitForTimeout(1000)
// Generate paths for the project.toml // Generate paths for the project.toml
const tempProjectSettingsFilePath = join( const tempProjectSettingsFilePath = join(
@ -305,9 +300,7 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot( expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created')
'verify-two-named-view-gets-created.toml'
)
}).toPass() }).toPass()
}) })
}) })

View File

@ -0,0 +1,16 @@
[settings]
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -0,0 +1,16 @@
[settings]
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -1,5 +0,0 @@
[settings]
app = { }
modeling = { }
text_editor = { }
command_bar = { }

View File

@ -17,12 +17,12 @@ version = 1
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7] [settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
name = "uuid2" name = "uuid2"
eye_offset = 608 eye_offset = 1_378.0059
fov_y = 45 fov_y = 45
is_ortho = false is_ortho = false
ortho_scale_enabled = true ortho_scale_enabled = true
ortho_scale_factor = 1.6 ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ] pivot_position = [ 1_826.5239, 0.0, 0.0 ]
pivot_rotation = [ 0.5, 0.5, 0.5, 0.5 ] pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z" world_coord_system = "right_handed_up_z"
version = 1 version = 1

View File

@ -0,0 +1,28 @@
[settings]
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
name = "uuid2"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 1_826.5239, 0.0, 0.0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -534,7 +534,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
const expected = 'Open project' const expected = 'Open project'
expect(actual).toBe(expected) expect(actual).toBe(expected)
}) })
test('Modeling.File.Load external model', async ({ test('Modeling.File.Load a sample model', async ({
tronApp, tronApp,
cmdBar, cmdBar,
page, page,
@ -555,10 +555,10 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
throw new Error('app or app.applicationMenu is missing') throw new Error('app or app.applicationMenu is missing')
} }
const openProject = app.applicationMenu.getMenuItemById( const openProject = app.applicationMenu.getMenuItemById(
'File.Load external model' 'File.Load a sample model'
) )
if (!openProject) { if (!openProject) {
throw new Error('File.Load external model') throw new Error('File.Load a sample model')
} }
openProject.click() openProject.click()
}) })
@ -568,7 +568,44 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
const actual = await cmdBar.cmdBarElement const actual = await cmdBar.cmdBarElement
.getByTestId('command-name') .getByTestId('command-name')
.textContent() .textContent()
const expected = 'Load external model' const expected = 'Open sample'
expect(actual).toBe(expected)
})
test('Modeling.File.Insert from project file', async ({
tronApp,
cmdBar,
page,
homePage,
scene,
}) => {
if (!tronApp) {
throwTronAppMissing()
return
}
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) {
throw new Error('app or app.applicationMenu is missing')
}
const openProject = app.applicationMenu.getMenuItemById(
'File.Insert from project file'
)
if (!openProject) {
throw new Error('File.Insert from project file')
}
openProject.click()
})
// Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists
const actual = await cmdBar.cmdBarElement
.getByTestId('command-name')
.textContent()
const expected = 'Insert'
expect(actual).toBe(expected) expect(actual).toBe(expected)
}) })
test('Modeling.File.Export current part', async ({ test('Modeling.File.Export current part', async ({
@ -2122,44 +2159,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
expect(actual).toBe(expected) expect(actual).toBe(expected)
}) })
test('Modeling.Design.Insert from project file', async ({
tronApp,
cmdBar,
page,
homePage,
scene,
}) => {
if (!tronApp) {
throwTronAppMissing()
return
}
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) {
throw new Error('app or app.applicationMenu is missing')
}
const openProject = app.applicationMenu.getMenuItemById(
'Design.Insert from project file'
)
if (!openProject) {
throw new Error('Design.Insert from project file')
}
openProject.click()
})
// Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists
const actual = await cmdBar.cmdBarElement
.getByTestId('command-name')
.textContent()
const expected = 'Insert'
expect(actual).toBe(expected)
})
test('Modeling.Design.Create with Zoo Text-To-CAD', async ({ test('Modeling.Design.Create with Zoo Text-To-CAD', async ({
tronApp, tronApp,
cmdBar, cmdBar,

View File

@ -1,7 +1,7 @@
import { join } from 'path' import { bracket } from '@src/lib/exampleKcl'
import { bracket } from '@e2e/playwright/fixtures/bracket'
import { onboardingPaths } from '@src/routes/Onboarding/paths' import { onboardingPaths } from '@src/routes/Onboarding/paths'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { join } from 'path'
import { expectPixelColor } from '@e2e/playwright/fixtures/sceneFixture' import { expectPixelColor } from '@e2e/playwright/fixtures/sceneFixture'
import { import {
@ -15,7 +15,6 @@ import {
executorInputPath, executorInputPath,
getUtils, getUtils,
orRunWhenFullSuiteEnabled, orRunWhenFullSuiteEnabled,
runningOnWindows,
settingsToToml, settingsToToml,
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
@ -49,7 +48,10 @@ test.describe('Onboarding tests', () => {
await expect(page.getByText('Welcome to Design Studio! This')).toBeVisible() await expect(page.getByText('Welcome to Design Studio! This')).toBeVisible()
// *and* that the code is shown in the editor // *and* that the code is shown in the editor
await expect(page.locator('.cm-content')).toContainText('// Shelf Bracket') await expect(page.locator('.cm-content')).toContainText(
'// Shelf Bracket',
{ timeout: 10_000 }
)
// Make sure the model loaded // Make sure the model loaded
const XYPlanePoint = { x: 774, y: 116 } as const const XYPlanePoint = { x: 774, y: 116 } as const
@ -92,7 +94,8 @@ test.describe('Onboarding tests', () => {
// *and* that the code is shown in the editor // *and* that the code is shown in the editor
await expect(page.locator('.cm-content')).toContainText( await expect(page.locator('.cm-content')).toContainText(
'// Shelf Bracket' '// Shelf Bracket',
{ timeout: 10_000 }
) )
// TODO: jess make less shit // TODO: jess make less shit
@ -280,9 +283,6 @@ test.describe('Onboarding tests', () => {
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
if (runningOnWindows()) {
test.fixme(orRunWhenFullSuiteEnabled())
}
await tronApp.cleanProjectDir({ await tronApp.cleanProjectDir({
app: { app: {
onboarding_status: '/parametric-modeling', onboarding_status: '/parametric-modeling',

View File

@ -1,5 +1,5 @@
import path from 'path'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import path from 'path'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture' import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture' import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'

View File

@ -1,6 +1,6 @@
import type { Locator, Page } from '@playwright/test'
import fs from 'node:fs/promises' import fs from 'node:fs/promises'
import path from 'node:path' import path from 'node:path'
import type { Locator, Page } from '@playwright/test'
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture' import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture' import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
@ -220,7 +220,7 @@ test.describe('Point-and-click tests', () => {
)`, )`,
afterChamferSelectSnippet: afterChamferSelectSnippet:
'sketch002 = startSketchOn(extrude001, face = seg03)', 'sketch002 = startSketchOn(extrude001, seg03)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([205.96, 254.59], sketch002)', 'startProfileAt([205.96, 254.59], sketch002)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002) afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002)
@ -244,7 +244,7 @@ test.describe('Point-and-click tests', () => {
)`, )`,
afterChamferSelectSnippet: afterChamferSelectSnippet:
'sketch003 = startSketchOn(extrude001, face = seg04)', 'sketch003 = startSketchOn(extrude001, seg04)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([-209.64, 255.28], sketch003)', 'startProfileAt([-209.64, 255.28], sketch003)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.56,tag=$rectangleSegmentA003) afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.56,tag=$rectangleSegmentA003)
@ -266,7 +266,7 @@ test.describe('Point-and-click tests', () => {
] ]
)`, )`,
afterChamferSelectSnippet: afterChamferSelectSnippet:
'sketch004 = startSketchOn(extrude001, face = seg05)', 'sketch004 = startSketchOn(extrude001, seg05)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([82.57, 322.96], sketch004)', 'startProfileAt([82.57, 322.96], sketch004)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.16,tag=$rectangleSegmentA004) afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.16,tag=$rectangleSegmentA004)
@ -284,7 +284,7 @@ test.describe('Point-and-click tests', () => {
beforeChamferSnippetEnd: beforeChamferSnippetEnd:
'|> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)])', '|> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)])',
afterChamferSelectSnippet: afterChamferSelectSnippet:
'sketch005 = startSketchOn(extrude001, face = seg06)', 'sketch005 = startSketchOn(extrude001, seg06)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([-23.43, 19.69], sketch005)', 'startProfileAt([-23.43, 19.69], sketch005)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=9.1,tag=$rectangleSegmentA005) afterRectangle2ndClickSnippet: `angledLine(angle=0,length=9.1,tag=$rectangleSegmentA005)
@ -309,28 +309,28 @@ extrude001 = extrude(sketch001, length = 100)
|> chamfer(length = 30, tags = [seg01], tag = $seg04) |> chamfer(length = 30, tags = [seg01], tag = $seg04)
|> chamfer(length = 30, tags = [getNextAdjacentEdge(seg02)], tag = $seg05) |> chamfer(length = 30, tags = [getNextAdjacentEdge(seg02)], tag = $seg05)
|> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)], tag = $seg06) |> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)], tag = $seg06)
sketch005 = startSketchOn(extrude001, face = seg06) sketch005 = startSketchOn(extrude001, seg06)
profile004=startProfileAt([-23.43,19.69], sketch005) profile004=startProfileAt([-23.43,19.69], sketch005)
|> angledLine(angle = 0, length = 9.1, tag = $rectangleSegmentA005) |> angledLine(angle = 0, length = 9.1, tag = $rectangleSegmentA005)
|> angledLine(angle = segAng(rectangleSegmentA005) - 90, length = 84.07) |> angledLine(angle = segAng(rectangleSegmentA005) - 90, length = 84.07)
|> angledLine(angle = segAng(rectangleSegmentA005), length = -segLen(rectangleSegmentA005)) |> angledLine(angle = segAng(rectangleSegmentA005), length = -segLen(rectangleSegmentA005))
|> line(endAbsolute=[profileStartX(%), profileStartY(%)]) |> line(endAbsolute=[profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch004 = startSketchOn(extrude001, face = seg05) sketch004 = startSketchOn(extrude001, seg05)
profile003 = startProfileAt([82.57, 322.96], sketch004) profile003 = startProfileAt([82.57, 322.96], sketch004)
|> angledLine(angle = 0, length = 11.16, tag = $rectangleSegmentA004) |> angledLine(angle = 0, length = 11.16, tag = $rectangleSegmentA004)
|> angledLine(angle = segAng(rectangleSegmentA004) - 90, length = 103.07) |> angledLine(angle = segAng(rectangleSegmentA004) - 90, length = 103.07)
|> angledLine(angle = segAng(rectangleSegmentA004), length = -segLen(rectangleSegmentA004)) |> angledLine(angle = segAng(rectangleSegmentA004), length = -segLen(rectangleSegmentA004))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch003 = startSketchOn(extrude001, face = seg04) sketch003 = startSketchOn(extrude001, seg04)
profile002 = startProfileAt([-209.64, 255.28], sketch003) profile002 = startProfileAt([-209.64, 255.28], sketch003)
|> angledLine(angle = 0, length = 11.56, tag = $rectangleSegmentA003) |> angledLine(angle = 0, length = 11.56, tag = $rectangleSegmentA003)
|> angledLine(angle = segAng(rectangleSegmentA003) - 90, length = 106.84) |> angledLine(angle = segAng(rectangleSegmentA003) - 90, length = 106.84)
|> angledLine(angle = segAng(rectangleSegmentA003), length = -segLen(rectangleSegmentA003)) |> angledLine(angle = segAng(rectangleSegmentA003), length = -segLen(rectangleSegmentA003))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch002 = startSketchOn(extrude001, face = seg03) sketch002 = startSketchOn(extrude001, seg03)
profile001 = startProfileAt([205.96, 254.59], sketch002) profile001 = startProfileAt([205.96, 254.59], sketch002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002) |> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26) |> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26)
@ -383,7 +383,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
])`, ])`,
beforeChamferSnippetEnd: ')', beforeChamferSnippetEnd: ')',
afterChamferSelectSnippet: afterChamferSelectSnippet:
'sketch002 = startSketchOn(extrude001, face = seg03)', 'sketch002 = startSketchOn(extrude001, seg03)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([205.96, 254.59], sketch002)', 'startProfileAt([205.96, 254.59], sketch002)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002) afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002)
@ -416,7 +416,7 @@ chamf = chamfer(
getNextAdjacentEdge(seg02) getNextAdjacentEdge(seg02)
], ],
) )
sketch002 = startSketchOn(extrude001, face = seg03) sketch002 = startSketchOn(extrude001, seg03)
profile001 = startProfileAt([205.96, 254.59], sketch002) profile001 = startProfileAt([205.96, 254.59], sketch002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002) |> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26) |> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26)
@ -550,7 +550,7 @@ openSketch = startSketchOn(XY)
|> startProfileAt([-5, 0], %) |> startProfileAt([-5, 0], %)
|> line(endAbsolute = [0, 5]) |> line(endAbsolute = [0, 5])
|> xLine(length = 5) |> xLine(length = 5)
|> tangentialArc(endAbsolute = [10, 0]) |> tangentialArcTo([10, 0], %)
` `
const viewPortSize = { width: 1000, height: 500 } const viewPortSize = { width: 1000, height: 500 }
await page.setBodyDimensions(viewPortSize) await page.setBodyDimensions(viewPortSize)
@ -634,8 +634,8 @@ openSketch = startSketchOn(XY)
// Wait for enter sketch mode to complete // Wait for enter sketch mode to complete
await page.waitForTimeout(500) await page.waitForTimeout(500)
await editor.expectState({ await editor.expectState({
activeLines: [`|>tangentialArc(endAbsolute=[10,0])`], activeLines: [`|>tangentialArcTo([10,0],%)`],
highlightedCode: 'tangentialArc(endAbsolute=[10,0])', highlightedCode: 'tangentialArcTo([10,0],%)',
diagnostics: [], diagnostics: [],
}) })
}) })
@ -1624,7 +1624,7 @@ profile001 = circle(sketch001, center = [0, 0], radius = 500)
sketch002 = startSketchOn(XZ) sketch002 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> xLine(length = -500) |> xLine(length = -500)
|> tangentialArc(endAbsolute = [-2000, 500])`, |> tangentialArcTo([-2000, 500], %)`,
}, },
{ {
targetType: 'rectangle', targetType: 'rectangle',
@ -1640,7 +1640,7 @@ profile001 = startProfileAt([-400, -400], sketch001)
sketch002 = startSketchOn(XZ) sketch002 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> xLine(length = -500) |> xLine(length = -500)
|> tangentialArc(endAbsolute = [-2000, 500])`, |> tangentialArcTo([-2000, 500], %)`,
}, },
] ]
sweepCases.map(({ initialCode, targetType, testPoint }) => { sweepCases.map(({ initialCode, targetType, testPoint }) => {
@ -2935,9 +2935,9 @@ extrude001 = extrude(sketch001, length = 30)
const testPoint = { x: 575, y: 200 } const testPoint = { x: 575, y: 200 }
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y) const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
const shellDeclaration = const shellDeclaration =
'shell001 = shell(extrude001, faces = [END], thickness = 5)' "shell001 = shell(extrude001, faces = ['end'], thickness = 5)"
const editedShellDeclaration = const editedShellDeclaration =
'shell001 = shell(extrude001, faces = [END], thickness = 2)' "shell001 = shell(extrude001, faces = ['end'], thickness = 2)"
await test.step(`Look for the grey of the shape`, async () => { await test.step(`Look for the grey of the shape`, async () => {
await scene.expectPixelColor([127, 127, 127], testPoint, 15) await scene.expectPixelColor([127, 127, 127], testPoint, 15)
@ -3079,9 +3079,9 @@ extrude001 = extrude(sketch001, length = 40)
const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y + 70) const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y + 70)
const mutatedCode = 'xLine(length = -40, tag = $seg01)' const mutatedCode = 'xLine(length = -40, tag = $seg01)'
const shellDeclaration = const shellDeclaration =
'shell001 = shell(extrude001, faces = [END, seg01], thickness = 5)' "shell001 = shell(extrude001, faces = ['end', seg01], thickness = 5)"
const editedShellDeclaration = const editedShellDeclaration =
'shell001 = shell(extrude001, faces = [END, seg01], thickness = 1)' "shell001 = shell(extrude001, faces = ['end', seg01], thickness = 1)"
await test.step(`Look for the grey of the shape`, async () => { await test.step(`Look for the grey of the shape`, async () => {
await scene.expectPixelColor([99, 99, 99], testPoint, 15) await scene.expectPixelColor([99, 99, 99], testPoint, 15)
@ -3188,7 +3188,7 @@ sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100) |> circle(center = [0, 0], radius = 100)
|> extrude(length = 100) |> extrude(length = 100)
sketch002 = startSketchOn(sketch001, face = 'END') sketch002 = startSketchOn(sketch001, 'END')
|> circle(center = [0, 0], radius = 50) |> circle(center = [0, 0], radius = 50)
|> extrude(length = 50) |> extrude(length = 50)
`, `,
@ -3197,7 +3197,7 @@ sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100) |> circle(center = [0, 0], radius = 100)
extrude001 = extrude(sketch001, length = 100) extrude001 = extrude(sketch001, length = 100)
sketch002 = startSketchOn(extrude001, face = 'END') sketch002 = startSketchOn(extrude001, 'END')
|> circle(center = [0, 0], radius = 50) |> circle(center = [0, 0], radius = 50)
extrude002 = extrude(sketch002, length = 50) extrude002 = extrude(sketch002, length = 50)
`, `,
@ -3224,7 +3224,7 @@ extrude002 = extrude(sketch002, length = 50)
const testPoint = { x: 580, y: 320 } const testPoint = { x: 580, y: 320 }
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y) const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
const shellTarget = hasExtrudesInPipe ? 'sketch002' : 'extrude002' const shellTarget = hasExtrudesInPipe ? 'sketch002' : 'extrude002'
const shellDeclaration = `shell001 = shell(${shellTarget}, faces = [END], thickness = 5)` const shellDeclaration = `shell001 = shell(${shellTarget}, faces = ['end'], thickness = 5)`
await test.step(`Look for the grey of the shape`, async () => { await test.step(`Look for the grey of the shape`, async () => {
await scene.expectPixelColor([113, 113, 113], testPoint, 15) await scene.expectPixelColor([113, 113, 113], testPoint, 15)
@ -3299,7 +3299,7 @@ profile001 = startProfileAt([-20, 20], sketch001)
` `
const extrudeCode = `extrude001 = extrude(profile001, length = 40) const extrudeCode = `extrude001 = extrude(profile001, length = 40)
` `
const shellCode = `shell001 = shell(extrude001, faces = [END], thickness = 5) const shellCode = `shell001 = shell(extrude001, faces = ['end'], thickness = 5)
` `
const initialCode = sketchCode + extrudeCode + shellCode const initialCode = sketchCode + extrudeCode + shellCode
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
@ -3447,7 +3447,7 @@ tag=$rectangleSegmentC001,
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 200) extrude001 = extrude(sketch001, length = 200)
sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001) sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> startProfileAt([-66.77, 84.81], %) |> startProfileAt([-66.77, 84.81], %)
|> angledLine(angle = 180, length = 27.08, tag = $rectangleSegmentA002) |> angledLine(angle = 180, length = 27.08, tag = $rectangleSegmentA002)
|> angledLine( |> angledLine(
@ -3535,7 +3535,7 @@ tag=$rectangleSegmentC002,
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 50) extrude001 = extrude(sketch001, length = 50)
sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001) sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> circle(center = [-11.34, 10.0], radius = 8.69) |> circle(center = [-11.34, 10.0], radius = 8.69)
` `
@ -3623,7 +3623,7 @@ sketch002 = startSketchOn(extrude001, face = rectangleSegmentA001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 5) extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, face = 'START') sketch003 = startSketchOn(extrude001, 'START')
|> circle( |> circle(
center = [-0.69, 0.56], center = [-0.69, 0.56],
radius = 0.28 radius = 0.28

View File

@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import { DEFAULT_PROJECT_KCL_FILE } from '@src/lib/constants' import { DEFAULT_PROJECT_KCL_FILE } from '@src/lib/constants'
import fs from 'fs'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import path from 'path'
import type { Paths } from '@e2e/playwright/test-utils' import type { Paths } from '@e2e/playwright/test-utils'
import { import {

View File

@ -68,10 +68,12 @@ test.describe('edit with AI example snapshots', () => {
body1CapCoords.x, body1CapCoords.x,
body1CapCoords.y body1CapCoords.y
) )
const yellow: [number, number, number] = [179, 179, 131]
const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
await test.step('wait for scene to load select body and check selection came through', async () => { await test.step('wait for scene to load select body and check selection came through', async () => {
await clickBody1Cap() await clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({ await editor.expectState({
highlightedCode: '', highlightedCode: '',
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'], activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],

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