Merge remote-tracking branch 'origin/main' into paultag/import
This commit is contained in:
39
.github/workflows/build-apps.yml
vendored
39
.github/workflows/build-apps.yml
vendored
@ -33,26 +33,63 @@ jobs:
|
||||
|
||||
- run: yarn install
|
||||
|
||||
- id: filter
|
||||
name: Check for Rust changes
|
||||
uses: dorny/paths-filter@v3
|
||||
with:
|
||||
filters: |
|
||||
rust:
|
||||
- 'rust/**'
|
||||
|
||||
- name: Download Wasm Cache
|
||||
id: download-wasm
|
||||
if: ${{ github.event_name == 'pull_request' && steps.filter.outputs.rust == 'false' }}
|
||||
uses: dawidd6/action-download-artifact@v7
|
||||
continue-on-error: true
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
name: wasm-bundle
|
||||
workflow: build-and-store-wasm.yml
|
||||
branch: main
|
||||
path: rust/kcl-wasm-lib/pkg
|
||||
|
||||
- name: Build WASM condition
|
||||
id: wasm
|
||||
run: |
|
||||
set -euox pipefail
|
||||
# Build wasm if this is a push to main or tag, there are Rust changes, or
|
||||
# downloading from the wasm cache failed.
|
||||
if [[ ${{github.event_name}} == 'push' || ${{steps.filter.outputs.rust}} == 'true' || ${{steps.download-wasm.outcome}} == 'failure' ]]; then
|
||||
echo "should-build-wasm=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "should-build-wasm=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Use correct Rust toolchain
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
|
||||
- name: Install rust
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false # Configured below.
|
||||
|
||||
# TODO: see if we can fetch from main instead if no diff at rust
|
||||
- uses: taiki-e/install-action@955a6ff1416eae278c9f833008a9beb4b7f9afe3
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
with:
|
||||
tool: wasm-pack
|
||||
|
||||
- name: Rust Cache
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: rust
|
||||
|
||||
- name: Run build:wasm
|
||||
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
|
||||
run: "yarn build:wasm"
|
||||
|
||||
- name: Set nightly version, product name, release notes, and icons
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import {
|
||||
getUtils,
|
||||
TEST_COLORS,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import { HomePageFixture } from './fixtures/homePageFixture'
|
||||
import { getUtils } from './test-utils'
|
||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||
|
@ -10,7 +10,11 @@ import fsp from 'fs/promises'
|
||||
test(
|
||||
'export works on the first try',
|
||||
{ tag: ['@electron', '@skipLocalEngine'] },
|
||||
async ({ page, context, scene }, testInfo) => {
|
||||
async ({ page, context, scene, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await Promise.all([fsp.mkdir(bracketDir, { recursive: true })])
|
||||
@ -86,7 +90,7 @@ test(
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
const firstFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(page),
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
)
|
||||
await test.step('Check the export size', async () => {
|
||||
@ -165,7 +169,7 @@ test(
|
||||
]))
|
||||
|
||||
const secondFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(page),
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
)
|
||||
await test.step('Check the export size', async () => {
|
||||
|
@ -158,11 +158,14 @@ test.describe('when using the file tree to', () => {
|
||||
await createNewFile('lee')
|
||||
|
||||
await test.step('Postcondition: there are 5 new lee-*.kcl files', async () => {
|
||||
await expect(
|
||||
await expect
|
||||
.poll(() =>
|
||||
page
|
||||
.locator('[data-testid="file-pane-scroll-container"] button')
|
||||
.filter({ hasText: /lee[-]?[0-5]?/ })
|
||||
).toHaveCount(5)
|
||||
.count()
|
||||
)
|
||||
.toEqual(5)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -27,28 +27,19 @@ type CmdBarSerialised =
|
||||
|
||||
export class CmdBarFixture {
|
||||
public page: Page
|
||||
|
||||
get cmdBarOpenBtn() {
|
||||
return this.page.getByTestId('command-bar-open-button')
|
||||
}
|
||||
|
||||
get cmdBarElement() {
|
||||
return this.page.getByTestId('command-bar')
|
||||
}
|
||||
public cmdBarOpenBtn!: Locator
|
||||
public cmdBarElement!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.cmdBarOpenBtn = this.page.getByTestId('command-bar-open-button')
|
||||
this.cmdBarElement = this.page.getByTestId('command-bar')
|
||||
}
|
||||
|
||||
get currentArgumentInput() {
|
||||
return this.page.getByTestId('cmd-bar-arg-value')
|
||||
}
|
||||
|
||||
// Put all selectors here because this method is re-run on fixture creation.
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
}
|
||||
|
||||
private _serialiseCmdBar = async (): Promise<CmdBarSerialised> => {
|
||||
if (!(await this.page.getByTestId('command-bar-wrapper').isVisible())) {
|
||||
return { stage: 'commandBarClosed' }
|
||||
|
@ -24,11 +24,6 @@ export class EditorFixture {
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.reConstruct(page)
|
||||
}
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
|
||||
this.codeContent = page.locator('.cm-content[data-language="kcl"]')
|
||||
this.diagnosticsTooltip = page.locator('.cm-tooltip-lint')
|
||||
this.diagnosticsGutterIcon = page.locator('.cm-lint-marker-error')
|
||||
|
@ -1,13 +1,31 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
|
||||
import type {
|
||||
BrowserContext,
|
||||
ElectronApplication,
|
||||
Fixtures as PlaywrightFixtures,
|
||||
TestInfo,
|
||||
Page,
|
||||
} from '@playwright/test'
|
||||
|
||||
import { getUtils, setup, setupElectron } from '../test-utils'
|
||||
import {
|
||||
_electron as electron,
|
||||
PlaywrightTestArgs,
|
||||
PlaywrightWorkerArgs,
|
||||
} from '@playwright/test'
|
||||
|
||||
import * as TOML from '@iarna/toml'
|
||||
import {
|
||||
TEST_SETTINGS_KEY,
|
||||
TEST_SETTINGS_CORRUPTED,
|
||||
TEST_SETTINGS,
|
||||
TEST_SETTINGS_DEFAULT_THEME,
|
||||
} from '../storageStates'
|
||||
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
|
||||
import { getUtils, setup } from '../test-utils'
|
||||
import fsp from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import fs from 'node:fs'
|
||||
import path from 'path'
|
||||
import { CmdBarFixture } from './cmdBarFixture'
|
||||
import { EditorFixture } from './editorFixture'
|
||||
import { ToolbarFixture } from './toolbarFixture'
|
||||
@ -23,7 +41,7 @@ export class AuthenticatedApp {
|
||||
public readonly testInfo: TestInfo
|
||||
public readonly viewPortSize = { width: 1200, height: 500 }
|
||||
public electronApp: undefined | ElectronApplication
|
||||
public dir: string = ''
|
||||
public projectDirName: string = ''
|
||||
|
||||
constructor(context: BrowserContext, page: Page, testInfo: TestInfo) {
|
||||
this.context = context
|
||||
@ -46,7 +64,7 @@ export class AuthenticatedApp {
|
||||
}
|
||||
getInputFile = (fileName: string) => {
|
||||
return fsp.readFile(
|
||||
join('rust', 'kcl-lib', 'e2e', 'executor', 'inputs', fileName),
|
||||
path.join('rust', 'kcl-lib', 'e2e', 'executor', 'inputs', fileName),
|
||||
'utf-8'
|
||||
)
|
||||
}
|
||||
@ -59,101 +77,300 @@ export interface Fixtures {
|
||||
scene: SceneFixture
|
||||
homePage: HomePageFixture
|
||||
}
|
||||
export class AuthenticatedTronApp {
|
||||
public originalPage: Page
|
||||
public page: Page
|
||||
public browserContext: BrowserContext
|
||||
public context: BrowserContext
|
||||
public readonly testInfo: TestInfo
|
||||
public electronApp: ElectronApplication | undefined
|
||||
public readonly viewPortSize = { width: 1200, height: 500 }
|
||||
public dir: string = ''
|
||||
|
||||
constructor(
|
||||
browserContext: BrowserContext,
|
||||
originalPage: Page,
|
||||
testInfo: TestInfo
|
||||
) {
|
||||
this.page = originalPage
|
||||
this.originalPage = originalPage
|
||||
this.browserContext = browserContext
|
||||
// Will be overwritten in the initializer
|
||||
this.context = browserContext
|
||||
this.testInfo = testInfo
|
||||
export class ElectronZoo {
|
||||
public available: boolean = true
|
||||
public electron!: ElectronApplication
|
||||
public firstUrl = ''
|
||||
public viewPortSize = { width: 1200, height: 500 }
|
||||
public projectDirName = ''
|
||||
|
||||
public page!: Page
|
||||
public context!: BrowserContext
|
||||
|
||||
constructor() {}
|
||||
|
||||
async makeAvailableAgain() {
|
||||
// Help remote end by signaling we're done with the connection.
|
||||
await this.page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
if (!window.engineCommandManager.engineConnection?.state?.type) {
|
||||
return resolve(undefined)
|
||||
}
|
||||
async initialise(
|
||||
arg: {
|
||||
fixtures: Partial<Fixtures>
|
||||
folderSetupFn?: (projectDirName: string) => Promise<void>
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: DeepPartial<Settings>
|
||||
} = { fixtures: {} }
|
||||
) {
|
||||
const { electronApp, page, context, dir } = await setupElectron({
|
||||
testInfo: this.testInfo,
|
||||
folderSetupFn: arg.folderSetupFn,
|
||||
cleanProjectDir: arg.cleanProjectDir,
|
||||
appSettings: arg.appSettings,
|
||||
viewport: this.viewPortSize,
|
||||
})
|
||||
this.page = page
|
||||
|
||||
// These assignments "fix" some brokenness in the Playwright Workbench when
|
||||
// running against electron applications.
|
||||
// The timeline is still broken but failure screenshots work again.
|
||||
this.context = context
|
||||
// TODO: try to get this to work again for screenshots, but it messed with test ends when enabled
|
||||
// Object.assign(this.browserContext, this.context)
|
||||
|
||||
this.electronApp = electronApp
|
||||
this.dir = dir
|
||||
|
||||
// Easier to access throughout utils
|
||||
this.page.dir = dir
|
||||
|
||||
// Setup localStorage, addCookies, reload
|
||||
await setup(this.context, this.page, this.testInfo)
|
||||
|
||||
for (const key of unsafeTypedKeys(arg.fixtures)) {
|
||||
const fixture = arg.fixtures[key]
|
||||
window.engineCommandManager.tearDown()
|
||||
// Keep polling (per js event tick) until state is Disconnected.
|
||||
const checkDisconnected = () => {
|
||||
// It's possible we never even created an engineConnection
|
||||
// e.g. never left Projects view.
|
||||
if (
|
||||
!fixture ||
|
||||
fixture instanceof AuthenticatedApp ||
|
||||
fixture instanceof AuthenticatedTronApp
|
||||
)
|
||||
continue
|
||||
fixture.reConstruct(page)
|
||||
window.engineCommandManager?.engineConnection?.state.type ===
|
||||
'disconnected'
|
||||
) {
|
||||
return resolve(undefined)
|
||||
}
|
||||
setTimeout(checkDisconnected, 0)
|
||||
}
|
||||
checkDisconnected()
|
||||
})
|
||||
})
|
||||
|
||||
await this.context.tracing.stopChunk({ path: 'trace.zip' })
|
||||
|
||||
// Only after cleanup we're ready.
|
||||
this.available = true
|
||||
}
|
||||
|
||||
close = async () => {
|
||||
await this.electronApp?.close?.()
|
||||
async createInstanceIfMissing(testInfo: TestInfo) {
|
||||
// Create or otherwise clear the folder.
|
||||
this.projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
|
||||
// We need to expose this in order for some tests that require folder
|
||||
// creation and some code below.
|
||||
const that = this
|
||||
|
||||
const options = {
|
||||
args: ['.', '--no-sandbox'],
|
||||
env: {
|
||||
...process.env,
|
||||
TEST_SETTINGS_FILE_KEY: this.projectDirName,
|
||||
IS_PLAYWRIGHT: 'true',
|
||||
},
|
||||
...(process.env.ELECTRON_OVERRIDE_DIST_PATH
|
||||
? {
|
||||
executablePath:
|
||||
process.env.ELECTRON_OVERRIDE_DIST_PATH + 'electron',
|
||||
}
|
||||
debugPause = () =>
|
||||
new Promise(() => {
|
||||
console.log('UN-RESOLVING PROMISE')
|
||||
: {}),
|
||||
...(process.env.PLAYWRIGHT_RECORD_VIDEO
|
||||
? {
|
||||
recordVideo: {
|
||||
dir: testInfo.snapshotPath(),
|
||||
size: this.viewPortSize,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
// Do this once and then reuse window on subsequent calls.
|
||||
if (!this.electron) {
|
||||
this.electron = await electron.launch(options)
|
||||
this.context = this.electron.context()
|
||||
this.page = await this.electron.firstWindow()
|
||||
await this.context.tracing.start({ screenshots: true, snapshots: true })
|
||||
}
|
||||
|
||||
await this.context.tracing.startChunk()
|
||||
|
||||
await setup(this.context, this.page, testInfo)
|
||||
|
||||
await this.cleanProjectDir()
|
||||
|
||||
// Create a consistent way to resize the page across electron and web.
|
||||
// (lee) I had to do everything in the book to make electron change its
|
||||
// damn window size. I succeeded in making it consistently and reliably
|
||||
// do it after a whole afternoon.
|
||||
this.page.setBodyDimensions = async function (dims: {
|
||||
width: number
|
||||
height: number
|
||||
}) {
|
||||
await this.setViewportSize(dims)
|
||||
|
||||
await that.electron?.evaluateHandle(async ({ app }, dims) => {
|
||||
// @ts-ignore sorry jon but see comment in main.ts why this is ignored
|
||||
await app.resizeWindow(dims.width, dims.height)
|
||||
}, dims)
|
||||
|
||||
return this.evaluate(async (dims: { width: number; height: number }) => {
|
||||
await window.electron.resizeWindow(dims.width, dims.height)
|
||||
window.document.body.style.width = dims.width + 'px'
|
||||
window.document.body.style.height = dims.height + 'px'
|
||||
window.document.documentElement.style.width = dims.width + 'px'
|
||||
window.document.documentElement.style.height = dims.height + 'px'
|
||||
}, dims)
|
||||
}
|
||||
|
||||
await this.page.setBodyDimensions(this.viewPortSize)
|
||||
|
||||
this.context.folderSetupFn = async function (fn) {
|
||||
return fn(that.projectDirName)
|
||||
.then(() => that.page.reload())
|
||||
.then(() => ({
|
||||
dir: that.projectDirName,
|
||||
}))
|
||||
}
|
||||
|
||||
// We need to patch this because addInitScript will bind too late in our
|
||||
// electron tests, never running. We need to call reload() after each call
|
||||
// to guarantee it runs.
|
||||
const oldContextAddInitScript = this.context.addInitScript
|
||||
this.context.addInitScript = async function (a, b) {
|
||||
// @ts-ignore pretty sure way out of tsc's type checking capabilities.
|
||||
// This code works perfectly fine.
|
||||
await oldContextAddInitScript.apply(this, [a, b])
|
||||
await that.page.reload()
|
||||
}
|
||||
|
||||
// No idea why we mix and match page and context's addInitScript but we do
|
||||
const oldPageAddInitScript = this.page.addInitScript
|
||||
this.page.addInitScript = async function (a: any, b: any) {
|
||||
// @ts-ignore pretty sure way out of tsc's type checking capabilities.
|
||||
// This code works perfectly fine.
|
||||
await oldPageAddInitScript.apply(this, [a, b])
|
||||
await that.page.reload()
|
||||
}
|
||||
|
||||
if (!this.firstUrl) {
|
||||
await this.page.getByText('Your Projects').count()
|
||||
this.firstUrl = this.page.url()
|
||||
}
|
||||
|
||||
// Due to the app controlling its own window context we need to inject new
|
||||
// options and context here.
|
||||
// NOTE TO LEE: Seems to destroy page context when calling an electron loadURL.
|
||||
// await tronApp.electronApp.evaluate(({ app }) => {
|
||||
// return app.reuseWindowForTest();
|
||||
// });
|
||||
|
||||
await this.electron?.evaluate(({ app }, projectDirName) => {
|
||||
// @ts-ignore can't declaration merge see main.ts
|
||||
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
|
||||
}, this.projectDirName)
|
||||
|
||||
// Always start at the root view
|
||||
await this.page.goto(this.firstUrl)
|
||||
|
||||
// Force a hard reload, destroying the stream and other state
|
||||
await this.page.reload()
|
||||
}
|
||||
|
||||
async cleanProjectDir(appSettings?: DeepPartial<Settings>) {
|
||||
try {
|
||||
if (fs.existsSync(this.projectDirName)) {
|
||||
await fsp.rm(this.projectDirName, { recursive: true })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
try {
|
||||
await fsp.mkdir(this.projectDirName)
|
||||
} catch (e) {
|
||||
// Not a problem if it already exists.
|
||||
}
|
||||
|
||||
const tempSettingsFilePath = path.join(
|
||||
this.projectDirName,
|
||||
SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
let settingsOverridesToml = ''
|
||||
|
||||
if (appSettings) {
|
||||
settingsOverridesToml = TOML.stringify({
|
||||
// @ts-expect-error
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
...appSettings,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
project_directory: this.projectDirName,
|
||||
...appSettings.app,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
settingsOverridesToml = TOML.stringify({
|
||||
// @ts-expect-error
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
project_directory: this.projectDirName,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
await fsp.writeFile(tempSettingsFilePath, settingsOverridesToml)
|
||||
}
|
||||
}
|
||||
|
||||
export const fixtures = {
|
||||
cmdBar: async ({ page }: { page: Page }, use: any) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// If yee encounter this, please try to type it.
|
||||
type FnUse = any
|
||||
|
||||
const fixturesForElectron = {
|
||||
page: async (
|
||||
{ tronApp }: { tronApp: ElectronZoo },
|
||||
use: FnUse,
|
||||
testInfo: TestInfo
|
||||
) => {
|
||||
await tronApp.createInstanceIfMissing(testInfo)
|
||||
await use(tronApp.page)
|
||||
await tronApp?.makeAvailableAgain()
|
||||
},
|
||||
context: async (
|
||||
{ tronApp }: { tronApp: ElectronZoo },
|
||||
use: FnUse,
|
||||
testInfo: TestInfo
|
||||
) => {
|
||||
await tronApp.createInstanceIfMissing(testInfo)
|
||||
await use(tronApp.context)
|
||||
},
|
||||
}
|
||||
|
||||
const fixturesForWeb = {
|
||||
page: async (
|
||||
{ page, context }: { page: Page; context: BrowserContext },
|
||||
use: FnUse,
|
||||
testInfo: TestInfo
|
||||
) => {
|
||||
page.setBodyDimensions = page.setViewportSize
|
||||
|
||||
// We do the same thing in ElectronZoo. addInitScript simply doesn't fire
|
||||
// at the correct time, so we reload the page and it fires appropriately.
|
||||
const oldPageAddInitScript = page.addInitScript
|
||||
page.addInitScript = async function (...args) {
|
||||
// @ts-expect-error
|
||||
await oldPageAddInitScript.apply(this, args)
|
||||
await page.reload()
|
||||
}
|
||||
|
||||
const oldContextAddInitScript = context.addInitScript
|
||||
context.addInitScript = async function (...args) {
|
||||
// @ts-expect-error
|
||||
await oldContextAddInitScript.apply(this, args)
|
||||
await page.reload()
|
||||
}
|
||||
|
||||
const webApp = new AuthenticatedApp(context, page, testInfo)
|
||||
await webApp.initialise()
|
||||
|
||||
await use(page)
|
||||
},
|
||||
}
|
||||
|
||||
const fixturesBasedOnProcessEnvPlatform = {
|
||||
cmdBar: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new CmdBarFixture(page))
|
||||
},
|
||||
editor: async ({ page }: { page: Page }, use: any) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
editor: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new EditorFixture(page))
|
||||
},
|
||||
toolbar: async ({ page }: { page: Page }, use: any) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
toolbar: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new ToolbarFixture(page))
|
||||
},
|
||||
scene: async ({ page }: { page: Page }, use: any) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
scene: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new SceneFixture(page))
|
||||
},
|
||||
homePage: async ({ page }: { page: Page }, use: any) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
homePage: async ({ page }: { page: Page }, use: FnUse) => {
|
||||
await use(new HomePageFixture(page))
|
||||
},
|
||||
}
|
||||
|
||||
if (process.env.PLATFORM === 'web') {
|
||||
Object.assign(fixturesBasedOnProcessEnvPlatform, fixturesForWeb)
|
||||
} else {
|
||||
Object.assign(fixturesBasedOnProcessEnvPlatform, fixturesForElectron)
|
||||
}
|
||||
|
||||
export { fixturesBasedOnProcessEnvPlatform }
|
||||
|
@ -27,10 +27,6 @@ export class HomePageFixture {
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.reConstruct(page)
|
||||
}
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
|
||||
this.projectSection = this.page.getByTestId('home-section')
|
||||
|
||||
@ -96,8 +92,12 @@ export class HomePageFixture {
|
||||
}
|
||||
}
|
||||
|
||||
createAndGoToProject = async (projectTitle = 'project-$nnn') => {
|
||||
projectsLoaded = async () => {
|
||||
await expect(this.projectSection).not.toHaveText('Loading your Projects...')
|
||||
}
|
||||
|
||||
createAndGoToProject = async (projectTitle = 'project-$nnn') => {
|
||||
await this.projectsLoaded()
|
||||
await this.projectButtonNew.click()
|
||||
await this.projectTextName.click()
|
||||
await this.projectTextName.fill(projectTitle)
|
||||
|
@ -53,7 +53,12 @@ export class SceneFixture {
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.reConstruct(page)
|
||||
this.streamWrapper = page.getByTestId('stream')
|
||||
this.networkToggleConnected = page.getByTestId('network-toggle-ok')
|
||||
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
||||
this.startEditSketchBtn = page
|
||||
.getByRole('button', { name: 'Start Sketch' })
|
||||
.or(page.getByRole('button', { name: 'Edit Sketch' }))
|
||||
}
|
||||
private _serialiseScene = async (): Promise<SceneSerialised> => {
|
||||
const camera = await this.getCameraInfo()
|
||||
@ -72,17 +77,6 @@ export class SceneFixture {
|
||||
.toEqual(expected)
|
||||
}
|
||||
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
|
||||
this.streamWrapper = page.getByTestId('stream')
|
||||
this.networkToggleConnected = page.getByTestId('network-toggle-ok')
|
||||
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
||||
this.startEditSketchBtn = page
|
||||
.getByRole('button', { name: 'Start Sketch' })
|
||||
.or(page.getByRole('button', { name: 'Edit Sketch' }))
|
||||
}
|
||||
|
||||
makeMouseHelpers = (
|
||||
x: number,
|
||||
y: number,
|
||||
@ -253,7 +247,7 @@ export class SceneFixture {
|
||||
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.clearAndCloseDebugPanel()
|
||||
await u.closeDebugPanel()
|
||||
|
||||
await this.waitForExecutionDone()
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled()
|
||||
|
@ -37,13 +37,12 @@ export class ToolbarFixture {
|
||||
featureTreeId = 'feature-tree' as const
|
||||
/** The pane element for the Feature Tree */
|
||||
featureTreePane!: Locator
|
||||
gizmo!: Locator
|
||||
gizmoDisabled!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.reConstruct(page)
|
||||
}
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
|
||||
this.extrudeButton = page.getByTestId('extrude')
|
||||
this.loftButton = page.getByTestId('loft')
|
||||
this.sweepButton = page.getByTestId('sweep')
|
||||
@ -67,6 +66,13 @@ export class ToolbarFixture {
|
||||
this.filePane = page.locator('#files-pane')
|
||||
this.featureTreePane = page.locator('#feature-tree-pane')
|
||||
this.fileCreateToast = page.getByText('Successfully created')
|
||||
|
||||
// Note to test writers: having two locators like this is preferable to one
|
||||
// which changes another el property because it means our test "signal" is
|
||||
// completely decoupled from the elements themselves. It means the same
|
||||
// element or two different elements can represent these states.
|
||||
this.gizmo = page.getByTestId('gizmo')
|
||||
this.gizmoDisabled = page.getByTestId('gizmo-disabled')
|
||||
}
|
||||
|
||||
get editSketchBtn() {
|
||||
@ -86,6 +92,18 @@ export class ToolbarFixture {
|
||||
startSketchPlaneSelection = async () =>
|
||||
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
|
||||
|
||||
waitUntilSketchingReady = async () => {
|
||||
await expect(this.gizmoDisabled).toBeVisible()
|
||||
}
|
||||
|
||||
startSketchThenCallbackThenWaitUntilReady = async (
|
||||
cb: () => Promise<void>
|
||||
) => {
|
||||
await this.startSketchBtn.click()
|
||||
await cb()
|
||||
await this.waitUntilSketchingReady()
|
||||
}
|
||||
|
||||
exitSketch = async () => {
|
||||
await this.exitSketchBtn.click()
|
||||
await expect(
|
||||
|
@ -21,58 +21,54 @@ import { expectPixelColor } from './fixtures/sceneFixture'
|
||||
// we must set it to empty for the tests where we want to see the onboarding immediately.
|
||||
|
||||
test.describe('Onboarding tests', () => {
|
||||
test(
|
||||
'Onboarding code is shown in the editor',
|
||||
{
|
||||
appSettings: {
|
||||
test('Onboarding code is shown in the editor', async ({
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ page, homePage }) => {
|
||||
})
|
||||
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// Test that the onboarding pane loaded
|
||||
await expect(
|
||||
page.getByText('Welcome to Modeling App! This')
|
||||
).toBeVisible()
|
||||
await expect(page.getByText('Welcome to Modeling App! This')).toBeVisible()
|
||||
|
||||
// Test that the onboarding pane loaded
|
||||
await expect(
|
||||
page.getByText('Welcome to Modeling App! This')
|
||||
).toBeVisible()
|
||||
await expect(page.getByText('Welcome to Modeling App! This')).toBeVisible()
|
||||
|
||||
// *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')
|
||||
|
||||
// Make sure the model loaded
|
||||
const XYPlanePoint = { x: 774, y: 116 } as const
|
||||
const modelColor: [number, number, number] = [45, 45, 45]
|
||||
await page.mouse.move(XYPlanePoint.x, XYPlanePoint.y)
|
||||
expect(await u.getGreatestPixDiff(XYPlanePoint, modelColor)).toBeLessThan(
|
||||
8
|
||||
)
|
||||
}
|
||||
)
|
||||
expect(await u.getGreatestPixDiff(XYPlanePoint, modelColor)).toBeLessThan(8)
|
||||
})
|
||||
|
||||
test(
|
||||
'Desktop: fresh onboarding executes and loads',
|
||||
{
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
},
|
||||
async ({ page, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ page }) => {
|
||||
})
|
||||
const u = await getUtils(page)
|
||||
|
||||
const viewportSize = { width: 1200, height: 500 }
|
||||
@ -107,22 +103,30 @@ test.describe('Onboarding tests', () => {
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Code resets after confirmation',
|
||||
{
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
test('Code resets after confirmation', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir()
|
||||
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')`
|
||||
|
||||
// Load the page up with some code so we see the confirmation warning
|
||||
// when we go to replay onboarding
|
||||
await context.addInitScript((code) => {
|
||||
await page.addInitScript((code) => {
|
||||
localStorage.setItem('persistCode', code)
|
||||
}, initialCode)
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Replay the onboarding
|
||||
await page.getByRole('link', { name: 'Settings' }).last().click()
|
||||
@ -142,26 +146,27 @@ test.describe('Onboarding tests', () => {
|
||||
|
||||
// Ensure we see the introduction and that the code has been reset
|
||||
await expect(page.getByText('Welcome to Modeling App!')).toBeVisible()
|
||||
await expect(page.locator('.cm-content')).toContainText(
|
||||
'// Shelf Bracket'
|
||||
)
|
||||
await expect(page.locator('.cm-content')).toContainText('// Shelf Bracket')
|
||||
|
||||
// There used to be old code here that checked if we stored the reset
|
||||
// code into localStorage but that isn't the case on desktop. It gets
|
||||
// saved to the file system, which we have other tests for.
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'Click through each onboarding step and back',
|
||||
{
|
||||
appSettings: {
|
||||
test('Click through each onboarding step and back', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
})
|
||||
// Override beforeEach test setup
|
||||
await context.addInitScript(
|
||||
async ({ settingsKey, settings }) => {
|
||||
@ -181,9 +186,7 @@ test.describe('Onboarding tests', () => {
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// Test that the onboarding pane loaded
|
||||
await expect(
|
||||
page.getByText('Welcome to Modeling App! This')
|
||||
).toBeVisible()
|
||||
await expect(page.getByText('Welcome to Modeling App! This')).toBeVisible()
|
||||
|
||||
const nextButton = page.getByTestId('onboarding-next')
|
||||
const prevButton = page.getByTestId('onboarding-prev')
|
||||
@ -205,20 +208,23 @@ test.describe('Onboarding tests', () => {
|
||||
// Test that the onboarding pane is gone
|
||||
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
||||
await expect.poll(() => page.url()).not.toContain('/onboarding')
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'Onboarding redirects and code updating',
|
||||
{
|
||||
appSettings: {
|
||||
test('Onboarding redirects and code updating', async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '/export',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
})
|
||||
|
||||
const originalCode = 'sigmaAllow = 15000'
|
||||
|
||||
// Override beforeEach test setup
|
||||
@ -260,21 +266,22 @@ test.describe('Onboarding tests', () => {
|
||||
await page.locator('[data-testid="onboarding-next"]').hover()
|
||||
await page.locator('[data-testid="onboarding-next"]').click()
|
||||
await expect(page.locator('.cm-content')).toHaveText(/.+/)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'Onboarding code gets reset to demo on Interactive Numbers step',
|
||||
{
|
||||
appSettings: {
|
||||
test('Onboarding code gets reset to demo on Interactive Numbers step', async ({
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '/parametric-modeling',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
})
|
||||
|
||||
async ({ page, homePage }) => {
|
||||
const u = await getUtils(page)
|
||||
const badCode = `// This is bad code we shouldn't see`
|
||||
|
||||
@ -307,23 +314,24 @@ test.describe('Onboarding tests', () => {
|
||||
|
||||
// Check that the code has been reset
|
||||
await expect(u.codeLocator).toHaveText(bracketNoNewLines)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// (lee) The two avatar tests are weird because even on main, we don't have
|
||||
// anything to do with the avatar inside the onboarding test. Due to the
|
||||
// low impact of an avatar not showing I'm changing this to fixme.
|
||||
test.fixme(
|
||||
'Avatar text updates depending on image load success',
|
||||
{
|
||||
appSettings: {
|
||||
async ({ context, page, homePage, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
})
|
||||
|
||||
// Override beforeEach test setup
|
||||
await context.addInitScript(
|
||||
async ({ settingsKey, settings }) => {
|
||||
@ -388,15 +396,16 @@ test.describe('Onboarding tests', () => {
|
||||
|
||||
test.fixme(
|
||||
"Avatar text doesn't mention avatar when no avatar",
|
||||
{
|
||||
appSettings: {
|
||||
async ({ context, page, homePage, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: '',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
})
|
||||
// Override beforeEach test setup
|
||||
await context.addInitScript(
|
||||
async ({ settingsKey, settings }) => {
|
||||
@ -444,15 +453,17 @@ test.describe('Onboarding tests', () => {
|
||||
|
||||
test.fixme(
|
||||
'Restarting onboarding on desktop takes one attempt',
|
||||
{
|
||||
appSettings: {
|
||||
async ({ context, page, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
onboarding_status: 'dismissed',
|
||||
},
|
||||
},
|
||||
cleanProjectDir: true,
|
||||
},
|
||||
async ({ context, page }) => {
|
||||
})
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const routerTemplateDir = join(dir, 'router-template-slate')
|
||||
await fsp.mkdir(routerTemplateDir, { recursive: true })
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import { EditorFixture } from './fixtures/editorFixture'
|
||||
import { SceneFixture } from './fixtures/sceneFixture'
|
||||
import { ToolbarFixture } from './fixtures/toolbarFixture'
|
||||
|
@ -163,7 +163,7 @@ test(
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
.toBeLessThan(20)
|
||||
})
|
||||
|
||||
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
|
||||
@ -464,7 +464,11 @@ test.describe('Can export from electron app', () => {
|
||||
test(
|
||||
`Can export using ${method}`,
|
||||
{ tag: ['@electron', '@skipLocalEngine'] },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -516,6 +520,7 @@ test.describe('Can export from electron app', () => {
|
||||
storage: 'embedded',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page,
|
||||
method
|
||||
)
|
||||
@ -523,7 +528,7 @@ test.describe('Can export from electron app', () => {
|
||||
})
|
||||
|
||||
const filepath = path.resolve(
|
||||
getPlaywrightDownloadDir(page),
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
'main.gltf'
|
||||
)
|
||||
|
||||
@ -781,6 +786,7 @@ test(
|
||||
page.on('console', console.log)
|
||||
|
||||
await expect(page.getByText('router-template-slate')).toBeVisible()
|
||||
await expect(page.getByText('Loading your Projects...')).not.toBeVisible()
|
||||
await expect(page.getByText('Your Projects')).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Delete')
|
||||
@ -858,7 +864,7 @@ test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Delete from project page`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_delete`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
|
||||
@ -887,6 +893,8 @@ test.describe(`Project management commands`, () => {
|
||||
|
||||
await projectHomeLink.click()
|
||||
await u.waitForPageLoad()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step(`Run delete command via command palette`, async () => {
|
||||
@ -909,7 +917,7 @@ test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Rename from home page`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, homePage }, testInfo) => {
|
||||
const projectName = `my_project_to_rename`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
|
||||
@ -936,6 +944,7 @@ test.describe(`Project management commands`, () => {
|
||||
await test.step(`Setup`, async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
page.on('console', console.log)
|
||||
await homePage.projectsLoaded()
|
||||
await expect(projectHomeLink).toBeVisible()
|
||||
})
|
||||
|
||||
@ -1682,7 +1691,11 @@ test(
|
||||
test(
|
||||
'You can change the root projects directory and nothing is lost',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page, electronApp }, testInfo) => {
|
||||
async ({ context, page, tronApp, homePage }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await Promise.all([
|
||||
fsp.mkdir(`${dir}/router-template-slate`, { recursive: true }),
|
||||
@ -1712,6 +1725,8 @@ test(
|
||||
await fsp.rm(newProjectDirName, { recursive: true })
|
||||
}
|
||||
|
||||
await homePage.projectsLoaded()
|
||||
|
||||
await test.step('We can change the root project directory', async () => {
|
||||
// expect to see the project directory settings link
|
||||
await expect(
|
||||
@ -1725,7 +1740,7 @@ test(
|
||||
.locator('section#projectDirectory input')
|
||||
.inputValue()
|
||||
|
||||
const handleFile = electronApp?.evaluate(
|
||||
const handleFile = tronApp.electron.evaluate(
|
||||
async ({ dialog }, filePaths) => {
|
||||
dialog.showOpenDialog = () =>
|
||||
Promise.resolve({ canceled: false, filePaths })
|
||||
@ -1741,6 +1756,8 @@ test(
|
||||
|
||||
await page.getByTestId('settings-close-button').click()
|
||||
|
||||
await homePage.projectsLoaded()
|
||||
|
||||
await expect(page.getByText('No Projects found')).toBeVisible()
|
||||
await createProject({ name: 'project-000', page, returnHome: true })
|
||||
await expect(
|
||||
@ -1755,7 +1772,7 @@ test(
|
||||
|
||||
await page.getByTestId('project-directory-settings-link').click()
|
||||
|
||||
const handleFile = electronApp?.evaluate(
|
||||
const handleFile = tronApp.electron.evaluate(
|
||||
async ({ dialog }, filePaths) => {
|
||||
dialog.showOpenDialog = () =>
|
||||
Promise.resolve({ canceled: false, filePaths })
|
||||
@ -1767,6 +1784,7 @@ test(
|
||||
await page.getByTestId('project-directory-button').click()
|
||||
await handleFile
|
||||
|
||||
await homePage.projectsLoaded()
|
||||
await expect(page.locator('section#projectDirectory input')).toHaveValue(
|
||||
originalProjectDirName
|
||||
)
|
||||
@ -2000,8 +2018,8 @@ test(
|
||||
|
||||
test(
|
||||
'Settings persist across restarts',
|
||||
{ tag: '@electron', cleanProjectDir: true },
|
||||
async ({ page }, testInfo) => {
|
||||
{ tag: '@electron' },
|
||||
async ({ page, scene, cmdBar }, testInfo) => {
|
||||
await test.step('We can change a user setting like theme', async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
@ -2014,6 +2032,10 @@ test(
|
||||
await expect(page.getByTestId('app-theme')).toHaveValue('dark')
|
||||
|
||||
await page.getByTestId('app-theme').selectOption('light')
|
||||
await expect(page.getByTestId('app-theme')).toHaveValue('light')
|
||||
|
||||
// Give time to system for writing to a persistent store
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step('Starting the app again and we can see the same theme', async () => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import path from 'path'
|
||||
import * as fsp from 'fs/promises'
|
||||
import { getUtils, executorInputPath } from './test-utils'
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { HomePageFixture } from './fixtures/homePageFixture'
|
||||
@ -2153,6 +2154,8 @@ extrude001 = extrude(profile003, length = 5)
|
||||
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await page.waitForTimeout(5000)
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
@ -2165,7 +2168,7 @@ extrude001 = extrude(profile003, length = 5)
|
||||
await page.waitForTimeout(600)
|
||||
|
||||
await editor.expectEditor.toContain(`sketch001 = startSketchOn('XZ')`)
|
||||
await toolbar.exitSketchBtn.click()
|
||||
await toolbar.exitSketch()
|
||||
|
||||
await editor.expectEditor.not.toContain(`sketch001 = startSketchOn('XZ')`)
|
||||
|
||||
@ -2181,6 +2184,8 @@ extrude001 = extrude(profile003, length = 5)
|
||||
)`
|
||||
)
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.expectPixelColor([255, 255, 255], { x: 633, y: 211 }, 15)
|
||||
})
|
||||
})
|
||||
|
@ -31,8 +31,7 @@ test.beforeEach(async ({ page, context }) => {
|
||||
// Help engine-manager: tear shit down.
|
||||
test.afterEach(async ({ page }) => {
|
||||
await page.evaluate(() => {
|
||||
// @ts-expect-error
|
||||
window.tearDown()
|
||||
window.engineCommandManager.tearDown()
|
||||
})
|
||||
})
|
||||
|
||||
@ -45,7 +44,11 @@ test.setTimeout(60_000)
|
||||
test.skip(
|
||||
'exports of each format should work',
|
||||
{ tag: ['@snapshot', '@skipWin', '@skipMacos'] },
|
||||
async ({ page, context, scene, cmdBar }) => {
|
||||
async ({ page, context, scene, cmdBar, tronApp }) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
// FYI this test doesn't work with only engine running locally
|
||||
// And you will need to have the KittyCAD CLI installed
|
||||
const u = await getUtils(page)
|
||||
@ -134,6 +137,7 @@ part001 = startSketchOn('-XZ')
|
||||
storage: 'ascii',
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -146,6 +150,7 @@ part001 = startSketchOn('-XZ')
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -158,6 +163,7 @@ part001 = startSketchOn('-XZ')
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -170,6 +176,7 @@ part001 = startSketchOn('-XZ')
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -182,6 +189,7 @@ part001 = startSketchOn('-XZ')
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -193,6 +201,7 @@ part001 = startSketchOn('-XZ')
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -203,6 +212,7 @@ part001 = startSketchOn('-XZ')
|
||||
storage: 'embedded',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -213,6 +223,7 @@ part001 = startSketchOn('-XZ')
|
||||
storage: 'binary',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
@ -223,6 +234,7 @@ part001 = startSketchOn('-XZ')
|
||||
storage: 'standard',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp.projectDirName,
|
||||
page
|
||||
)
|
||||
)
|
||||
|
@ -84,7 +84,7 @@ test.describe('Test network and connection issues', () => {
|
||||
'Engine disconnect & reconnect in sketch mode',
|
||||
{ tag: '@skipLocalEngine' },
|
||||
async ({ page, homePage }) => {
|
||||
// TODO: Don't skip Mac for these. After `window.tearDown` is working in Safari, these should work on webkit
|
||||
// TODO: Don't skip Mac for these. After `window.engineCommandManager.tearDown` is working in Safari, these should work on webkit
|
||||
const networkToggle = page.getByTestId('network-toggle')
|
||||
|
||||
const u = await getUtils(page)
|
||||
|
@ -5,8 +5,9 @@ import {
|
||||
_electron as electron,
|
||||
ElectronApplication,
|
||||
Locator,
|
||||
Page,
|
||||
} from '@playwright/test'
|
||||
import { test, Page } from './zoo-test'
|
||||
import { test } from './zoo-test'
|
||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||
import fsp from 'fs/promises'
|
||||
import fsSync from 'fs'
|
||||
@ -337,7 +338,7 @@ export const getMovementUtils = (opts: any) => {
|
||||
|
||||
async function waitForAuthAndLsp(page: Page) {
|
||||
const waitForLspPromise = page.waitForEvent('console', {
|
||||
predicate: async (message) => {
|
||||
predicate: async (message: any) => {
|
||||
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
|
||||
// but that doesn't seem to make it to the console for macos/safari :(
|
||||
if (message.text().includes('start kcl lsp')) {
|
||||
@ -420,7 +421,7 @@ export async function getUtils(page: Page, test_?: typeof test) {
|
||||
const overlay = page.locator(locator)
|
||||
const bbox = await overlay
|
||||
.boundingBox({ timeout: 5_000 })
|
||||
.then((box) => ({ ...box, x: box?.x || 0, y: box?.y || 0 }))
|
||||
.then((box: any) => ({ ...box, x: box?.x || 0, y: box?.y || 0 }))
|
||||
const angle = Number(await overlay.getAttribute('data-overlay-angle'))
|
||||
const angleXOffset = Math.cos(((angle - 180) * Math.PI) / 180) * px
|
||||
const angleYOffset = Math.sin(((angle - 180) * Math.PI) / 180) * px
|
||||
@ -437,7 +438,7 @@ export async function getUtils(page: Page, test_?: typeof test) {
|
||||
page
|
||||
.locator(locator)
|
||||
.boundingBox({ timeout: 5_000 })
|
||||
.then((box) => ({ ...box, x: box?.x || 0, y: box?.y || 0 })),
|
||||
.then((box: any) => ({ ...box, x: box?.x || 0, y: box?.y || 0 })),
|
||||
codeLocator: page.locator('.cm-content'),
|
||||
crushKclCodeIntoOneLineAndThenMaybeSome: async () => {
|
||||
const code = await page.locator('.cm-content').innerText()
|
||||
@ -504,7 +505,7 @@ export async function getUtils(page: Page, test_?: typeof test) {
|
||||
) => {
|
||||
if (cdpSession === null) {
|
||||
// Use a fail safe if we can't simulate disconnect (on Safari)
|
||||
return page.evaluate('window.tearDown()')
|
||||
return page.evaluate('window.engineCommandManager.tearDown()')
|
||||
}
|
||||
|
||||
return cdpSession?.send(
|
||||
@ -631,7 +632,7 @@ export async function getUtils(page: Page, test_?: typeof test) {
|
||||
panesOpen: async (paneIds: PaneId[]) => {
|
||||
return test?.step(`Setting ${paneIds} panes to be open`, async () => {
|
||||
await page.addInitScript(
|
||||
({ PERSIST_MODELING_CONTEXT, paneIds }) => {
|
||||
({ PERSIST_MODELING_CONTEXT, paneIds }: any) => {
|
||||
localStorage.setItem(
|
||||
PERSIST_MODELING_CONTEXT,
|
||||
JSON.stringify({ openPanes: paneIds })
|
||||
@ -722,14 +723,14 @@ export const makeTemplate: (
|
||||
|
||||
const PLAYWRIGHT_DOWNLOAD_DIR = 'downloads-during-playwright'
|
||||
|
||||
export const getPlaywrightDownloadDir = (page: Page) => {
|
||||
return path.resolve(page.dir, PLAYWRIGHT_DOWNLOAD_DIR)
|
||||
export const getPlaywrightDownloadDir = (rootDir: string) => {
|
||||
return path.resolve(rootDir, PLAYWRIGHT_DOWNLOAD_DIR)
|
||||
}
|
||||
|
||||
const moveDownloadedFileTo = async (page: Page, toLocation: string) => {
|
||||
const moveDownloadedFileTo = async (rootDir: string, toLocation: string) => {
|
||||
await fsp.mkdir(path.dirname(toLocation), { recursive: true })
|
||||
|
||||
const downloadDir = getPlaywrightDownloadDir(page)
|
||||
const downloadDir = getPlaywrightDownloadDir(rootDir)
|
||||
|
||||
// Expect there to be at least one file
|
||||
await expect
|
||||
@ -756,6 +757,7 @@ export interface Paths {
|
||||
|
||||
export const doExport = async (
|
||||
output: Models['OutputFormat_type'],
|
||||
rootDir: string,
|
||||
page: Page,
|
||||
exportFrom: 'dropdown' | 'sidebarButton' | 'commandBar' = 'dropdown'
|
||||
): Promise<Paths> => {
|
||||
@ -836,7 +838,7 @@ export const doExport = async (
|
||||
// (declared in src/lib/exportSave)
|
||||
// To remain consistent with our old web tests, we want to move some downloads
|
||||
// (images) to another directory.
|
||||
await moveDownloadedFileTo(page, downloadLocation)
|
||||
await moveDownloadedFileTo(rootDir, downloadLocation)
|
||||
}
|
||||
|
||||
return {
|
||||
@ -859,12 +861,6 @@ export async function tearDown(page: Page, testInfo: TestInfo) {
|
||||
downloadThroughput: -1,
|
||||
uploadThroughput: -1,
|
||||
})
|
||||
|
||||
// It seems it's best to give the browser about 3s to close things
|
||||
// It's not super reliable but we have no real other choice for now
|
||||
await page.waitForTimeout(3000)
|
||||
|
||||
await testInfo.tronApp?.close()
|
||||
}
|
||||
|
||||
// settingsOverrides may need to be augmented to take more generic items,
|
||||
@ -936,107 +932,11 @@ let electronApp: ElectronApplication | undefined = undefined
|
||||
let context: BrowserContext | undefined = undefined
|
||||
let page: Page | undefined = undefined
|
||||
|
||||
export async function setupElectron({
|
||||
testInfo,
|
||||
cleanProjectDir = true,
|
||||
appSettings,
|
||||
viewport,
|
||||
}: {
|
||||
testInfo: TestInfo
|
||||
folderSetupFn?: (projectDirName: string) => Promise<void>
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: DeepPartial<Settings>
|
||||
viewport: {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
}): Promise<{
|
||||
electronApp: ElectronApplication
|
||||
context: BrowserContext
|
||||
page: Page
|
||||
dir: string
|
||||
}> {
|
||||
// create or otherwise clear the folder
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
try {
|
||||
if (fsSync.existsSync(projectDirName) && cleanProjectDir) {
|
||||
await fsp.rm(projectDirName, { recursive: true })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
if (cleanProjectDir) {
|
||||
await fsp.mkdir(projectDirName)
|
||||
}
|
||||
|
||||
const options = {
|
||||
args: ['.', '--no-sandbox'],
|
||||
env: {
|
||||
...process.env,
|
||||
TEST_SETTINGS_FILE_KEY: projectDirName,
|
||||
IS_PLAYWRIGHT: 'true',
|
||||
},
|
||||
...(process.env.ELECTRON_OVERRIDE_DIST_PATH
|
||||
? { executablePath: process.env.ELECTRON_OVERRIDE_DIST_PATH + 'electron' }
|
||||
: {}),
|
||||
...(process.env.PLAYWRIGHT_RECORD_VIDEO
|
||||
? {
|
||||
recordVideo: {
|
||||
dir: testInfo.snapshotPath(),
|
||||
size: viewport,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
// Do this once and then reuse window on subsequent calls.
|
||||
if (!electronApp) {
|
||||
electronApp = await electron.launch(options)
|
||||
}
|
||||
|
||||
if (!context || !page) {
|
||||
context = electronApp.context()
|
||||
page = await electronApp.firstWindow()
|
||||
context.on('console', console.log)
|
||||
page.on('console', console.log)
|
||||
}
|
||||
|
||||
if (cleanProjectDir) {
|
||||
const tempSettingsFilePath = path.join(projectDirName, SETTINGS_FILE_NAME)
|
||||
const settingsOverrides = settingsToToml(
|
||||
appSettings
|
||||
? {
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
...appSettings,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
project_directory: projectDirName,
|
||||
...appSettings.app,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {
|
||||
settings: {
|
||||
...TEST_SETTINGS,
|
||||
app: {
|
||||
...TEST_SETTINGS.app,
|
||||
project_directory: projectDirName,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
await fsp.writeFile(tempSettingsFilePath, settingsOverrides)
|
||||
}
|
||||
|
||||
return { electronApp, page, context, dir: projectDirName }
|
||||
}
|
||||
|
||||
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
||||
// enabled for chrome for now
|
||||
if (page.context().browser()?.browserType().name() === 'chromium') {
|
||||
page.on('pageerror', (exception) => {
|
||||
// No idea wtf exception is
|
||||
page.on('pageerror', (exception: any) => {
|
||||
if (isErrorWhitelisted(exception)) {
|
||||
return
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
|
||||
import { deg, getUtils, wiggleMove } from './test-utils'
|
||||
import { LineInputsType } from 'lang/std/sketchcombos'
|
||||
|
@ -20,14 +20,20 @@ import { DeepPartial } from 'lib/types'
|
||||
import { Settings } from '@rust/kcl-lib/bindings/Settings'
|
||||
|
||||
test.describe('Testing settings', () => {
|
||||
test(
|
||||
'Stored settings are validated and fall back to defaults',
|
||||
test('Stored settings are validated and fall back to defaults', async ({
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
// Override beforeEach test setup
|
||||
// with corrupted settings
|
||||
{
|
||||
appSettings: TEST_SETTINGS_CORRUPTED as DeepPartial<Settings>,
|
||||
},
|
||||
async ({ page, homePage }) => {
|
||||
await tronApp.cleanProjectDir(
|
||||
TEST_SETTINGS_CORRUPTED as DeepPartial<Settings>
|
||||
)
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
// Check the settings were reset
|
||||
@ -47,8 +53,7 @@ test.describe('Testing settings', () => {
|
||||
expect(storedSettings.settings?.project?.default_project_name).toBe(
|
||||
'project-$nnn'
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// The behavior is actually broken. Parent always takes precedence
|
||||
test.fixme(
|
||||
@ -357,8 +362,6 @@ test.describe('Testing settings', () => {
|
||||
`Load desktop app with no settings file`,
|
||||
{
|
||||
tag: '@electron',
|
||||
// This is what makes no settings file get created
|
||||
cleanProjectDir: false,
|
||||
},
|
||||
async ({ page }, testInfo) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
@ -379,13 +382,17 @@ test.describe('Testing settings', () => {
|
||||
`Load desktop app with a settings file, but no project directory setting`,
|
||||
{
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
},
|
||||
async ({ context, page, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
theme_color: '259',
|
||||
},
|
||||
},
|
||||
},
|
||||
async ({ context, page }, testInfo) => {
|
||||
})
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
// Selectors and constants
|
||||
@ -405,15 +412,20 @@ test.describe('Testing settings', () => {
|
||||
'user settings reload on external change, on project and modeling view',
|
||||
{
|
||||
tag: '@electron',
|
||||
appSettings: {
|
||||
},
|
||||
async ({ context, page, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
app: {
|
||||
// Doesn't matter what you set it to. It will
|
||||
// default to 264.5
|
||||
theme_color: '0',
|
||||
},
|
||||
},
|
||||
},
|
||||
async ({ context, page }, testInfo) => {
|
||||
})
|
||||
|
||||
const { dir: projectDirName } = await context.folderSetupFn(
|
||||
async () => {}
|
||||
)
|
||||
@ -783,13 +795,20 @@ test.describe('Testing settings', () => {
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
`Changing system theme preferences (via media query) should update UI and stream`,
|
||||
{
|
||||
test(`Changing system theme preferences (via media query) should update UI and stream`, async ({
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
// Override the settings so that the theme is set to `system`
|
||||
appSettings: TEST_SETTINGS_DEFAULT_THEME,
|
||||
},
|
||||
async ({ page, homePage }) => {
|
||||
...TEST_SETTINGS_DEFAULT_THEME,
|
||||
})
|
||||
|
||||
const u = await getUtils(page)
|
||||
|
||||
// Selectors and constants
|
||||
@ -829,29 +848,31 @@ test.describe('Testing settings', () => {
|
||||
.poll(() => streamBackgroundPixelIsColor(darkBackgroundColor))
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
`Turning off "Show debug panel" with debug panel open leaves no phantom panel`,
|
||||
{
|
||||
test(`Turning off "Show debug panel" with debug panel open leaves no phantom panel`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await tronApp.cleanProjectDir({
|
||||
// Override beforeEach test setup
|
||||
// with debug panel open
|
||||
// but "show debug panel" set to false
|
||||
appSettings: {
|
||||
...TEST_SETTINGS,
|
||||
app: { ...TEST_SETTINGS.app, show_debug_panel: false },
|
||||
modeling: { ...TEST_SETTINGS.modeling },
|
||||
},
|
||||
},
|
||||
async ({ context, page, homePage }) => {
|
||||
})
|
||||
|
||||
const u = await getUtils(page)
|
||||
|
||||
await context.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistModelingContext',
|
||||
'{"openPanes":["debug"]}'
|
||||
)
|
||||
localStorage.setItem('persistModelingContext', '{"openPanes":["debug"]}')
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
@ -903,8 +924,7 @@ test.describe('Testing settings', () => {
|
||||
await expect(debugPaneButton).not.toBeVisible()
|
||||
await expect(resizeHandle).not.toBeVisible()
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(`Change inline units setting`, async ({
|
||||
page,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test, expect, Page } from './zoo-test'
|
||||
import { Page } from '@playwright/test'
|
||||
import { test, expect } from './zoo-test'
|
||||
import { getUtils, createProject } from './test-utils'
|
||||
import { join } from 'path'
|
||||
import fs from 'fs'
|
||||
|
@ -35,7 +35,7 @@ test.fixme('Units menu', async ({ page, homePage }) => {
|
||||
test(
|
||||
'Successful export shows a success toast',
|
||||
{ tag: '@skipLocalEngine' },
|
||||
async ({ page, homePage }) => {
|
||||
async ({ page, homePage, tronApp }) => {
|
||||
// FYI this test doesn't work with only engine running locally
|
||||
// And you will need to have the KittyCAD CLI installed
|
||||
const u = await getUtils(page)
|
||||
@ -92,12 +92,17 @@ part001 = startSketchOn('-XZ')
|
||||
await page.waitForTimeout(1000)
|
||||
await u.clearAndCloseDebugPanel()
|
||||
|
||||
if (!tronApp?.projectDirName) {
|
||||
fail()
|
||||
}
|
||||
|
||||
await doExport(
|
||||
{
|
||||
type: 'gltf',
|
||||
storage: 'embedded',
|
||||
presentation: 'pretty',
|
||||
},
|
||||
tronApp?.projectDirName,
|
||||
page
|
||||
)
|
||||
}
|
||||
@ -465,7 +470,7 @@ test('Delete key does not navigate back', async ({ page, homePage }) => {
|
||||
await expect.poll(() => page.url()).not.toContain('/settings')
|
||||
})
|
||||
|
||||
test('Sketch on face', async ({ page, homePage, scene, cmdBar }) => {
|
||||
test('Sketch on face', async ({ page, homePage, scene, cmdBar, toolbar }) => {
|
||||
test.setTimeout(90_000)
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async () => {
|
||||
@ -491,17 +496,12 @@ extrude001 = extrude(sketch001, length = 5 + 7)`
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
|
||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||
await page.waitForTimeout(300)
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
let previousCodeContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
await toolbar.startSketchThenCallbackThenWaitUntilReady(async () => {
|
||||
await u.openAndClearDebugPanel()
|
||||
await u.doAndWaitForCmd(
|
||||
() => page.mouse.click(625, 165),
|
||||
@ -510,6 +510,8 @@ extrude001 = extrude(sketch001, length = 5 + 7)`
|
||||
)
|
||||
await page.waitForTimeout(150)
|
||||
await u.closeDebugPanel()
|
||||
})
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
const firstClickPosition = [612, 238]
|
||||
const secondClickPosition = [661, 242]
|
||||
|
@ -1,21 +1,11 @@
|
||||
import {
|
||||
test as playwrightTestFn,
|
||||
TestInfo as TestInfoPlaywright,
|
||||
BrowserContext as BrowserContextPlaywright,
|
||||
Page as PagePlaywright,
|
||||
TestDetails as TestDetailsPlaywright,
|
||||
PlaywrightTestArgs,
|
||||
PlaywrightTestOptions,
|
||||
PlaywrightWorkerArgs,
|
||||
PlaywrightWorkerOptions,
|
||||
ElectronApplication,
|
||||
} from '@playwright/test'
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
|
||||
import { test as playwrightTestFn, ElectronApplication } from '@playwright/test'
|
||||
|
||||
import {
|
||||
fixtures,
|
||||
fixturesBasedOnProcessEnvPlatform,
|
||||
Fixtures,
|
||||
AuthenticatedTronApp,
|
||||
AuthenticatedApp,
|
||||
ElectronZoo,
|
||||
} from './fixtures/fixtureSetup'
|
||||
|
||||
import { Settings } from '@rust/kcl-lib/bindings/Settings'
|
||||
@ -23,9 +13,6 @@ import { DeepPartial } from 'lib/types'
|
||||
export { expect } from '@playwright/test'
|
||||
|
||||
declare module '@playwright/test' {
|
||||
interface TestInfo {
|
||||
tronApp?: AuthenticatedTronApp
|
||||
}
|
||||
interface BrowserContext {
|
||||
folderSetupFn: (
|
||||
cb: (dir: string) => Promise<void>
|
||||
@ -41,288 +28,29 @@ declare module '@playwright/test' {
|
||||
}
|
||||
}
|
||||
|
||||
export type TestInfo = TestInfoPlaywright
|
||||
export type BrowserContext = BrowserContextPlaywright
|
||||
export type Page = PagePlaywright
|
||||
export type TestDetails = TestDetailsPlaywright & {
|
||||
cleanProjectDir?: boolean
|
||||
appSettings?: DeepPartial<Settings>
|
||||
}
|
||||
// Each worker spawns a new thread, which will spawn its own ElectronZoo.
|
||||
// So in some sense there is an implicit pool.
|
||||
// For example, the variable just beneath this text is reused many times
|
||||
// *for one worker*.
|
||||
const electronZooInstance = new ElectronZoo()
|
||||
|
||||
// Our custom decorated Zoo test object. Makes it easier to add fixtures, and
|
||||
// switch between web and electron if needed.
|
||||
const pwTestFnWithFixtures = playwrightTestFn.extend<Fixtures>(fixtures)
|
||||
|
||||
// In JavaScript you cannot replace a function's body only (despite functions
|
||||
// are themselves objects, which you'd expect a body property or something...)
|
||||
// So we must redefine the function and then re-attach properties.
|
||||
type PWFunction = (
|
||||
args: PlaywrightTestArgs &
|
||||
Fixtures &
|
||||
PlaywrightWorkerArgs &
|
||||
PlaywrightTestOptions &
|
||||
PlaywrightWorkerOptions & {
|
||||
electronApp?: ElectronApplication
|
||||
},
|
||||
testInfo: TestInfo
|
||||
) => void | Promise<void>
|
||||
|
||||
let firstUrl = ''
|
||||
|
||||
export const test = (
|
||||
desc: string,
|
||||
objOrFn: PWFunction | TestDetails,
|
||||
fnMaybe?: PWFunction
|
||||
) => {
|
||||
const hasTestConf = typeof objOrFn === 'object'
|
||||
const fn = hasTestConf ? fnMaybe : objOrFn
|
||||
|
||||
return pwTestFnWithFixtures(
|
||||
desc,
|
||||
hasTestConf ? objOrFn : {},
|
||||
async (
|
||||
{
|
||||
page,
|
||||
context,
|
||||
cmdBar,
|
||||
editor,
|
||||
toolbar,
|
||||
scene,
|
||||
homePage,
|
||||
request,
|
||||
playwright,
|
||||
browser,
|
||||
acceptDownloads,
|
||||
bypassCSP,
|
||||
colorScheme,
|
||||
clientCertificates,
|
||||
deviceScaleFactor,
|
||||
extraHTTPHeaders,
|
||||
geolocation,
|
||||
hasTouch,
|
||||
httpCredentials,
|
||||
ignoreHTTPSErrors,
|
||||
isMobile,
|
||||
javaScriptEnabled,
|
||||
locale,
|
||||
offline,
|
||||
permissions,
|
||||
proxy,
|
||||
storageState,
|
||||
timezoneId,
|
||||
userAgent,
|
||||
viewport,
|
||||
baseURL,
|
||||
contextOptions,
|
||||
actionTimeout,
|
||||
navigationTimeout,
|
||||
serviceWorkers,
|
||||
testIdAttribute,
|
||||
browserName,
|
||||
defaultBrowserType,
|
||||
headless,
|
||||
channel,
|
||||
launchOptions,
|
||||
connectOptions,
|
||||
screenshot,
|
||||
trace,
|
||||
video,
|
||||
},
|
||||
testInfo
|
||||
) => {
|
||||
// To switch to web, use PLATFORM=web environment variable.
|
||||
// Only use this for debugging, since the playwright tracer is busted
|
||||
// for electron.
|
||||
|
||||
let tronApp
|
||||
|
||||
const playwrightTestFnWithFixtures_ = playwrightTestFn.extend<{
|
||||
tronApp?: ElectronZoo
|
||||
}>({
|
||||
tronApp: async ({}, use, testInfo) => {
|
||||
if (process.env.PLATFORM === 'web') {
|
||||
tronApp = new AuthenticatedApp(context, page, testInfo)
|
||||
} else {
|
||||
tronApp = new AuthenticatedTronApp(context, page, testInfo)
|
||||
}
|
||||
|
||||
const fixtures: Fixtures = { cmdBar, editor, toolbar, scene, homePage }
|
||||
if (tronApp instanceof AuthenticatedTronApp) {
|
||||
const options = {
|
||||
fixtures,
|
||||
}
|
||||
if (hasTestConf) {
|
||||
Object.assign(options, {
|
||||
appSettings: objOrFn?.appSettings,
|
||||
cleanProjectDir: objOrFn?.cleanProjectDir,
|
||||
})
|
||||
}
|
||||
await tronApp.initialise(options)
|
||||
} else {
|
||||
await tronApp.initialise('')
|
||||
}
|
||||
|
||||
// We need to patch this because addInitScript will bind too late in our
|
||||
// electron tests, never running. We need to call reload() after each call
|
||||
// to guarantee it runs.
|
||||
const oldContextAddInitScript = tronApp.context.addInitScript
|
||||
tronApp.context.addInitScript = async function (a, b) {
|
||||
// @ts-ignore pretty sure way out of tsc's type checking capabilities.
|
||||
// This code works perfectly fine.
|
||||
await oldContextAddInitScript.apply(this, [a, b])
|
||||
await tronApp.page.reload()
|
||||
}
|
||||
|
||||
// No idea why we mix and match page and context's addInitScript but we do
|
||||
const oldPageAddInitScript = tronApp.page.addInitScript
|
||||
tronApp.page.addInitScript = async function (a: any, b: any) {
|
||||
// @ts-ignore pretty sure way out of tsc's type checking capabilities.
|
||||
// This code works perfectly fine.
|
||||
await oldPageAddInitScript.apply(this, [a, b])
|
||||
await tronApp.page.reload()
|
||||
}
|
||||
|
||||
// Create a consistent way to resize the page across electron and web.
|
||||
// (lee) I had to do everything in the book to make electron change its
|
||||
// damn window size. I succeeded in making it consistently and reliably
|
||||
// do it after a whole afternoon.
|
||||
tronApp.page.setBodyDimensions = async function (dims: {
|
||||
width: number
|
||||
height: number
|
||||
}) {
|
||||
await tronApp.page.setViewportSize(dims)
|
||||
|
||||
if (!(tronApp instanceof AuthenticatedTronApp)) {
|
||||
await use(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
await tronApp.electronApp?.evaluateHandle(async ({ app }, dims) => {
|
||||
// @ts-ignore sorry jon but see comment in main.ts why this is ignored
|
||||
await app.resizeWindow(dims.width, dims.height)
|
||||
}, dims)
|
||||
|
||||
return tronApp.page.evaluate(
|
||||
async (dims: { width: number; height: number }) => {
|
||||
await window.electron.resizeWindow(dims.width, dims.height)
|
||||
window.document.body.style.width = dims.width + 'px'
|
||||
window.document.body.style.height = dims.height + 'px'
|
||||
window.document.documentElement.style.width = dims.width + 'px'
|
||||
window.document.documentElement.style.height = dims.height + 'px'
|
||||
await use(electronZooInstance)
|
||||
},
|
||||
dims
|
||||
})
|
||||
|
||||
const test = playwrightTestFnWithFixtures_.extend<Fixtures>(
|
||||
fixturesBasedOnProcessEnvPlatform
|
||||
)
|
||||
}
|
||||
|
||||
await tronApp.page.setBodyDimensions(tronApp.viewPortSize)
|
||||
|
||||
// We need to expose this in order for some tests that require folder
|
||||
// creation. Before they used to do this by their own electronSetup({...})
|
||||
// calls.
|
||||
if (tronApp instanceof AuthenticatedTronApp) {
|
||||
tronApp.context.folderSetupFn = async function (fn) {
|
||||
return fn(tronApp.dir)
|
||||
.then(() => tronApp.page.reload())
|
||||
.then(() => ({
|
||||
dir: tronApp.dir,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstUrl) {
|
||||
await tronApp.page.getByText('Your Projects').count()
|
||||
firstUrl = tronApp.page.url()
|
||||
}
|
||||
|
||||
// Due to the app controlling its own window context we need to inject new
|
||||
// options and context here.
|
||||
// NOTE TO LEE: Seems to destroy page context when calling an electron loadURL.
|
||||
// await tronApp.electronApp.evaluate(({ app }) => {
|
||||
// return app.reuseWindowForTest();
|
||||
// });
|
||||
|
||||
await tronApp.electronApp?.evaluate(({ app }, projectDirName) => {
|
||||
// @ts-ignore can't declaration merge see main.ts
|
||||
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
|
||||
}, tronApp.dir)
|
||||
|
||||
// Always start at the root view
|
||||
await tronApp.page.goto(firstUrl)
|
||||
|
||||
// Force a hard reload, destroying the stream and other state
|
||||
await tronApp.page.reload()
|
||||
|
||||
// tsc aint smart enough to know this'll never be undefined
|
||||
// but I dont blame it, the logic to know is complex
|
||||
if (fn) {
|
||||
await fn(
|
||||
{
|
||||
context: tronApp.context,
|
||||
page: tronApp.page,
|
||||
electronApp:
|
||||
tronApp instanceof AuthenticatedTronApp
|
||||
? tronApp.electronApp
|
||||
: undefined,
|
||||
...fixtures,
|
||||
request,
|
||||
playwright,
|
||||
browser,
|
||||
acceptDownloads,
|
||||
bypassCSP,
|
||||
colorScheme,
|
||||
clientCertificates,
|
||||
deviceScaleFactor,
|
||||
extraHTTPHeaders,
|
||||
geolocation,
|
||||
hasTouch,
|
||||
httpCredentials,
|
||||
ignoreHTTPSErrors,
|
||||
isMobile,
|
||||
javaScriptEnabled,
|
||||
locale,
|
||||
offline,
|
||||
permissions,
|
||||
proxy,
|
||||
storageState,
|
||||
timezoneId,
|
||||
userAgent,
|
||||
viewport,
|
||||
baseURL,
|
||||
contextOptions,
|
||||
actionTimeout,
|
||||
navigationTimeout,
|
||||
serviceWorkers,
|
||||
testIdAttribute,
|
||||
browserName,
|
||||
defaultBrowserType,
|
||||
headless,
|
||||
channel,
|
||||
launchOptions,
|
||||
connectOptions,
|
||||
screenshot,
|
||||
trace,
|
||||
video,
|
||||
},
|
||||
testInfo
|
||||
)
|
||||
}
|
||||
|
||||
testInfo.tronApp =
|
||||
tronApp instanceof AuthenticatedTronApp ? tronApp : undefined
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
type ZooTest = typeof test
|
||||
|
||||
test.describe = pwTestFnWithFixtures.describe
|
||||
test.beforeEach = pwTestFnWithFixtures.beforeEach
|
||||
test.afterEach = pwTestFnWithFixtures.afterEach
|
||||
test.step = pwTestFnWithFixtures.step
|
||||
test.skip = pwTestFnWithFixtures.skip
|
||||
test.setTimeout = pwTestFnWithFixtures.setTimeout
|
||||
test.fixme = pwTestFnWithFixtures.fixme as unknown as ZooTest
|
||||
test.only = pwTestFnWithFixtures.only
|
||||
test.fail = pwTestFnWithFixtures.fail
|
||||
test.slow = pwTestFnWithFixtures.slow
|
||||
test.beforeAll = pwTestFnWithFixtures.beforeAll
|
||||
test.afterAll = pwTestFnWithFixtures.afterAll
|
||||
test.use = pwTestFnWithFixtures.use
|
||||
test.expect = pwTestFnWithFixtures.expect
|
||||
test.extend = pwTestFnWithFixtures.extend
|
||||
test.info = pwTestFnWithFixtures.info
|
||||
export { test }
|
||||
|
@ -106,7 +106,7 @@
|
||||
"files:flip-to-nightly:windows": "./scripts/flip-files-to-nightly.ps1",
|
||||
"files:invalidate-bucket": "./scripts/invalidate-files-bucket.sh",
|
||||
"files:invalidate-bucket:nightly": "./scripts/invalidate-files-bucket.sh --nightly",
|
||||
"postinstall": "./node_modules/.bin/electron-rebuild",
|
||||
"postinstall": "yarn --cwd ./rust/kcl-language-server --modules-folder node_modules install && ./node_modules/.bin/electron-rebuild",
|
||||
"make:dev": "make dev",
|
||||
"generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts",
|
||||
"generate:samples-manifest": "cd public/kcl-samples && node generate-manifest.js",
|
||||
|
31
rust/Cargo.lock
generated
31
rust/Cargo.lock
generated
@ -1783,7 +1783,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1794,7 +1794,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1813,7 +1813,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1822,7 +1822,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.48"
|
||||
version = "0.2.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1843,7 +1843,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1863,7 +1863,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.48"
|
||||
version = "0.2.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1931,7 +1931,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.48"
|
||||
version = "0.3.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1946,7 +1946,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1959,7 +1959,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1973,7 +1973,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"console_error_panic_hook",
|
||||
@ -3097,15 +3097,14 @@ checksum = "e6cd655523701785087f69900df39892fb7b9b0721aa67682f571c38c32ac58a"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
version = "0.17.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@ -3560,12 +3559,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.48"
|
||||
version = "0.1.49"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
|
@ -72,7 +72,7 @@ impl Build {
|
||||
}
|
||||
|
||||
fn build_client(sh: &Shell, version: &str, release_tag: &str, target: &Target) -> anyhow::Result<()> {
|
||||
let bundle_path = Path::new("server");
|
||||
let bundle_path = Path::new("kcl-language-server/server");
|
||||
sh.create_dir(bundle_path)?;
|
||||
sh.copy_file(&target.server_path, bundle_path)?;
|
||||
if let Some(symbols_path) = &target.symbols_path {
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.48"
|
||||
version = "0.2.49"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -97,7 +97,7 @@ async function getServer(
|
||||
'You need to manually clone the kcl-lsp repository and ' +
|
||||
'run `cargo install` to build the language server from sources. ' +
|
||||
'If you feel that your platform should be supported, please create an issue ' +
|
||||
'about that [here](https://github.com/kittycad/kcl-lsp/issues) and we ' +
|
||||
'about that [here](https://github.com/kittycad/modeling-app/issues) and we ' +
|
||||
'will consider it.'
|
||||
)
|
||||
return undefined
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.48"
|
||||
version = "0.2.49"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -1,8 +1,15 @@
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([0,0], %)
|
||||
|> line(end = [0, 10], tag = $thing)
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [0, -10], tag = $thing2)
|
||||
|> close()
|
||||
startProfileAt([0, 0], startSketchOn("XY"))
|
||||
|> xLine(length = 10, tag = $line000)
|
||||
|> yLine(length = 10, tag = $line001)
|
||||
|> xLine(endAbsolute = profileStartX(%), tag = $line002)
|
||||
|> close(tag = $line003)
|
||||
|> extrude(length = 10)
|
||||
|> fillet(radius = 0.5, tags = [thing, thing])
|
||||
|> fillet(
|
||||
radius = 1,
|
||||
tags = [
|
||||
line003,
|
||||
getNextAdjacentEdge(line000),
|
||||
getPreviousAdjacentEdge(line001)
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -27,11 +27,14 @@ async fn kcl_test_fillet_duplicate_tags() {
|
||||
let code = kcl_input!("fillet_duplicate_tags");
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm, None).await;
|
||||
assert!(result.is_err());
|
||||
let err = result.expect_err("Code should have failed due to the duplicate edges being filletted");
|
||||
|
||||
let err = err.as_kcl_error().unwrap();
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([229, 272, 0])], message: "Duplicate tags are not allowed." }"#,
|
||||
err.message(),
|
||||
"The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge"
|
||||
);
|
||||
assert_eq!(err.source_ranges().len(), 2);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
@ -857,7 +860,7 @@ part = rectShape([0, 0], 20, 20)
|
||||
};
|
||||
assert_eq!(
|
||||
err.error.message(),
|
||||
"This function expected this argument to be of type SketchOrSurface but it's actually of type string (text)"
|
||||
"This function expected the input argument to be of type SketchOrSurface but it's actually of type string (text)"
|
||||
);
|
||||
}
|
||||
|
||||
@ -2103,7 +2106,7 @@ async fn kcl_test_better_type_names() {
|
||||
},
|
||||
None => todo!(),
|
||||
};
|
||||
assert_eq!(err, "This function expected this argument to be of type SolidSet but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`");
|
||||
assert_eq!(err, "This function expected the input argument to be of type SolidSet but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
|
@ -48,6 +48,15 @@ impl ExecErrorWithState {
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecError {
|
||||
pub fn as_kcl_error(&self) -> Option<&crate::KclError> {
|
||||
let ExecError::Kcl(k) = &self else {
|
||||
return None;
|
||||
};
|
||||
Some(&k.error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExecError> for ExecErrorWithState {
|
||||
fn from(error: ExecError) -> Self {
|
||||
Self {
|
||||
|
@ -596,12 +596,11 @@ impl ExecutorContext {
|
||||
self.exec_module_for_result(module_id, exec_state, ExecutionKind::Normal, metadata.source_range)
|
||||
.await?
|
||||
.unwrap_or_else(|| {
|
||||
// The module didn't have a return value. Currently,
|
||||
// the only way to have a return value is with the final
|
||||
// statement being an expression statement.
|
||||
//
|
||||
// TODO: Make a warning when we support them in the
|
||||
// execution phase.
|
||||
exec_state.warn(CompilationError::err(
|
||||
metadata.source_range,
|
||||
"Imported module has no return value. The last statement of the module must be an expression, usually the Solid.",
|
||||
));
|
||||
|
||||
let mut new_meta = vec![metadata.to_owned()];
|
||||
new_meta.extend(meta);
|
||||
KclValue::KclNone {
|
||||
@ -1187,7 +1186,7 @@ impl Node<CallExpressionKw> {
|
||||
},
|
||||
self.into(),
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
||||
exec_state.mod_local.pipe_value.clone().map(|v| Arg::new(v, callsite)),
|
||||
);
|
||||
match ctx.stdlib.get_either(fn_name) {
|
||||
FunctionKind::Core(func) => {
|
||||
@ -1349,7 +1348,7 @@ impl Node<CallExpression> {
|
||||
fn_args,
|
||||
self.into(),
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
||||
exec_state.mod_local.pipe_value.clone().map(|v| Arg::new(v, callsite)),
|
||||
);
|
||||
let mut return_value = {
|
||||
// Don't early-return in this block.
|
||||
@ -2000,7 +1999,11 @@ impl FunctionSource {
|
||||
args,
|
||||
source_range,
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
||||
exec_state
|
||||
.mod_local
|
||||
.pipe_value
|
||||
.clone()
|
||||
.map(|v| Arg::new(v, source_range)),
|
||||
);
|
||||
|
||||
func(exec_state, args).await.map(Some)
|
||||
|
@ -659,7 +659,11 @@ impl KclValue {
|
||||
args,
|
||||
source_range,
|
||||
ctx.clone(),
|
||||
exec_state.mod_local.pipe_value.clone().map(Arg::synthetic),
|
||||
exec_state
|
||||
.mod_local
|
||||
.pipe_value
|
||||
.clone()
|
||||
.map(|v| Arg::new(v, source_range)),
|
||||
);
|
||||
let result = func(exec_state, args).await.map(Some);
|
||||
exec_state.mut_stack().pop_env();
|
||||
|
@ -844,11 +844,23 @@ fn object_property(i: &mut TokenSlice) -> PResult<Node<ObjectProperty>> {
|
||||
))
|
||||
.parse_next(i)?;
|
||||
ignore_whitespace(i);
|
||||
let expr = expression
|
||||
let expr = match expression
|
||||
.context(expected(
|
||||
"the value which you're setting the property to, e.g. in 'height: 4', the value is 4",
|
||||
))
|
||||
.parse_next(i)?;
|
||||
.parse_next(i)
|
||||
{
|
||||
Ok(expr) => expr,
|
||||
Err(_) => {
|
||||
return Err(ErrMode::Cut(
|
||||
CompilationError::fatal(
|
||||
SourceRange::from(sep),
|
||||
"This property has a label, but no value. Put some value after the equals sign",
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let result = Node {
|
||||
start: key.start,
|
||||
@ -2810,7 +2822,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
ignore_whitespace(i);
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ArgPlace {
|
||||
enum ArgPlace {
|
||||
NonCode(Node<NonCodeNode>),
|
||||
LabeledArg(LabeledArg),
|
||||
UnlabeledArg(Expr),
|
||||
@ -2827,22 +2839,34 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
.parse_next(i)?;
|
||||
let (args, non_code_nodes): (Vec<_>, BTreeMap<usize, _>) = args.into_iter().enumerate().try_fold(
|
||||
(Vec::new(), BTreeMap::new()),
|
||||
|(mut args, mut non_code_nodes), (i, e)| {
|
||||
|(mut args, mut non_code_nodes), (index, e)| {
|
||||
match e {
|
||||
ArgPlace::NonCode(x) => {
|
||||
non_code_nodes.insert(i, vec![x]);
|
||||
non_code_nodes.insert(index, vec![x]);
|
||||
}
|
||||
ArgPlace::LabeledArg(x) => {
|
||||
args.push(x);
|
||||
}
|
||||
ArgPlace::UnlabeledArg(arg) => {
|
||||
return Err(ErrMode::Cut(
|
||||
let followed_by_equals = peek((opt(whitespace), equals)).parse_next(i).is_ok();
|
||||
let err = if followed_by_equals {
|
||||
ErrMode::Cut(
|
||||
CompilationError::fatal(
|
||||
SourceRange::from(arg),
|
||||
"This argument has a label, but no value. Put some value after the equals sign",
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
ErrMode::Cut(
|
||||
CompilationError::fatal(
|
||||
SourceRange::from(arg),
|
||||
"This argument needs a label, but it doesn't have one",
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
)
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok((args, non_code_nodes))
|
||||
@ -4678,6 +4702,42 @@ baz = 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sensible_error_when_missing_rhs_of_kw_arg() {
|
||||
for (i, program) in ["f(x, y=)"].into_iter().enumerate() {
|
||||
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
|
||||
let err = fn_call_kw.parse(tokens.as_slice()).unwrap_err();
|
||||
let cause = err.inner().cause.as_ref().unwrap();
|
||||
assert_eq!(
|
||||
cause.message, "This argument has a label, but no value. Put some value after the equals sign",
|
||||
"failed test {i}: {program}"
|
||||
);
|
||||
assert_eq!(
|
||||
cause.source_range.start(),
|
||||
program.find("y").unwrap(),
|
||||
"failed test {i}: {program}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sensible_error_when_missing_rhs_of_obj_property() {
|
||||
for (i, program) in ["{x = 1, y =}"].into_iter().enumerate() {
|
||||
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
|
||||
let err = object.parse(tokens.as_slice()).unwrap_err();
|
||||
let cause = err.inner().cause.as_ref().unwrap();
|
||||
assert_eq!(
|
||||
cause.message, "This property has a label, but no value. Put some value after the equals sign",
|
||||
"failed test {i}: {program}"
|
||||
);
|
||||
assert_eq!(
|
||||
cause.source_range.start(),
|
||||
program.rfind('=').unwrap(),
|
||||
"failed test {i}: {program}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -159,6 +159,49 @@ impl Args {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a labelled keyword arg, check it's an array, and return all items in the array
|
||||
/// plus their source range.
|
||||
pub(crate) fn kw_arg_array_and_source<'a, T>(&'a self, label: &str) -> Result<Vec<(T, SourceRange)>, KclError>
|
||||
where
|
||||
T: FromKclValue<'a>,
|
||||
{
|
||||
let Some(arg) = self.kw_args.labeled.get(label) else {
|
||||
let err = KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![self.source_range],
|
||||
message: format!("This function requires a keyword argument '{label}'"),
|
||||
});
|
||||
return Err(err);
|
||||
};
|
||||
let Some(array) = arg.value.as_array() else {
|
||||
let err = KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: vec![arg.source_range],
|
||||
message: format!(
|
||||
"Expected an array of {} but found {}",
|
||||
type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
});
|
||||
return Err(err);
|
||||
};
|
||||
array
|
||||
.iter()
|
||||
.map(|item| {
|
||||
let source = SourceRange::from(item);
|
||||
let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
message: format!(
|
||||
"Expected a {} but found {}",
|
||||
type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
})
|
||||
})?;
|
||||
Ok((val, source))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
/// Get the unlabeled keyword argument. If not set, returns None.
|
||||
pub(crate) fn unlabeled_kw_arg_unconverted(&self) -> Option<&Arg> {
|
||||
self.kw_args
|
||||
@ -184,7 +227,7 @@ impl Args {
|
||||
T::from_kcl_val(&arg.value).ok_or_else(|| {
|
||||
let expected_type_name = tynm::type_name::<T>();
|
||||
let actual_type_name = arg.value.human_friendly_type();
|
||||
let msg_base = format!("This function expected this argument to be of type {expected_type_name} but it's actually of type {actual_type_name}");
|
||||
let msg_base = format!("This function expected the input argument to be of type {expected_type_name} but it's actually of type {actual_type_name}");
|
||||
let suggestion = match (expected_type_name.as_str(), actual_type_name) {
|
||||
("SolidSet", "Sketch") => Some(
|
||||
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
|
||||
|
@ -5,7 +5,6 @@ use kcl_derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::CutType, ModelingCmd};
|
||||
use kittycad_modeling_cmds as kcmc;
|
||||
|
||||
use super::utils::unique_count;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{ChamferSurface, EdgeCut, ExecState, ExtrudeSurface, GeoMeta, KclValue, Solid},
|
||||
@ -19,9 +18,11 @@ pub(crate) const DEFAULT_TOLERANCE: f64 = 0.0000001;
|
||||
pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solid = args.get_unlabeled_kw_arg("solid")?;
|
||||
let length = args.get_kw_arg("length")?;
|
||||
let tags = args.get_kw_arg("tags")?;
|
||||
let tags = args.kw_arg_array_and_source::<EdgeReference>("tags")?;
|
||||
let tag = args.get_kw_arg_opt("tag")?;
|
||||
|
||||
super::fillet::validate_unique(&tags)?;
|
||||
let tags: Vec<EdgeReference> = tags.into_iter().map(|item| item.0).collect();
|
||||
let value = inner_chamfer(solid, length, tags, tag, exec_state, args).await?;
|
||||
Ok(KclValue::Solid { value })
|
||||
}
|
||||
@ -109,15 +110,6 @@ async fn inner_chamfer(
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
// Check if tags contains any duplicate values.
|
||||
let unique_tags = unique_count(tags.clone());
|
||||
if unique_tags != tags.len() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Duplicate tags are not allowed.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
// If you try and tag multiple edges with a tagged chamfer, we want to return an
|
||||
// error to the user that they can only tag one edge at a time.
|
||||
if tag.is_some() && tags.len() > 1 {
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Standard library fillets.
|
||||
|
||||
use anyhow::Result;
|
||||
use indexmap::IndexMap;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{
|
||||
each_cmd as mcmd, length_unit::LengthUnit, ok_response::OkModelingCmdResponse, shared::CutType,
|
||||
@ -11,13 +12,13 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::utils::unique_count;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{EdgeCut, ExecState, ExtrudeSurface, FilletSurface, GeoMeta, KclValue, Solid, TagIdentifier},
|
||||
parsing::ast::types::TagNode,
|
||||
settings::types::UnitLength,
|
||||
std::Args,
|
||||
SourceRange,
|
||||
};
|
||||
|
||||
/// A tag or a uuid of an edge.
|
||||
@ -40,13 +41,39 @@ impl EdgeReference {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]) -> Result<(), KclError> {
|
||||
// Check if tags contains any duplicate values.
|
||||
let mut tag_counts: IndexMap<&T, Vec<SourceRange>> = Default::default();
|
||||
for tag in tags {
|
||||
tag_counts.entry(&tag.0).or_insert(Vec::new()).push(tag.1);
|
||||
}
|
||||
let mut duplicate_tags_source = Vec::new();
|
||||
for (_tag, count) in tag_counts {
|
||||
if count.len() > 1 {
|
||||
duplicate_tags_source.extend(count)
|
||||
}
|
||||
}
|
||||
if !duplicate_tags_source.is_empty() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "The same edge ID is being referenced multiple times, which is not allowed. Please select a different edge".to_string(),
|
||||
source_ranges: duplicate_tags_source,
|
||||
}));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create fillets on tagged paths.
|
||||
pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
// Get all args:
|
||||
let solid = args.get_unlabeled_kw_arg("solid")?;
|
||||
let radius = args.get_kw_arg("radius")?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
let tags = args.get_kw_arg("tags")?;
|
||||
let tags = args.kw_arg_array_and_source::<EdgeReference>("tags")?;
|
||||
let tag = args.get_kw_arg_opt("tag")?;
|
||||
|
||||
// Run the function.
|
||||
validate_unique(&tags)?;
|
||||
let tags: Vec<EdgeReference> = tags.into_iter().map(|item| item.0).collect();
|
||||
let value = inner_fillet(solid, radius, tags, tolerance, tag, exec_state, args).await?;
|
||||
Ok(KclValue::Solid { value })
|
||||
}
|
||||
@ -129,15 +156,6 @@ async fn inner_fillet(
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
// Check if tags contains any duplicate values.
|
||||
let unique_tags = unique_count(tags.clone());
|
||||
if unique_tags != tags.len() {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Duplicate tags are not allowed.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let mut solid = solid.clone();
|
||||
for edge_tag in tags {
|
||||
let edge_id = edge_tag.get_engine_id(exec_state, &args)?;
|
||||
@ -432,3 +450,22 @@ pub(crate) fn default_tolerance(units: &UnitLength) -> f64 {
|
||||
UnitLength::M => 0.001,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_validate_unique() {
|
||||
let dup_a = SourceRange::from([1, 3, 0]);
|
||||
let dup_b = SourceRange::from([10, 30, 0]);
|
||||
// Two entries are duplicates (abc) with different source ranges.
|
||||
let tags = vec![("abc", dup_a), ("abc", dup_b), ("def", SourceRange::from([2, 4, 0]))];
|
||||
let actual = validate_unique(&tags);
|
||||
// Both the duplicates should show up as errors, with both of the
|
||||
// source ranges they correspond to.
|
||||
// But the unique source range 'def' should not.
|
||||
let expected = vec![dup_a, dup_b];
|
||||
assert_eq!(actual.err().unwrap().source_ranges(), expected);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{collections::HashSet, f64::consts::PI};
|
||||
use std::f64::consts::PI;
|
||||
|
||||
use kittycad_modeling_cmds::shared::Angle;
|
||||
|
||||
@ -8,16 +8,6 @@ use crate::{
|
||||
source_range::SourceRange,
|
||||
};
|
||||
|
||||
/// Count the number of unique items in a `Vec` in O(n) time.
|
||||
pub(crate) fn unique_count<T: Eq + std::hash::Hash>(vec: Vec<T>) -> usize {
|
||||
// Add to a set.
|
||||
let mut set = HashSet::with_capacity(vec.len());
|
||||
for item in vec {
|
||||
set.insert(item);
|
||||
}
|
||||
set.len()
|
||||
}
|
||||
|
||||
/// Get the distance between two points.
|
||||
pub fn distance(a: Point2d, b: Point2d) -> f64 {
|
||||
((b.x - a.x).powi(2) + (b.y - a.y).powi(2)).sqrt()
|
||||
@ -686,11 +676,6 @@ mod get_tangential_arc_to_info_tests {
|
||||
(num * 1000.0).round() / 1000.0
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unique_count() {
|
||||
assert_eq!(unique_count(vec![1, 2, 2, 3, 2]), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_case() {
|
||||
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed angled_line.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed angled_line.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
270,
|
||||
289,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed artifact_graph_example_code1.kcl
|
||||
---
|
||||
[
|
||||
@ -125,8 +125,8 @@ description: Operations executed artifact_graph_example_code1.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
298,
|
||||
332,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed basic_fillet_cube_close_opposite.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed basic_fillet_cube_close_opposite.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
197,
|
||||
217,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -129,8 +129,8 @@ description: Operations executed basic_fillet_cube_close_opposite.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
223,
|
||||
283,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed basic_fillet_cube_end.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed basic_fillet_cube_end.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
185,
|
||||
205,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -129,8 +129,8 @@ description: Operations executed basic_fillet_cube_end.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
211,
|
||||
269,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed basic_fillet_cube_next_adjacent.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed basic_fillet_cube_next_adjacent.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
212,
|
||||
232,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -124,8 +124,8 @@ description: Operations executed basic_fillet_cube_next_adjacent.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
238,
|
||||
294,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed basic_fillet_cube_previous_adjacent.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed basic_fillet_cube_previous_adjacent.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
212,
|
||||
232,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -124,8 +124,8 @@ description: Operations executed basic_fillet_cube_previous_adjacent.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
238,
|
||||
298,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed basic_fillet_cube_start.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed basic_fillet_cube_start.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
185,
|
||||
205,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -130,8 +130,8 @@ description: Operations executed basic_fillet_cube_start.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
211,
|
||||
253,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed big_number_angle_to_match_length_x.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed big_number_angle_to_match_length_x.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
183,
|
||||
203,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed big_number_angle_to_match_length_y.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed big_number_angle_to_match_length_y.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
183,
|
||||
203,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed circle_three_point.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed circle_three_point.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
104,
|
||||
124,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed circular_pattern3d_a_pattern.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed circular_pattern3d_a_pattern.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
159,
|
||||
178,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ description: Operations executed cube.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
374,
|
||||
402,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ description: Operations executed cube_with_error.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
366,
|
||||
390,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1057,
|
||||
1085,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -159,8 +159,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1091,
|
||||
1297,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -280,8 +280,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1497,
|
||||
1521,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -404,8 +404,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1497,
|
||||
1521,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -528,8 +528,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1497,
|
||||
1521,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -652,8 +652,8 @@ description: Operations executed fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1497,
|
||||
1521,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed function_sketch.kcl
|
||||
---
|
||||
[
|
||||
@ -80,8 +80,8 @@ description: Operations executed function_sketch.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
183,
|
||||
202,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed function_sketch_with_position.kcl
|
||||
---
|
||||
[
|
||||
@ -80,8 +80,8 @@ description: Operations executed function_sketch_with_position.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
181,
|
||||
200,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed helix_ccw.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed helix_ccw.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
77,
|
||||
97,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -125,8 +125,8 @@ description: Operations executed i_shape.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2510,
|
||||
2531,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed import_whole.kcl
|
||||
---
|
||||
[
|
||||
@ -64,9 +64,9 @@ description: Operations executed import_whole.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
103,
|
||||
123,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -124,8 +124,8 @@ description: Operations executed import_whole.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
83,
|
||||
123,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1379,
|
||||
1417,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -173,9 +173,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1455,
|
||||
1494,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -428,9 +428,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1379,
|
||||
1417,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -508,9 +508,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1455,
|
||||
1494,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -763,9 +763,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1379,
|
||||
1417,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -843,9 +843,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1455,
|
||||
1494,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1104,9 +1104,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1949,
|
||||
1973,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1190,9 +1190,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
2015,
|
||||
2039,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1339,9 +1339,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
2523,
|
||||
2547,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1485,9 +1485,9 @@ description: Operations executed 3d-boaty.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
3047,
|
||||
3071,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -118,8 +118,8 @@ description: Operations executed 80-20-rail.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6006,
|
||||
6034,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -238,8 +238,8 @@ description: Operations executed 80-20-rail.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6042,
|
||||
6746,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -358,8 +358,8 @@ description: Operations executed 80-20-rail.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6754,
|
||||
7457,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed a-parametric-bearing-pillow-block.kcl
|
||||
---
|
||||
[
|
||||
@ -254,8 +254,8 @@ description: Operations executed a-parametric-bearing-pillow-block.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1902,
|
||||
1936,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -693,8 +693,8 @@ description: Operations executed a-parametric-bearing-pillow-block.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3383,
|
||||
3408,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed ball-bearing.kcl
|
||||
---
|
||||
[
|
||||
@ -519,8 +519,8 @@ description: Operations executed ball-bearing.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1561,
|
||||
1721,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -779,8 +779,8 @@ description: Operations executed ball-bearing.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2214,
|
||||
2374,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1027,8 +1027,8 @@ description: Operations executed ball-bearing.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2718,
|
||||
2878,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed bracket.kcl
|
||||
---
|
||||
[
|
||||
@ -274,8 +274,8 @@ description: Operations executed bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1903,
|
||||
2052,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -724,8 +724,8 @@ description: Operations executed bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3306,
|
||||
3455,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1510,9 +1510,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
529,
|
||||
562,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1622,9 +1622,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
859,
|
||||
892,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1710,9 +1710,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1214,
|
||||
1248,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1798,9 +1798,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1572,
|
||||
1606,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2362,9 +2362,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
4067,
|
||||
4247,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2801,9 +2801,9 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
4067,
|
||||
4247,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -3298,8 +3298,8 @@ description: Operations executed car-wheel-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
373,
|
||||
524,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed enclosure.kcl
|
||||
---
|
||||
[
|
||||
@ -130,8 +130,8 @@ description: Operations executed enclosure.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
740,
|
||||
1021,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -190,8 +190,8 @@ description: Operations executed enclosure.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1100,
|
||||
1170,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1699,8 +1699,8 @@ description: Operations executed enclosure.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3601,
|
||||
3882,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1997,8 +1997,8 @@ description: Operations executed enclosure.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5327,
|
||||
5608,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -338,8 +338,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1547,
|
||||
1570,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -682,8 +682,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1547,
|
||||
1570,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1026,8 +1026,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1547,
|
||||
1570,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1370,8 +1370,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1547,
|
||||
1570,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1744,8 +1744,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3933,
|
||||
3962,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1808,8 +1808,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3968,
|
||||
4101,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1872,8 +1872,8 @@ description: Operations executed exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4107,
|
||||
4240,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed flange-with-patterns.kcl
|
||||
---
|
||||
[
|
||||
@ -174,8 +174,8 @@ description: Operations executed flange-with-patterns.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1413,
|
||||
1444,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -461,8 +461,8 @@ description: Operations executed flange-with-patterns.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1928,
|
||||
1963,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -566,8 +566,8 @@ description: Operations executed flange-with-patterns.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2230,
|
||||
2264,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed flange-xy.kcl
|
||||
---
|
||||
[
|
||||
@ -254,8 +254,8 @@ description: Operations executed flange-xy.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1555,
|
||||
1586,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -552,8 +552,8 @@ description: Operations executed flange-xy.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2077,
|
||||
2112,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -657,8 +657,8 @@ description: Operations executed flange-xy.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2379,
|
||||
2413,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
---
|
||||
[
|
||||
@ -253,8 +253,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1831,
|
||||
1865,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -325,8 +325,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1871,
|
||||
2129,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -612,8 +612,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2875,
|
||||
2900,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -670,8 +670,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2906,
|
||||
3050,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -779,8 +779,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3056,
|
||||
3184,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1066,8 +1066,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3719,
|
||||
3744,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1124,8 +1124,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3750,
|
||||
3894,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1233,8 +1233,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3900,
|
||||
4028,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1476,8 +1476,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4458,
|
||||
4486,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1719,8 +1719,8 @@ description: Operations executed focusrite-scarlett-mounting-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4706,
|
||||
4734,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -323,8 +323,8 @@ description: Operations executed french-press.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2157,
|
||||
2179,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -500,8 +500,8 @@ description: Operations executed french-press.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2185,
|
||||
2340,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1293,8 +1293,8 @@ description: Operations executed french-press.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5053,
|
||||
5092,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed gear-rack.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed gear-rack.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
731,
|
||||
754,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -147,8 +147,8 @@ description: Operations executed gear-rack.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1279,
|
||||
1302,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -265,8 +265,8 @@ description: Operations executed gear-rack.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1409,
|
||||
1508,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -332,8 +332,8 @@ description: Operations executed gear-rack.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1820,
|
||||
1843,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -399,8 +399,8 @@ description: Operations executed gear-rack.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2157,
|
||||
2180,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -5897,8 +5897,8 @@ description: Operations executed gear.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1405,
|
||||
1433,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -9802,8 +9802,8 @@ description: Operations executed gear.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2128,
|
||||
2156,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -9979,8 +9979,8 @@ description: Operations executed gear.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2162,
|
||||
2322,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -10097,8 +10097,8 @@ description: Operations executed gear.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3058,
|
||||
3087,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -919,8 +919,8 @@ description: Operations executed gridfinity-baseplate-magnets.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2243,
|
||||
2360,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1183,8 +1183,8 @@ description: Operations executed gridfinity-baseplate-magnets.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2584,
|
||||
2701,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2008,8 +2008,8 @@ description: Operations executed gridfinity-baseplate-magnets.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6613,
|
||||
6730,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2243,8 +2243,8 @@ description: Operations executed gridfinity-baseplate-magnets.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6933,
|
||||
7050,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -919,8 +919,8 @@ description: Operations executed gridfinity-baseplate.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2118,
|
||||
2235,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1183,8 +1183,8 @@ description: Operations executed gridfinity-baseplate.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2459,
|
||||
2576,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -722,8 +722,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2875,
|
||||
2899,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -794,8 +794,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2905,
|
||||
3134,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -885,8 +885,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3580,
|
||||
3607,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1137,8 +1137,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3813,
|
||||
3943,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1389,8 +1389,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4174,
|
||||
4304,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1612,8 +1612,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4529,
|
||||
4659,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1715,8 +1715,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5002,
|
||||
5046,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1787,8 +1787,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5052,
|
||||
5284,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1847,8 +1847,8 @@ description: Operations executed gridfinity-bins-stacking-lip.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5290,
|
||||
5332,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -722,8 +722,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2618,
|
||||
2642,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -794,8 +794,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2648,
|
||||
2877,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -885,8 +885,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3323,
|
||||
3350,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1137,8 +1137,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3556,
|
||||
3686,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1389,8 +1389,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3917,
|
||||
4047,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1612,8 +1612,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4272,
|
||||
4402,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1715,8 +1715,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4771,
|
||||
4815,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1787,8 +1787,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4821,
|
||||
5053,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1847,8 +1847,8 @@ description: Operations executed gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5059,
|
||||
5101,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed hex-nut.kcl
|
||||
---
|
||||
[
|
||||
@ -118,8 +118,8 @@ description: Operations executed hex-nut.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1038,
|
||||
1059,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ description: Operations executed i-beam.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
652,
|
||||
680,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed kitt.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
900,
|
||||
930,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -160,8 +160,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -243,8 +243,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2204,
|
||||
2235,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -339,8 +339,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -438,8 +438,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -537,8 +537,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -636,8 +636,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -719,8 +719,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3485,
|
||||
3514,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -815,8 +815,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -914,8 +914,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1013,8 +1013,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1112,8 +1112,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1211,8 +1211,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1310,8 +1310,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1409,8 +1409,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1508,8 +1508,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1607,8 +1607,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1706,8 +1706,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1805,8 +1805,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1904,8 +1904,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2003,8 +2003,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2185,8 +2185,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2370,8 +2370,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2489,8 +2489,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2588,8 +2588,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2687,8 +2687,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2786,8 +2786,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2905,8 +2905,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3004,8 +3004,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3103,8 +3103,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3202,8 +3202,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3305,8 +3305,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3405,8 +3405,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3505,8 +3505,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3605,8 +3605,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3705,8 +3705,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3805,8 +3805,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -3905,8 +3905,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -4005,8 +4005,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -4105,8 +4105,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -4205,8 +4205,8 @@ description: Operations executed kitt.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
449,
|
||||
472,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed lego.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed lego.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1780,
|
||||
1804,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -138,8 +138,8 @@ description: Operations executed lego.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2221,
|
||||
2252,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -262,8 +262,8 @@ description: Operations executed lego.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2687,
|
||||
2715,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -528,8 +528,8 @@ description: Operations executed lego.kcl
|
||||
]
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3197,
|
||||
3226,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed mounting-plate.kcl
|
||||
---
|
||||
[
|
||||
@ -273,8 +273,8 @@ description: Operations executed mounting-plate.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1825,
|
||||
1857,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -345,8 +345,8 @@ description: Operations executed mounting-plate.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1863,
|
||||
2127,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed multi-axis-robot.kcl
|
||||
---
|
||||
[
|
||||
@ -212,9 +212,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
769,
|
||||
1045,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -352,9 +352,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1280,
|
||||
1362,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -923,9 +923,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
323,
|
||||
406,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1340,9 +1340,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1143,
|
||||
1226,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -1685,9 +1685,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1996,
|
||||
2079,
|
||||
4
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2341,9 +2341,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1033,
|
||||
1116,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2519,9 +2519,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1415,
|
||||
1498,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -3400,9 +3400,9 @@ description: Operations executed multi-axis-robot.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
1299,
|
||||
1382,
|
||||
6
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -247,8 +247,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5504,
|
||||
5535,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -410,8 +410,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
5838,
|
||||
5872,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -713,8 +713,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3177,
|
||||
3198,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -893,8 +893,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6049,
|
||||
6204,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1431,8 +1431,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6407,
|
||||
6562,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1857,8 +1857,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
6781,
|
||||
6936,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2160,8 +2160,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3177,
|
||||
3198,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2340,8 +2340,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
7426,
|
||||
7581,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2643,8 +2643,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4236,
|
||||
4258,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -2823,8 +2823,8 @@ description: Operations executed pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
7778,
|
||||
7933,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -209,8 +209,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1706,
|
||||
1743,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -452,8 +452,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2178,
|
||||
2209,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -532,8 +532,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2907,
|
||||
2938,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -775,8 +775,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3566,
|
||||
3597,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -856,8 +856,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3816,
|
||||
3847,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -930,8 +930,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4043,
|
||||
4093,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -1173,8 +1173,8 @@ description: Operations executed poopy-shoe.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
4597,
|
||||
4629,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed sheet-metal-bracket.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1299,
|
||||
1325,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -124,8 +124,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1331,
|
||||
1410,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -184,8 +184,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1416,
|
||||
1502,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -244,8 +244,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1508,
|
||||
1594,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -304,8 +304,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1600,
|
||||
1679,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -364,8 +364,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1685,
|
||||
1771,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -424,8 +424,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1777,
|
||||
1856,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -484,8 +484,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1862,
|
||||
1942,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -544,8 +544,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1948,
|
||||
2035,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -687,8 +687,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2446,
|
||||
2473,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -751,8 +751,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2479,
|
||||
2608,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -894,8 +894,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
2976,
|
||||
3003,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -958,8 +958,8 @@ description: Operations executed sheet-metal-bracket.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
3009,
|
||||
3139,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -136,9 +136,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
564,
|
||||
794,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2035,9 +2035,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
745,
|
||||
890,
|
||||
8
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2227,9 +2227,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
745,
|
||||
890,
|
||||
8
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2419,9 +2419,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
745,
|
||||
890,
|
||||
8
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2611,9 +2611,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
745,
|
||||
890,
|
||||
8
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -2923,9 +2923,9 @@ description: Operations executed walkie-talkie.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
891,
|
||||
1096,
|
||||
6
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed kittycad_svg.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed kittycad_svg.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
18347,
|
||||
18366,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed linear_pattern3d_a_pattern.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed linear_pattern3d_a_pattern.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
159,
|
||||
178,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed mike_stress_test.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed mike_stress_test.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
77102,
|
||||
77121,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed neg_xz_plane.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed neg_xz_plane.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
151,
|
||||
174,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed parametric.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed parametric.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
465,
|
||||
488,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ description: Operations executed parametric_with_tan_arc.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
622,
|
||||
645,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Operations executed pentagon_fillet_sugar.kcl
|
||||
---
|
||||
[
|
||||
@ -64,8 +64,8 @@ description: Operations executed pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
379,
|
||||
411,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -164,8 +164,8 @@ description: Operations executed pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
612,
|
||||
640,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -229,8 +229,8 @@ description: Operations executed pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
646,
|
||||
773,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -329,8 +329,8 @@ description: Operations executed pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
812,
|
||||
840,
|
||||
0
|
||||
]
|
||||
}
|
||||
@ -394,8 +394,8 @@ description: Operations executed pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
846,
|
||||
973,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -93,8 +93,8 @@ description: Operations executed pipe_as_arg.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
367,
|
||||
391,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
@ -209,8 +209,8 @@ description: Operations executed poop_chute.kcl
|
||||
}
|
||||
},
|
||||
"sourceRange": [
|
||||
0,
|
||||
0,
|
||||
1719,
|
||||
1757,
|
||||
0
|
||||
]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user