Compare commits

...

26 Commits

Author SHA1 Message Date
5bea90ad9a add API fallback for engine utils lib 2024-10-22 12:58:35 -07:00
d23ddc19eb Merge branch 'main' into mike/engine-utils-wasm 2024-10-22 10:27:12 -07:00
4bd7e02271 Support negative start and end in ranges (#4249)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-10-22 14:28:48 +13:00
26042790b6 Remove setInterval implementations from camera controls (#4255)
* remove setInterval implementations from camera controls

* fmt
2024-10-21 16:46:47 -07:00
af74f3bb05 Upgrade to rust toolchain 1.82.0 (#4245)
* Upgrade to rust toolchain 1.82.0

* Fix lint about variant being too large

* Fix lint about Err variant being too large
2024-10-21 16:35:04 -05:00
0bdedf5854 fix job name for printers (#4234)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Paul Tagliamonte <paul@zoo.dev>
2024-10-21 21:27:32 +00:00
d2c6b5cf3a Buffer file writes, because writing to file after every keypress has bad consequences (#4242)
* Buffer file writes, because writing to file after every keypress does bad things

* fix: kevin -- added timeouts for the time being since the workflow for saving data to disk is now changed

---------

Co-authored-by: Kevin Nadro <kevin@zoo.dev>
2024-10-21 15:07:20 -05:00
c42967d0e7 Fix auto changelog in make-release.sh (#4197) 2024-10-18 11:57:21 -07:00
cb8fc33adb Change CUT_RELEASE_PR to BUILD_RELEASE for out-yml (#4214)
Change CUT_RELEASE_PR to BUILD_RELEASE
2024-10-18 12:46:12 -04:00
2dc8b429ff Cut release v0.26.0 (#4196) 2024-10-18 09:17:13 -07:00
19ffa220e8 Fix reading files from WebAssembly (#4183) 2024-10-18 14:43:01 +00:00
5332ddd88e Add more Machine API capabilities (#4203) 2024-10-18 10:25:54 -04:00
11d9a2ee00 Fix test settings to actually get used (#4191)
* Fix test settings to actually get used

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Export file size changed out from under us again, relax this test to just be above a reasonable size

* Missed on updated export expectation

* Wrong check, should just be greater than

* Fix E2E test, remove console log

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Sketchy rectangle commit fix

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 2ace7a3b0e.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Bump timeouts for snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Re-run CI

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-18 08:31:00 +00:00
bfebc41a5c Franknoirot/adhoc/revert-dedupe-commits (#4213)
* Revert "KCL: Fix duplicate 'type' key"

This reverts commit f650281855.

* Revert "Remove duplicate "type" field in the snapshots (#4211)"

This reverts commit 824b4c823e.
2024-10-18 02:16:44 -04:00
824b4c823e Remove duplicate "type" field in the snapshots (#4211)
* Remove duplicate "type" field in the snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Confirm

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-10-18 01:32:03 -04:00
e65358f635 add needed tangential arc params to the serializable path 2024-10-11 11:11:27 -07:00
0a1201e680 cleanup 2024-10-11 10:55:55 -07:00
9db013e672 fmt 2024-10-11 10:47:17 -07:00
0196d72a2d mini code cleanup 2024-10-11 10:44:46 -07:00
e6af4078bd actual working arcs using engine utils 2024-10-10 18:19:26 -07:00
2b233dc705 it works! 2024-10-10 16:58:12 -07:00
b11e8af9c7 _ 2024-10-10 11:52:33 -07:00
c017847d7b Fix to convert JS Promise to async Rust 2024-10-09 00:09:19 -04:00
9635eea8c1 walking away 2024-10-08 13:15:24 -07:00
5a2df642b1 thrashing 2024-10-08 12:00:34 -07:00
621e41080e delme 2024-10-07 11:36:33 -07:00
119 changed files with 936 additions and 157 deletions

BIN
..env.development.local.swp Normal file

Binary file not shown.

View File

@ -1,3 +1,4 @@
src/wasm-lib/* src/wasm-lib/*
src/lib/engine-utils/engine.js
*.typegen.ts *.typegen.ts
packages/codemirror-lsp-client/dist/* packages/codemirror-lsp-client/dist/*

View File

@ -211,7 +211,7 @@ jobs:
out/*-x86_64-linux.* out/*-x86_64-linux.*
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }} if: ${{ env.BUILD_RELEASE == 'true' }}
with: with:
name: out-yml name: out-yml
path: | path: |

4
.gitignore vendored
View File

@ -66,3 +66,7 @@ venv
# electron # electron
out/ out/
# engine wasm utils
src/lib/engine-utils/engine.wasm
src/lib/engine-utils/engine.js

View File

@ -104,7 +104,7 @@ test(
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(431341) .toBeGreaterThan(300_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')
@ -179,7 +179,7 @@ test(
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(102040) .toBeGreaterThan(100_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')

View File

@ -1,6 +1,16 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
import fsp from 'fs/promises'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { getUtils, setup, tearDown } from './test-utils' import {
darkModeBgColor,
darkModePlaneColorXZ,
executorInputPath,
getUtils,
setup,
setupElectron,
tearDown,
} from './test-utils'
import { join } from 'path'
test.beforeEach(async ({ context, page }, testInfo) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo) await setup(context, page, testInfo)
@ -974,4 +984,84 @@ test.describe('Editor tests', () => {
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) })
test(
`Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'cube')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cube.obj'),
join(bracketDir, 'cube.obj')
)
await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
},
})
const viewportSize = { width: 1200, height: 500 }
await page.setViewportSize(viewportSize)
// Locators and constants
const u = await getUtils(page)
const projectLink = page.getByRole('link', { name: 'cube' })
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
const locationToHavColor = async (
position: { x: number; y: number },
color: [number, number, number]
) => {
return u.getGreatestPixDiff(position, color)
}
const notTheOrigin = {
x: viewportSize.width * 0.55,
y: viewportSize.height * 0.3,
}
const origin = { x: viewportSize.width / 2, y: viewportSize.height / 2 }
const errorIndicators = page.locator('.cm-lint-marker-error')
await test.step(`Open the empty file, see the default planes`, async () => {
await projectLink.click()
await u.waitForPageLoad()
await expect
.poll(
async () => locationToHavColor(notTheOrigin, darkModePlaneColorXZ),
{
timeout: 5000,
message: 'XZ plane color is visible',
}
)
.toBeLessThan(15)
})
await test.step(`Write the import function line`, async () => {
await u.codeLocator.fill(`import('cube.obj')`)
await page.waitForTimeout(800)
})
await test.step(`Reset the camera before checking`, async () => {
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
})
await test.step(`Verify that we see the imported geometry and no errors`, async () => {
await expect(errorIndicators).toHaveCount(0)
await expect
.poll(async () => locationToHavColor(origin, darkModePlaneColorXZ), {
timeout: 3000,
message: 'Plane color should not be visible',
})
.toBeGreaterThan(15)
await expect
.poll(async () => locationToHavColor(origin, darkModeBgColor), {
timeout: 3000,
message: 'Background color should not be visible',
})
.toBeGreaterThan(15)
})
await electronApp.close()
}
)
}) })

View File

@ -136,6 +136,9 @@ test.describe('when using the file tree to', () => {
) )
await pasteCodeInEditor(kclCube) await pasteCodeInEditor(kclCube)
// TODO: We have a timeout of 1s between edits to write to disk. If you reload the page too quickly it won't write to disk.
await tronApp.page.waitForTimeout(2000)
await renameFile(fromFile, toFile) await renameFile(fromFile, toFile)
await tronApp.page.reload() await tronApp.page.reload()
@ -222,9 +225,11 @@ test.describe('when using the file tree to', () => {
) )
await pasteCodeInEditor(kclCube) await pasteCodeInEditor(kclCube)
// TODO: We have a timeout of 1s between edits to write to disk. If you reload the page too quickly it won't write to disk.
await tronApp.page.waitForTimeout(2000)
const kcl1 = 'main.kcl' const kcl1 = 'main.kcl'
const kcl2 = '2.kcl' const kcl2 = '2.kcl'
await createNewFileAndSelect(kcl2) await createNewFileAndSelect(kcl2)
const kclCylinder = await fsp.readFile( const kclCylinder = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cylinder.kcl', 'src/wasm-lib/tests/executor/inputs/cylinder.kcl',
@ -232,6 +237,9 @@ test.describe('when using the file tree to', () => {
) )
await pasteCodeInEditor(kclCylinder) await pasteCodeInEditor(kclCylinder)
// TODO: We have a timeout of 1s between edits to write to disk. If you reload the page too quickly it won't write to disk.
await tronApp.page.waitForTimeout(2000)
await renameFile(kcl2, kcl1) await renameFile(kcl2, kcl1)
await test.step(`Postcondition: ${kcl1} still has the original content`, async () => { await test.step(`Postcondition: ${kcl1} still has the original content`, async () => {

View File

@ -255,7 +255,7 @@ test.describe('Can export from electron app', () => {
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(431341) .toBeGreaterThan(300_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')
@ -851,7 +851,7 @@ test(
} }
) )
test( test.fixme(
'When the project folder is empty, user can create new project and open it.', 'When the project folder is empty, user can create new project and open it.',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ browserName }, testInfo) => {
@ -861,6 +861,12 @@ test(
page.on('console', console.log) page.on('console', console.log)
// Locators and constants
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
const pointOnModel = { x: 660, y: 250 }
const expectedStartCamZPosition = 15633.47
// expect to see text "No Projects found" // expect to see text "No Projects found"
await expect(page.getByText('No Projects found')).toBeVisible() await expect(page.getByText('No Projects found')).toBeVisible()
@ -873,16 +879,7 @@ test(
await page.getByText('project-000').click() await page.getByText('project-000').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ') await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ')
|> startProfileAt([-87.4, 282.92], %) |> startProfileAt([-87.4, 282.92], %)
@ -892,8 +889,28 @@ test(
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
extrude001 = extrude(200, sketch001)`) extrude001 = extrude(200, sketch001)`)
await page.waitForTimeout(800)
const pointOnModel = { x: 660, y: 250 } async function getCameraZValue() {
return page
.getByTestId('cam-z-position')
.inputValue()
.then((value) => parseFloat(value))
}
await test.step(`Reset camera`, async () => {
await u.openDebugPanel()
await u.clearCommandLogs()
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
await expect
.poll(getCameraZValue, {
message: 'Camera Z should be at expected position after reset',
})
.toEqual(expectedStartCamZPosition)
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -901,7 +918,7 @@ extrude001 = extrude(200, sketch001)`)
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), { .poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
timeout: 10_000, timeout: 10_000,
}) })
.toBeLessThan(15) .toBeLessThan(30)
await expect(async () => { await expect(async () => {
await page.mouse.move(0, 0, { steps: 5 }) await page.mouse.move(0, 0, { steps: 5 })

View File

@ -471,7 +471,7 @@ test(
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 }) await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
await page.waitForTimeout(300) await page.waitForTimeout(1000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
@ -528,6 +528,7 @@ test(
// Draw the rectangle // Draw the rectangle
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 30) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 30)
await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 10, { steps: 5 }) await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 10, { steps: 5 })
await page.waitForTimeout(800)
// Ensure the draft rectangle looks the same as it usually does // Ensure the draft rectangle looks the same as it usually does
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
@ -895,7 +896,7 @@ test(
// Wait for the second extrusion to appear // Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished // TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient. // rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000) await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
@ -939,7 +940,7 @@ test(
// Wait for the second extrusion to appear // Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished // TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient. // rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000) await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -47,6 +47,14 @@ export const commonPoints = {
num2: 14.44, num2: 14.44,
} }
/** A semi-reliable color to check the default XZ plane on
* in dark mode in the default camera position
*/
export const darkModePlaneColorXZ: [number, number, number] = [50, 50, 99]
/** A semi-reliable color to check the default dark mode bg color against */
export const darkModeBgColor: [number, number, number] = [27, 27, 27]
export const editorSelector = '[role="textbox"][data-language="kcl"]' export const editorSelector = '[role="textbox"][data-language="kcl"]'
type PaneId = 'variables' | 'code' | 'files' | 'logs' type PaneId = 'variables' | 'code' | 'files' | 'logs'
@ -882,8 +890,8 @@ export async function setupElectron({
appSettings appSettings
? { settings: appSettings } ? { settings: appSettings }
: { : {
...TEST_SETTINGS,
settings: { settings: {
...TEST_SETTINGS,
app: { app: {
...TEST_SETTINGS.app, ...TEST_SETTINGS.app,
projectDirectory: projectDirName, projectDirectory: projectDirName,

2
interface.d.ts vendored
View File

@ -23,8 +23,8 @@ export interface IElectronAPI {
key: string, key: string,
callback: (eventType: string, path: string) => void callback: (eventType: string, path: string) => void
) => void ) => void
readFile: typeof fs.readFile
watchFileOff: (path: string, key: string) => void watchFileOff: (path: string, key: string) => void
readFile: (path: string) => ReturnType<fs.readFile>
writeFile: ( writeFile: (
path: string, path: string,
data: string | Uint8Array data: string | Uint8Array

View File

@ -70,7 +70,7 @@ echo ""
echo "Suggested changelog:" echo "Suggested changelog:"
echo "\`\`\`" echo "\`\`\`"
echo "## What's Changed" echo "## What's Changed"
git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:%s | grep -v Bump | grep -v 'Cut release v' | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}' git log $(git describe --tags --match="v[0-9]*" --abbrev=0)..HEAD --oneline --pretty=format:%s | grep -v Bump | grep -v 'Cut release v' | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}'
echo "" echo ""
echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}" echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}"
echo "\`\`\`" echo "\`\`\`"

View File

@ -1,6 +1,6 @@
{ {
"name": "zoo-modeling-app", "name": "zoo-modeling-app",
"version": "0.25.6", "version": "0.26.0",
"private": true, "private": true,
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"author": { "author": {

View File

@ -64,6 +64,27 @@ export type ReactCameraProperties =
const lastCmdDelay = 50 const lastCmdDelay = 50
class CameraRateLimiter {
lastSend?: Date = undefined
rateLimitMs: number = 16 //60 FPS
send = (f: () => void) => {
let now = new Date()
if (
this.lastSend === undefined ||
now.getTime() - this.lastSend.getTime() > this.rateLimitMs
) {
f()
this.lastSend = now
}
}
reset = () => {
this.lastSend = undefined
}
}
export class CameraControls { export class CameraControls {
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
syncDirection: 'clientToEngine' | 'engineToClient' = 'engineToClient' syncDirection: 'clientToEngine' | 'engineToClient' = 'engineToClient'
@ -77,9 +98,8 @@ export class CameraControls {
enableRotate = true enableRotate = true
enablePan = true enablePan = true
enableZoom = true enableZoom = true
zoomDataFromLastFrame?: number = undefined moveSender: CameraRateLimiter = new CameraRateLimiter()
// holds coordinates, and interaction zoomSender: CameraRateLimiter = new CameraRateLimiter()
moveDataFromLastFrame?: [number, number, string] = undefined
lastPerspectiveFov: number = 45 lastPerspectiveFov: number = 45
pendingZoom: number | null = null pendingZoom: number | null = null
pendingRotation: Vector2 | null = null pendingRotation: Vector2 | null = null
@ -171,6 +191,36 @@ export class CameraControls {
} }
} }
doMove = (interaction: any, coordinates: any) => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
interaction: interaction,
window: {
x: coordinates[0],
y: coordinates[1],
},
},
cmd_id: uuidv4(),
})
}
doZoom = (zoom: number) => {
this.handleStart()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'default_camera_zoom',
magnitude: (-1 * zoom) / window.devicePixelRatio,
},
cmd_id: uuidv4(),
})
this.handleEnd()
}
constructor( constructor(
isOrtho = false, isOrtho = false,
domElement: HTMLCanvasElement, domElement: HTMLCanvasElement,
@ -258,49 +308,6 @@ export class CameraControls {
this.onCameraChange() this.onCameraChange()
} }
// Our stream is never more than 60fps.
// We can get away with capping our "virtual fps" to 60 then.
const FPS_VIRTUAL = 60
const doZoom = () => {
if (this.zoomDataFromLastFrame !== undefined) {
this.handleStart()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'default_camera_zoom',
magnitude:
(-1 * this.zoomDataFromLastFrame) / window.devicePixelRatio,
},
cmd_id: uuidv4(),
})
this.handleEnd()
}
this.zoomDataFromLastFrame = undefined
}
setInterval(doZoom, 1000 / FPS_VIRTUAL)
const doMove = () => {
if (this.moveDataFromLastFrame !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
interaction: this.moveDataFromLastFrame[2] as any,
window: {
x: this.moveDataFromLastFrame[0],
y: this.moveDataFromLastFrame[1],
},
},
cmd_id: uuidv4(),
})
}
this.moveDataFromLastFrame = undefined
}
setInterval(doMove, 1000 / FPS_VIRTUAL)
setTimeout(() => { setTimeout(() => {
this.engineCommandManager.subscribeTo({ this.engineCommandManager.subscribeTo({
event: 'camera_drag_end', event: 'camera_drag_end',
@ -386,7 +393,9 @@ export class CameraControls {
if (interaction === 'none') return if (interaction === 'none') return
if (this.syncDirection === 'engineToClient') { if (this.syncDirection === 'engineToClient') {
this.moveDataFromLastFrame = [event.clientX, event.clientY, interaction] this.moveSender.send(() => {
this.doMove(interaction, [event.clientX, event.clientY])
})
return return
} }
@ -459,7 +468,9 @@ export class CameraControls {
if (this.syncDirection === 'engineToClient') { if (this.syncDirection === 'engineToClient') {
if (interaction === 'zoom') { if (interaction === 'zoom') {
this.zoomDataFromLastFrame = event.deltaY this.zoomSender.send(() => {
this.doZoom(event.deltaY)
})
} else { } else {
// This case will get handled when we add pan and rotate using Apple trackpad. // This case will get handled when we add pan and rotate using Apple trackpad.
console.error( console.error(

View File

@ -135,7 +135,9 @@ function CommandArgOptionInput({
<Combobox.Input <Combobox.Input
id="option-input" id="option-input"
ref={inputRef} ref={inputRef}
onChange={(event) => setQuery(event.target.value)} onChange={(event) =>
!event.target.disabled && setQuery(event.target.value)
}
className="flex-grow px-2 py-1 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80 !bg-transparent focus:outline-none" className="flex-grow px-2 py-1 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80 !bg-transparent focus:outline-none"
onKeyDown={(event) => { onKeyDown={(event) => {
if (event.metaKey && event.key === 'k') if (event.metaKey && event.key === 'k')
@ -175,9 +177,18 @@ function CommandArgOptionInput({
<Combobox.Option <Combobox.Option
key={option.name} key={option.name}
value={option} value={option}
disabled={option.disabled}
className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90" className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90"
> >
<p className="flex-grow">{option.name} </p> <p
className={`flex-grow ${
(option.disabled &&
'text-chalkboard-70 dark:text-chalkboard-50 cursor-not-allowed') ||
''
}`}
>
{option.name}
</p>
{option.value === currentOption?.value && ( {option.value === currentOption?.value && (
<small className="text-chalkboard-70 dark:text-chalkboard-50"> <small className="text-chalkboard-70 dark:text-chalkboard-50">
current current

View File

@ -140,7 +140,7 @@ const FileTreeItem = ({
async (eventType, path) => { async (eventType, path) => {
// Don't try to read a file that was removed. // Don't try to read a file that was removed.
if (isCurrentFile && eventType !== 'unlink') { if (isCurrentFile && eventType !== 'unlink') {
let code = await window.electron.readFile(path) let code = await window.electron.readFile(path, { encoding: 'utf-8' })
code = normalizeLineEndings(code) code = normalizeLineEndings(code)
codeManager.updateCodeStateEditor(code) codeManager.updateCodeStateEditor(code)
} }
@ -488,6 +488,12 @@ export const FileTreeInner = ({
// Refresh the file tree when there are changes. // Refresh the file tree when there are changes.
useFileSystemWatcher( useFileSystemWatcher(
async (eventType, path) => { async (eventType, path) => {
// Our other watcher races with this watcher on the current file changes,
// so we need to stop this one from reacting at all, otherwise Bad Things
// Happen™.
const isCurrentFile = loaderData.file?.path === path
const hasChanged = eventType === 'change'
if (isCurrentFile && hasChanged) return
fileSend({ type: 'Refresh' }) fileSend({ type: 'Refresh' })
}, },
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter( [loaderData?.project?.path, fileContext.selectedDirectory.path].filter(

View File

@ -69,7 +69,7 @@ import { exportFromEngine } from 'lib/exportFromEngine'
import { Models } from '@kittycad/lib/dist/types/src' import { Models } from '@kittycad/lib/dist/types/src'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { EditorSelection, Transaction } from '@codemirror/state' import { EditorSelection, Transaction } from '@codemirror/state'
import { useNavigate, useSearchParams } from 'react-router-dom' import { useLoaderData, useNavigate, useSearchParams } from 'react-router-dom'
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls' import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
import { getVarNameModal } from 'hooks/useToolbarGuards' import { getVarNameModal } from 'hooks/useToolbarGuards'
import { err, reportRejection, trap } from 'lib/trap' import { err, reportRejection, trap } from 'lib/trap'
@ -84,6 +84,7 @@ import {
import { submitAndAwaitTextToKcl } from 'lib/textToCad' import { submitAndAwaitTextToKcl } from 'lib/textToCad'
import { useFileContext } from 'hooks/useFileContext' import { useFileContext } from 'hooks/useFileContext'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { IndexLoaderData } from 'lib/types'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T> state: StateFrom<T>
@ -116,6 +117,7 @@ export const ModelingMachineProvider = ({
} = useSettingsAuthContext() } = useSettingsAuthContext()
const navigate = useNavigate() const navigate = useNavigate()
const { context, send: fileMachineSend } = useFileContext() const { context, send: fileMachineSend } = useFileContext()
const { file } = useLoaderData() as IndexLoaderData
const token = auth?.context?.token const token = auth?.context?.token
const streamRef = useRef<HTMLDivElement>(null) const streamRef = useRef<HTMLDivElement>(null)
const persistedContext = useMemo(() => getPersistedContext(), []) const persistedContext = useMemo(() => getPersistedContext(), [])
@ -409,12 +411,15 @@ export const ModelingMachineProvider = ({
Make: ({ event }) => { Make: ({ event }) => {
if (event.type !== 'Make') return if (event.type !== 'Make') return
// Check if we already have an export intent. // Check if we already have an export intent.
if (engineCommandManager.exportIntent) { if (engineCommandManager.exportInfo) {
toast.error('Already exporting') toast.error('Already exporting')
return return
} }
// Set the export intent. // Set the export intent.
engineCommandManager.exportIntent = ExportIntent.Make engineCommandManager.exportInfo = {
intent: ExportIntent.Make,
name: file?.name || '',
}
// Set the current machine. // Set the current machine.
machineManager.currentMachine = event.data.machine machineManager.currentMachine = event.data.machine
@ -443,12 +448,16 @@ export const ModelingMachineProvider = ({
}, },
'Engine export': ({ event }) => { 'Engine export': ({ event }) => {
if (event.type !== 'Export') return if (event.type !== 'Export') return
if (engineCommandManager.exportIntent) { if (engineCommandManager.exportInfo) {
toast.error('Already exporting') toast.error('Already exporting')
return return
} }
// Set the export intent. // Set the export intent.
engineCommandManager.exportIntent = ExportIntent.Save engineCommandManager.exportInfo = {
intent: ExportIntent.Save,
// This never gets used its only for make.
name: '',
}
const format = { const format = {
...event.data, ...event.data,

View File

@ -12,7 +12,6 @@ export const NetworkMachineIndicator = ({
const machineCount = machineManager.machineCount() const machineCount = machineManager.machineCount()
const reason = machineManager.noMachinesReason() const reason = machineManager.noMachinesReason()
const machines = machineManager.machines const machines = machineManager.machines
console.log('react machines', machines)
return isDesktop() ? ( return isDesktop() ? (
<Popover className="relative"> <Popover className="relative">
@ -55,12 +54,6 @@ export const NetworkMachineIndicator = ({
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs"> <p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
{machine.make_model.model} {machine.make_model.model}
</p> </p>
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
{machine.state.state.toUpperCase()}
{machine.state.state === 'failed' && machine.state.message
? ': ' + machine.state.message
: ''}
</p>
{machine.extra && {machine.extra &&
machine.extra.type === 'bambu' && machine.extra.type === 'bambu' &&
machine.extra.nozzle_diameter && ( machine.extra.nozzle_diameter && (
@ -68,6 +61,17 @@ export const NetworkMachineIndicator = ({
Nozzle Diameter: {machine.extra.nozzle_diameter} Nozzle Diameter: {machine.extra.nozzle_diameter}
</p> </p>
)} )}
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
{`Status: ${machine.state.state
.charAt(0)
.toUpperCase()}${machine.state.state.slice(1)}`}
{machine.state.state === 'failed' && machine.state.message
? ` (${machine.state.message})`
: ''}
{machine.state.state === 'running' && machine.progress
? ` (${Math.round(machine.progress)}%)`
: ''}
</p>
</li> </li>
) )
})} })}

View File

@ -18,6 +18,7 @@ export default class CodeManager {
#updateState: (arg: string) => void = () => {} #updateState: (arg: string) => void = () => {}
private _currentFilePath: string | null = null private _currentFilePath: string | null = null
private _hotkeys: { [key: string]: () => void } = {} private _hotkeys: { [key: string]: () => void } = {}
private timeoutWriter: ReturnType<typeof setTimeout> | undefined = undefined
constructor() { constructor() {
if (isDesktop()) { if (isDesktop()) {
@ -115,7 +116,11 @@ export default class CodeManager {
async writeToFile() { async writeToFile() {
if (isDesktop()) { if (isDesktop()) {
setTimeout(() => { // Only write our buffer contents to file once per second. Any faster
// and file-system watchers which read, will receive empty data during
// writes.
clearTimeout(this.timeoutWriter)
this.timeoutWriter = setTimeout(() => {
// Wait one event loop to give a chance for params to be set // Wait one event loop to give a chance for params to be set
// Save the file to disk // Save the file to disk
this._currentFilePath && this._currentFilePath &&
@ -126,7 +131,7 @@ export default class CodeManager {
console.error('error saving file', err) console.error('error saving file', err)
toast.error('Error saving file, please check file permissions') toast.error('Error saving file, please check file permissions')
}) })
}) }, 1000)
} else { } else {
safeLSSetItem(PERSIST_CODE_KEY, this.code) safeLSSetItem(PERSIST_CODE_KEY, this.code)
} }

View File

@ -41,7 +41,7 @@ beforeAll(async () => {
}, },
}) })
}) })
}, 20_000) }, 30_000)
afterAll(() => { afterAll(() => {
engineCommandManager.tearDown() engineCommandManager.tearDown()

View File

@ -50,6 +50,11 @@ export enum ExportIntent {
Make = 'make', Make = 'make',
} }
export interface ExportInfo {
intent: ExportIntent
name: string
}
type ClientMetrics = Models['ClientMetrics_type'] type ClientMetrics = Models['ClientMetrics_type']
interface WebRTCClientMetrics extends ClientMetrics { interface WebRTCClientMetrics extends ClientMetrics {
@ -1354,7 +1359,7 @@ export class EngineCommandManager extends EventTarget {
* export in progress. Otherwise it is an enum value of the intent. * export in progress. Otherwise it is an enum value of the intent.
* Another export cannot be started if one is already in progress. * Another export cannot be started if one is already in progress.
*/ */
private _exportIntent: ExportIntent | null = null private _exportInfo: ExportInfo | null = null
_commandLogCallBack: (command: CommandLog[]) => void = () => {} _commandLogCallBack: (command: CommandLog[]) => void = () => {}
subscriptions: { subscriptions: {
@ -1410,12 +1415,12 @@ export class EngineCommandManager extends EventTarget {
(() => {}) as any (() => {}) as any
kclManager: null | KclManager = null kclManager: null | KclManager = null
set exportIntent(intent: ExportIntent | null) { set exportInfo(info: ExportInfo | null) {
this._exportIntent = intent this._exportInfo = info
} }
get exportIntent() { get exportInfo() {
return this._exportIntent return this._exportInfo
} }
start({ start({
@ -1607,7 +1612,7 @@ export class EngineCommandManager extends EventTarget {
// because in all other cases we send JSON strings. But in the case of // because in all other cases we send JSON strings. But in the case of
// export we send a binary blob. // export we send a binary blob.
// Pass this to our export function. // Pass this to our export function.
if (this.exportIntent === null || this.pendingExport === undefined) { if (this.exportInfo === null || this.pendingExport === undefined) {
toast.error( toast.error(
'Export intent was not set, but export data was received' 'Export intent was not set, but export data was received'
) )
@ -1617,7 +1622,7 @@ export class EngineCommandManager extends EventTarget {
return return
} }
switch (this.exportIntent) { switch (this.exportInfo.intent) {
case ExportIntent.Save: { case ExportIntent.Save: {
exportSave(event.data, this.pendingExport.toastId).then(() => { exportSave(event.data, this.pendingExport.toastId).then(() => {
this.pendingExport?.resolve(null) this.pendingExport?.resolve(null)
@ -1625,21 +1630,22 @@ export class EngineCommandManager extends EventTarget {
break break
} }
case ExportIntent.Make: { case ExportIntent.Make: {
exportMake(event.data, this.pendingExport.toastId).then( exportMake(
(result) => { event.data,
if (result) { this.exportInfo.name,
this.pendingExport?.resolve(null) this.pendingExport.toastId
} else { ).then((result) => {
this.pendingExport?.reject('Failed to make export') if (result) {
} this.pendingExport?.resolve(null)
}, } else {
this.pendingExport?.reject this.pendingExport?.reject('Failed to make export')
) }
}, this.pendingExport?.reject)
break break
} }
} }
// Set the export intent back to null. // Set the export intent back to null.
this.exportIntent = null this.exportInfo = null
return return
} }
@ -1953,15 +1959,15 @@ export class EngineCommandManager extends EventTarget {
return Promise.resolve(null) return Promise.resolve(null)
} else if (cmd.type === 'export') { } else if (cmd.type === 'export') {
const promise = new Promise<null>((resolve, reject) => { const promise = new Promise<null>((resolve, reject) => {
if (this.exportIntent === null) { if (this.exportInfo === null) {
if (this.exportIntent === null) { if (this.exportInfo === null) {
toast.error('Export intent was not set, but export is being sent') toast.error('Export intent was not set, but export is being sent')
console.error('Export intent was not set, but export is being sent') console.error('Export intent was not set, but export is being sent')
return return
} }
} }
const toastId = toast.loading( const toastId = toast.loading(
this.exportIntent === ExportIntent.Save this.exportInfo.intent === ExportIntent.Save
? EXPORT_TOAST_MESSAGES.START ? EXPORT_TOAST_MESSAGES.START
: MAKE_TOAST_MESSAGES.START : MAKE_TOAST_MESSAGES.START
) )
@ -1975,7 +1981,7 @@ export class EngineCommandManager extends EventTarget {
resolve(passThrough) resolve(passThrough)
}, },
reject: (reason: string) => { reject: (reason: string) => {
this.exportIntent = null this.exportInfo = null
reject(reason) reject(reason)
}, },
commandId: command.cmd_id, commandId: command.cmd_id,

View File

@ -18,7 +18,7 @@ class FileSystemManager {
return Promise.resolve(window.electron.path.join(dir, path)) return Promise.resolve(window.electron.path.join(dir, path))
} }
async readFile(path: string): Promise<Uint8Array | void> { async readFile(path: string): Promise<Uint8Array> {
// Using local file system only works from desktop. // Using local file system only works from desktop.
if (!isDesktop()) { if (!isDesktop()) {
return Promise.reject( return Promise.reject(

View File

@ -110,6 +110,7 @@ const initialise = async () => {
const fullUrl = wasmUrl() const fullUrl = wasmUrl()
const input = await fetch(fullUrl) const input = await fetch(fullUrl)
const buffer = await input.arrayBuffer() const buffer = await input.arrayBuffer()
return await init(buffer) return await init(buffer)
} catch (e) { } catch (e) {
console.log('Error initialising WASM', e) console.log('Error initialising WASM', e)

View File

@ -194,10 +194,24 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
`${machine.id} (${ `${machine.id} (${
machine.make_model.model || machine.make_model.manufacturer machine.make_model.model || machine.make_model.manufacturer
}) (${machine.state.state})` + }) (${machine.state.state})` +
(machine.extra && (machine.hardware_configuration &&
machine.extra.type === 'bambu' && machine.hardware_configuration.type !== 'none' &&
machine.extra.nozzle_diameter machine.hardware_configuration.config.nozzle_diameter
? ` - Nozzle Diameter: ${machine.extra.nozzle_diameter}` ? ` - Nozzle Diameter: ${machine.hardware_configuration.config.nozzle_diameter}`
: '') +
(machine.hardware_configuration &&
machine.hardware_configuration.type !== 'none' &&
machine.hardware_configuration.config.filaments &&
machine.hardware_configuration.config.filaments[0]
? ` - ${
machine.hardware_configuration.config.filaments[0].name
} #${
machine.hardware_configuration.config &&
machine.hardware_configuration.config.filaments[0].color?.slice(
0,
6
)
}`
: ''), : ''),
isCurrent: false, isCurrent: false,
disabled: machine.state.state !== 'idle', disabled: machine.state.state !== 'idle',

View File

@ -258,5 +258,6 @@ export type CommandArgumentWithName<
export type CommandArgumentOption<A> = { export type CommandArgumentOption<A> = {
name: string name: string
isCurrent?: boolean isCurrent?: boolean
disabled?: boolean
value: A value: A
} }

View File

@ -92,6 +92,7 @@ export const MAKE_TOAST_MESSAGES = {
NO_MACHINE_API_IP: 'No machine api ip available', NO_MACHINE_API_IP: 'No machine api ip available',
NO_CURRENT_MACHINE: 'No current machine available', NO_CURRENT_MACHINE: 'No current machine available',
NO_MACHINE_ID: 'No machine id available', NO_MACHINE_ID: 'No machine id available',
NO_NAME: 'No name provided',
ERROR_STARTING_PRINT: 'Error while starting print', ERROR_STARTING_PRINT: 'Error while starting print',
SUCCESS: 'Started print successfully', SUCCESS: 'Started print successfully',
} }

View File

@ -448,7 +448,9 @@ export const readProjectSettingsFile = async (
} }
} }
const configToml = await window.electron.readFile(settingsPath) const configToml = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
const configObj = parseProjectSettings(configToml) const configObj = parseProjectSettings(configToml)
if (err(configObj)) { if (err(configObj)) {
return Promise.reject(configObj) return Promise.reject(configObj)
@ -467,7 +469,9 @@ export const readAppSettingsFile = async () => {
// The file exists, read it and parse it. // The file exists, read it and parse it.
if (window.electron.exists(settingsPath)) { if (window.electron.exists(settingsPath)) {
const configToml = await window.electron.readFile(settingsPath) const configToml = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
const parsedAppConfig = parseAppSettings(configToml) const parsedAppConfig = parseAppSettings(configToml)
if (err(parsedAppConfig)) { if (err(parsedAppConfig)) {
return Promise.reject(parsedAppConfig) return Promise.reject(parsedAppConfig)
@ -527,7 +531,9 @@ export const readTokenFile = async () => {
let settingsPath = await getTokenFilePath() let settingsPath = await getTokenFilePath()
if (window.electron.exists(settingsPath)) { if (window.electron.exists(settingsPath)) {
const token: string = await window.electron.readFile(settingsPath) const token: string = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
if (!token) return '' if (!token) return ''
return token return token

31
src/lib/engineUtils.ts Normal file
View File

@ -0,0 +1,31 @@
import EngineUtils from '@engine-utils'
type KCEngineUtilsEvaluatePath = {
(sketch: string, t: number): string
}
let kcEngineUtilsEvaluatePath: KCEngineUtilsEvaluatePath
export async function init() {
return await new Promise((resolve, reject) => {
try {
EngineUtils().then((module) => {
kcEngineUtilsEvaluatePath = module.cwrap(
'kcEngineUtilsEvaluatePath',
'string',
['string', 'number']
)
resolve(true)
})
} catch (e) {
reject(e)
}
})
}
export async function getTruePathEndPos(sketch: string) {
if (!kcEngineUtilsEvaluatePath) {
await init()
}
return kcEngineUtilsEvaluatePath(sketch, 1.0)
}

View File

@ -8,8 +8,15 @@ import { MAKE_TOAST_MESSAGES } from './constants'
// Make files locally from an export call. // Make files locally from an export call.
export async function exportMake( export async function exportMake(
data: ArrayBuffer, data: ArrayBuffer,
name: string,
toastId: string toastId: string
): Promise<Response | null> { ): Promise<Response | null> {
if (name === '') {
console.error(MAKE_TOAST_MESSAGES.NO_NAME)
toast.error(MAKE_TOAST_MESSAGES.NO_NAME, { id: toastId })
return null
}
if (machineManager.machineCount() === 0) { if (machineManager.machineCount() === 0) {
console.error(MAKE_TOAST_MESSAGES.NO_MACHINES) console.error(MAKE_TOAST_MESSAGES.NO_MACHINES)
toast.error(MAKE_TOAST_MESSAGES.NO_MACHINES, { id: toastId }) toast.error(MAKE_TOAST_MESSAGES.NO_MACHINES, { id: toastId })
@ -39,7 +46,7 @@ export async function exportMake(
const params: components['schemas']['PrintParameters'] = { const params: components['schemas']['PrintParameters'] = {
machine_id: machineId, machine_id: machineId,
job_name: 'Exported Job', // TODO: make this the project name. job_name: name,
} }
try { try {
console.log('params', params) console.log('params', params)

View File

@ -109,7 +109,9 @@ export const fileLoader: LoaderFunction = async (
) )
} }
code = await window.electron.readFile(currentFilePath) code = await window.electron.readFile(currentFilePath, {
encoding: 'utf-8',
})
code = normalizeLineEndings(code) code = normalizeLineEndings(code)
// Update both the state and the editor's code. // Update both the state and the editor's code.

View File

@ -74,7 +74,7 @@ const watchFileOff = (path: string, key: string) => {
fsWatchListeners.set(path, watchers) fsWatchListeners.set(path, watchers)
} }
} }
const readFile = (path: string) => fs.readFile(path, 'utf-8') const readFile = fs.readFile
// It seems like from the node source code this does not actually block but also // It seems like from the node source code this does not actually block but also
// don't trust me on that (jess). // don't trust me on that (jess).
const exists = (path: string) => fsSync.existsSync(path) const exists = (path: string) => fsSync.existsSync(path)

View File

@ -121,9 +121,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.89" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@ -1684,9 +1684,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad-modeling-cmds" name = "kittycad-modeling-cmds"
version = "0.2.68" version = "0.2.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3aedfcc1d8ea9995ec3eb78a6743c585c9380475c48701797f107489b696aa" checksum = "b135696d07a4fab928e5abace4dd05f4976eafab5d73e5747a85dc5a684b936c"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -3005,9 +3005,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.128" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [ dependencies = [
"indexmap 2.6.0", "indexmap 2.6.0",
"itoa", "itoa",

View File

@ -72,7 +72,7 @@ members = [
[workspace.dependencies] [workspace.dependencies]
http = "1" http = "1"
kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] } kittycad = { version = "0.3.23", default-features = false, features = ["js", "requests"] }
kittycad-modeling-cmds = { version = "0.2.68", features = ["websocket"] } kittycad-modeling-cmds = { version = "0.2.70", features = ["websocket"] }
[[test]] [[test]]
name = "executor" name = "executor"

View File

@ -12,7 +12,7 @@ fn basic() {
let expected = Program { let expected = Program {
start: 0, start: 0,
end: 11, end: 11,
body: vec![BodyItem::VariableDeclaration(VariableDeclaration { body: vec![BodyItem::VariableDeclaration(Box::new(VariableDeclaration {
start: 0, start: 0,
end: 11, end: 11,
declarations: vec![VariableDeclarator { declarations: vec![VariableDeclarator {
@ -36,7 +36,7 @@ fn basic() {
visibility: ItemVisibility::Default, visibility: ItemVisibility::Default,
kind: VariableKind::Const, kind: VariableKind::Const,
digest: None, digest: None,
})], }))],
non_code_meta: NonCodeMeta::default(), non_code_meta: NonCodeMeta::default(),
digest: None, digest: None,
}; };

View File

@ -68,7 +68,7 @@ tokio-tungstenite = { version = "0.24.0", features = ["rustls-tls-native-roots"]
tower-lsp = { version = "0.20.0", features = ["proposed"] } tower-lsp = { version = "0.20.0", features = ["proposed"] }
[features] [features]
default = ["engine"] default = ["engine"] # add wasm-engine-utils here when we're ready
cli = ["dep:clap"] cli = ["dep:clap"]
# For the lsp server, when run with stdout for rpc we want to disable println. # For the lsp server, when run with stdout for rpc we want to disable println.
# This is used for editor extensions that use the lsp server. # This is used for editor extensions that use the lsp server.
@ -77,6 +77,10 @@ engine = []
pyo3 = ["dep:pyo3"] pyo3 = ["dep:pyo3"]
# Helper functions also used in benchmarks. # Helper functions also used in benchmarks.
lsp-test-util = [] lsp-test-util = []
#if enabled, kcl will link directly against a wasm build of the engine utils lib to save latency
wasm-engine-utils = []
#if enabled, kcl will link directly against a native build of the engine utils lib to save latency (not yet functional)
native-engine-utils = []
tabled = ["dep:tabled"] tabled = ["dep:tabled"]

View File

@ -454,7 +454,7 @@ pub(crate) use impl_value_meta;
pub enum BodyItem { pub enum BodyItem {
ImportStatement(Box<ImportStatement>), ImportStatement(Box<ImportStatement>),
ExpressionStatement(ExpressionStatement), ExpressionStatement(ExpressionStatement),
VariableDeclaration(VariableDeclaration), VariableDeclaration(Box<VariableDeclaration>),
ReturnStatement(ReturnStatement), ReturnStatement(ReturnStatement),
} }
@ -494,7 +494,7 @@ impl From<&BodyItem> for SourceRange {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
#[databake(path = kcl_lib::ast::types)] #[databake(path = kcl_lib::ast::types)]
#[ts(export)] #[ts(export)]
#[serde(untagged)] #[serde(tag = "type")]
pub enum Expr { pub enum Expr {
Literal(Box<Literal>), Literal(Box<Literal>),
Identifier(Box<Identifier>), Identifier(Box<Identifier>),
@ -2719,7 +2719,7 @@ pub struct FunctionExpression {
impl_value_meta!(FunctionExpression); impl_value_meta!(FunctionExpression);
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct RequiredParamAfterOptionalParam(pub Parameter); pub struct RequiredParamAfterOptionalParam(pub Box<Parameter>);
impl std::fmt::Display for RequiredParamAfterOptionalParam { impl std::fmt::Display for RequiredParamAfterOptionalParam {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -2751,7 +2751,7 @@ impl FunctionExpression {
if param.optional { if param.optional {
found_optional = true; found_optional = true;
} else if found_optional { } else if found_optional {
return Err(RequiredParamAfterOptionalParam(param.clone())); return Err(RequiredParamAfterOptionalParam(Box::new(param.clone())));
} }
} }
let boundary = self.params.partition_point(|param| !param.optional); let boundary = self.params.partition_point(|param| !param.optional);

View File

@ -551,13 +551,13 @@ impl ArrayRangeExpression {
.execute_expr(&self.start_element, exec_state, &metadata, StatementKind::Expression) .execute_expr(&self.start_element, exec_state, &metadata, StatementKind::Expression)
.await? .await?
.get_json_value()?; .get_json_value()?;
let start = parse_json_number_as_u64(&start, (&*self.start_element).into())?; let start = parse_json_number_as_i64(&start, (&*self.start_element).into())?;
let metadata = Metadata::from(&*self.end_element); let metadata = Metadata::from(&*self.end_element);
let end = ctx let end = ctx
.execute_expr(&self.end_element, exec_state, &metadata, StatementKind::Expression) .execute_expr(&self.end_element, exec_state, &metadata, StatementKind::Expression)
.await? .await?
.get_json_value()?; .get_json_value()?;
let end = parse_json_number_as_u64(&end, (&*self.end_element).into())?; let end = parse_json_number_as_i64(&end, (&*self.end_element).into())?;
if end < start { if end < start {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
@ -603,9 +603,9 @@ impl ObjectExpression {
} }
} }
pub fn parse_json_number_as_u64(j: &serde_json::Value, source_range: SourceRange) -> Result<u64, KclError> { fn parse_json_number_as_i64(j: &serde_json::Value, source_range: SourceRange) -> Result<i64, KclError> {
if let serde_json::Value::Number(n) = &j { if let serde_json::Value::Number(n) = &j {
n.as_u64().ok_or_else(|| { n.as_i64().ok_or_else(|| {
KclError::Syntax(KclErrorDetails { KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range], source_ranges: vec![source_range],
message: format!("Invalid integer: {}", j), message: format!("Invalid integer: {}", j),

View File

@ -0,0 +1,57 @@
//! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing)
//! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented
use crate::{
errors::{KclError, KclErrorDetails},
std::Args,
};
use anyhow::Result;
use std::ffi::{CString, CStr};
use kittycad_modeling_cmds::{length_unit::LengthUnit, shared::Point3d};
mod cpp {
use std::os::raw::c_char;
extern "C" {
pub fn kcEngineUtilsEvaluatePath(sketch: *const c_char, t: f64) -> *const c_char;
}
}
pub fn is_available() -> bool {
true
}
pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> {
let c_string = CString::new(sketch).map_err(|e| {
KclError::Internal(KclErrorDetails {
message: format!("{:?}", e),
source_ranges: vec![args.source_range],
})
})?;
let arg = c_string.into_raw();
let result_string: String;
unsafe {
let result = cpp::kcEngineUtilsEvaluatePath(arg, 1.0);
let result_cstr = CStr::from_ptr(result);
let str_slice: &str = result_cstr.to_str().map_err(|e| {
KclError::Internal(KclErrorDetails {
message: format!("{:?}", e),
source_ranges: vec![args.source_range],
})
})?;
let str_buf: String = str_slice.to_owned();
result_string = str_buf.clone();
let _ = CString::from_raw(arg);
}
let point: Point3d<f64> = serde_json::from_str(&result_string).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to path position from json: {}", e),
source_ranges: vec![args.source_range],
})
})?;
Ok(Point3d::<f64>::from(point).map(LengthUnit))
}

View File

@ -0,0 +1,35 @@
//! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing)
//! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented
use crate::{
errors::{KclError, KclErrorDetails},
std::Args,
};
use crate::engine::kcmc::{each_cmd as mcmd, ModelingCmd};
use anyhow::Result;
use kittycad_modeling_cmds::{length_unit::LengthUnit, ok_response::OkModelingCmdResponse, shared::Point3d, websocket::OkWebSocketResponseData};
pub fn is_available() -> bool {
true
}
pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> {
let id = uuid::Uuid::new_v4();
let resp = args.send_modeling_cmd(id, ModelingCmd::from(mcmd::EngineUtilEvaluatePath {
path_json: sketch,
t: 1.0,
})).await?;
let OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::EngineUtilEvaluatePath(point),
} = &resp
else {
return Err(KclError::Engine(KclErrorDetails {
message: format!("mcmd::EngineUtilEvaluatePath response was not as expected: {:?}", resp),
source_ranges: vec![args.source_range],
}));
};
Ok(point.pos)
}

View File

@ -0,0 +1,56 @@
//! Functions for calling into the engine-utils library (a set of C++ utilities containing various logic for client-side CAD processing)
//! Note that this binary may not be available to all builds of kcl, so fallbacks that call the engine API should be implemented
use crate::{
errors::{KclError, KclErrorDetails},
std::Args,
};
use anyhow::Result;
use kittycad_modeling_cmds::{length_unit::LengthUnit, shared::Point3d};
mod cpp {
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen(module = "/../../lib/engineUtils.ts")]
extern "C" {
#[wasm_bindgen(js_name = getTruePathEndPos, catch)]
pub fn get_true_path_end_pos(sketch: String) -> Result<js_sys::Promise, js_sys::Error>;
}
}
pub fn is_available() -> bool {
true
}
async fn call_cpp<F>(args: &Args, f: F) -> Result<String, KclError>
where
F: FnOnce() -> Result<js_sys::Promise, js_sys::Error>,
{
let promise = f().map_err(|e| {
KclError::Internal(KclErrorDetails {
message: format!("{:?}", e),
source_ranges: vec![args.source_range],
})
})?;
let result = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
KclError::Internal(KclErrorDetails {
message: format!("{:?}", e),
source_ranges: vec![args.source_range],
})
})?;
Ok(result.as_string().unwrap_or_default())
}
pub async fn get_true_path_end_pos(sketch: String, args: &Args) -> Result<Point3d<LengthUnit>, KclError> {
let result_str = call_cpp(args, || cpp::get_true_path_end_pos(sketch.into())).await?;
let point: Point3d<f64> = serde_json::from_str(&result_str).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to path position from json: {}", e),
source_ranges: vec![args.source_range],
})
})?;
Ok(Point3d::<f64>::from(point).map(LengthUnit))
}

View File

@ -8,6 +8,17 @@ pub mod conn_mock;
#[cfg(feature = "engine")] #[cfg(feature = "engine")]
pub mod conn_wasm; pub mod conn_wasm;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "native-engine-utils")]
pub mod engine_utils;
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "wasm-engine-utils")]
pub mod engine_utils_wasm;
#[cfg(feature = "engine")]
#[cfg(any(not(target_arch = "wasm32"), all(not(feature = "native-engine-utils"), not(feature = "wasm-engine-utils"))))]
pub mod engine_utils_api;
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, Mutex}, sync::{Arc, Mutex},

View File

@ -1601,6 +1601,19 @@ pub enum Path {
#[serde(flatten)] #[serde(flatten)]
base: BasePath, base: BasePath,
}, },
/// An arc (only used for engine-utils arg serialization for now)
Arc {
#[serde(flatten)]
base: BasePath,
/// angle range
#[ts(type = "[number, number]")]
angle_range: [f64; 2],
/// center
#[ts(type = "[number, number]")]
center: [f64; 2],
/// the arc's radius
radius: f64,
},
/// A arc that is tangential to the last path segment that goes to a point /// A arc that is tangential to the last path segment that goes to a point
TangentialArcTo { TangentialArcTo {
#[serde(flatten)] #[serde(flatten)]
@ -1620,6 +1633,10 @@ pub enum Path {
center: [f64; 2], center: [f64; 2],
/// arc's direction /// arc's direction
ccw: bool, ccw: bool,
/// the arc's radius
radius: f64,
/// the arc's angle offset
offset: f64,
}, },
// TODO: consolidate segment enums, remove Circle. https://github.com/KittyCAD/modeling-app/issues/3940 // TODO: consolidate segment enums, remove Circle. https://github.com/KittyCAD/modeling-app/issues/3940
/// a complete arc /// a complete arc
@ -1668,6 +1685,7 @@ impl Path {
Path::TangentialArcTo { base, .. } => base.geo_meta.id, Path::TangentialArcTo { base, .. } => base.geo_meta.id,
Path::TangentialArc { base, .. } => base.geo_meta.id, Path::TangentialArc { base, .. } => base.geo_meta.id,
Path::Circle { base, .. } => base.geo_meta.id, Path::Circle { base, .. } => base.geo_meta.id,
Path::Arc { base, .. } => base.geo_meta.id,
} }
} }
@ -1680,6 +1698,7 @@ impl Path {
Path::TangentialArcTo { base, .. } => base.tag.clone(), Path::TangentialArcTo { base, .. } => base.tag.clone(),
Path::TangentialArc { base, .. } => base.tag.clone(), Path::TangentialArc { base, .. } => base.tag.clone(),
Path::Circle { base, .. } => base.tag.clone(), Path::Circle { base, .. } => base.tag.clone(),
Path::Arc { base, .. } => base.tag.clone(),
} }
} }
@ -1692,6 +1711,7 @@ impl Path {
Path::TangentialArcTo { base, .. } => base, Path::TangentialArcTo { base, .. } => base,
Path::TangentialArc { base, .. } => base, Path::TangentialArc { base, .. } => base,
Path::Circle { base, .. } => base, Path::Circle { base, .. } => base,
Path::Arc { base, .. } => base,
} }
} }
@ -1704,6 +1724,7 @@ impl Path {
Path::TangentialArcTo { base, .. } => Some(base), Path::TangentialArcTo { base, .. } => Some(base),
Path::TangentialArc { base, .. } => Some(base), Path::TangentialArc { base, .. } => Some(base),
Path::Circle { base, .. } => Some(base), Path::Circle { base, .. } => Some(base),
Path::Arc { base, .. } => Some(base),
} }
} }
} }

View File

@ -1342,7 +1342,7 @@ fn declaration_keyword(i: TokenSlice) -> PResult<(VariableKind, Token)> {
} }
/// Parse a variable/constant declaration. /// Parse a variable/constant declaration.
fn declaration(i: TokenSlice) -> PResult<VariableDeclaration> { fn declaration(i: TokenSlice) -> PResult<Box<VariableDeclaration>> {
let (visibility, visibility_token) = opt(terminated(item_visibility, whitespace)) let (visibility, visibility_token) = opt(terminated(item_visibility, whitespace))
.parse_next(i)? .parse_next(i)?
.map_or((ItemVisibility::Default, None), |pair| (pair.0, Some(pair.1))); .map_or((ItemVisibility::Default, None), |pair| (pair.0, Some(pair.1)));
@ -1404,7 +1404,7 @@ fn declaration(i: TokenSlice) -> PResult<VariableDeclaration> {
.map_err(|e| e.cut())?; .map_err(|e| e.cut())?;
let end = val.end(); let end = val.end();
Ok(VariableDeclaration { Ok(Box::new(VariableDeclaration {
start, start,
end, end,
declarations: vec![VariableDeclarator { declarations: vec![VariableDeclarator {
@ -1417,7 +1417,7 @@ fn declaration(i: TokenSlice) -> PResult<VariableDeclaration> {
visibility, visibility,
kind, kind,
digest: None, digest: None,
}) }))
} }
impl TryFrom<Token> for Identifier { impl TryFrom<Token> for Identifier {

View File

@ -23,11 +23,13 @@ expression: actual
"name": "boxSketch" "name": "boxSketch"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 18, "start": 18,
"end": 143, "end": 143,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 18, "start": 18,
"end": 39, "end": 39,
@ -39,11 +41,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 32, "start": 32,
"end": 38, "end": 38,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 33, "start": 33,
"end": 34, "end": 34,
@ -51,6 +55,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 36, "start": 36,
"end": 37, "end": 37,
@ -63,6 +68,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 47, "start": 47,
"end": 63, "end": 63,
@ -74,11 +80,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 52, "start": 52,
"end": 59, "end": 59,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 53, "start": 53,
"end": 54, "end": 54,
@ -86,6 +94,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 56, "start": 56,
"end": 58, "end": 58,
@ -95,6 +104,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 61, "start": 61,
"end": 62 "end": 62
@ -103,6 +113,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 71, "start": 71,
"end": 96, "end": 96,
@ -114,11 +125,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 85, "start": 85,
"end": 92, "end": 92,
"elements": [ "elements": [
{ {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 86, "start": 86,
"end": 88, "end": 88,
@ -133,6 +146,7 @@ expression: actual
} }
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 90, "start": 90,
"end": 91, "end": 91,
@ -142,6 +156,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 94, "start": 94,
"end": 95 "end": 95
@ -150,6 +165,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 104, "start": 104,
"end": 121, "end": 121,
@ -161,11 +177,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 109, "start": 109,
"end": 117, "end": 117,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 110, "start": 110,
"end": 111, "end": 111,
@ -173,6 +191,7 @@ expression: actual
"raw": "5" "raw": "5"
}, },
{ {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 113, "start": 113,
"end": 116, "end": 116,
@ -189,6 +208,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 119, "start": 119,
"end": 120 "end": 120
@ -197,6 +217,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 129, "start": 129,
"end": 143, "end": 143,
@ -208,6 +229,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 137, "start": 137,
"end": 139, "end": 139,
@ -215,6 +237,7 @@ expression: actual
"raw": "10" "raw": "10"
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 141, "start": 141,
"end": 142 "end": 142

View File

@ -23,6 +23,7 @@ expression: actual
"name": "sg" "name": "sg"
}, },
"init": { "init": {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 11, "start": 11,
"end": 17, "end": 17,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 23, "end": 23,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 23, "end": 23,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 22, "end": 22,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 13, "start": 13,
"end": 20, "end": 20,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 14, "start": 14,
"end": 15, "end": 15,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 17, "start": 17,
"end": 19, "end": 19,

View File

@ -23,10 +23,12 @@ expression: actual
"name": "myArray" "name": "myArray"
}, },
"init": { "init": {
"type": "ArrayRangeExpression",
"type": "ArrayRangeExpression", "type": "ArrayRangeExpression",
"start": 16, "start": 16,
"end": 23, "end": 23,
"startElement": { "startElement": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -34,6 +36,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
"endElement": { "endElement": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 20, "start": 20,
"end": 22, "end": 22,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "firstPrimeNumber" "name": "firstPrimeNumber"
}, },
"init": { "init": {
"type": "FunctionExpression",
"type": "FunctionExpression", "type": "FunctionExpression",
"start": 27, "start": 27,
"end": 57, "end": 57,
@ -37,6 +38,7 @@ expression: actual
"start": 43, "start": 43,
"end": 51, "end": 51,
"argument": { "argument": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 50, "start": 50,
"end": 51, "end": 51,
@ -57,6 +59,7 @@ expression: actual
"start": 62, "start": 62,
"end": 80, "end": 80,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 62, "start": 62,
"end": 80, "end": 80,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "thing" "name": "thing"
}, },
"init": { "init": {
"type": "FunctionExpression",
"type": "FunctionExpression", "type": "FunctionExpression",
"start": 11, "start": 11,
"end": 49, "end": 49,
@ -48,6 +49,7 @@ expression: actual
"start": 32, "start": 32,
"end": 43, "end": 43,
"argument": { "argument": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 39, "start": 39,
"end": 43, "end": 43,
@ -68,6 +70,7 @@ expression: actual
"start": 54, "start": 54,
"end": 66, "end": 66,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 54, "start": 54,
"end": 66, "end": 66,
@ -79,6 +82,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 60, "start": 60,
"end": 65, "end": 65,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "mySketch" "name": "mySketch"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 17, "start": 17,
"end": 165, "end": 165,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 17, "start": 17,
"end": 37, "end": 37,
@ -39,11 +41,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 31, "start": 31,
"end": 36, "end": 36,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 32, "start": 32,
"end": 33, "end": 33,
@ -51,6 +55,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 34, "start": 34,
"end": 35, "end": 35,
@ -63,6 +68,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 49, "start": 49,
"end": 75, "end": 75,
@ -74,11 +80,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 56, "start": 56,
"end": 62, "end": 62,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 57, "start": 57,
"end": 58, "end": 58,
@ -86,6 +94,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 60, "start": 60,
"end": 61, "end": 61,
@ -95,11 +104,13 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 64, "start": 64,
"end": 65 "end": 65
}, },
{ {
"type": "TagDeclarator",
"type": "TagDeclarator", "type": "TagDeclarator",
"start": 67, "start": 67,
"end": 74, "end": 74,
@ -109,6 +120,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 87, "start": 87,
"end": 104, "end": 104,
@ -120,11 +132,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 94, "start": 94,
"end": 100, "end": 100,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 95, "start": 95,
"end": 96, "end": 96,
@ -132,6 +146,7 @@ expression: actual
"raw": "1" "raw": "1"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 98, "start": 98,
"end": 99, "end": 99,
@ -141,6 +156,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 102, "start": 102,
"end": 103 "end": 103
@ -149,6 +165,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 116, "start": 116,
"end": 145, "end": 145,
@ -160,11 +177,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 123, "start": 123,
"end": 129, "end": 129,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 124, "start": 124,
"end": 125, "end": 125,
@ -172,6 +191,7 @@ expression: actual
"raw": "1" "raw": "1"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 127, "start": 127,
"end": 128, "end": 128,
@ -181,11 +201,13 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 131, "start": 131,
"end": 132 "end": 132
}, },
{ {
"type": "TagDeclarator",
"type": "TagDeclarator", "type": "TagDeclarator",
"start": 134, "start": 134,
"end": 144, "end": 144,
@ -195,6 +217,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 157, "start": 157,
"end": 165, "end": 165,
@ -206,6 +229,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 163, "start": 163,
"end": 164 "end": 164

View File

@ -23,11 +23,13 @@ expression: actual
"name": "mySketch" "name": "mySketch"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 17, "start": 17,
"end": 70, "end": 70,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 17, "start": 17,
"end": 37, "end": 37,
@ -39,11 +41,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 31, "start": 31,
"end": 36, "end": 36,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 32, "start": 32,
"end": 33, "end": 33,
@ -51,6 +55,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 34, "start": 34,
"end": 35, "end": 35,
@ -63,6 +68,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 41, "start": 41,
"end": 58, "end": 58,
@ -74,11 +80,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 48, "start": 48,
"end": 54, "end": 54,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 49, "start": 49,
"end": 50, "end": 50,
@ -86,6 +94,7 @@ expression: actual
"raw": "1" "raw": "1"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 52, "start": 52,
"end": 53, "end": 53,
@ -95,6 +104,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 56, "start": 56,
"end": 57 "end": 57
@ -103,6 +113,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 62, "start": 62,
"end": 70, "end": 70,
@ -114,6 +125,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 68, "start": 68,
"end": 69 "end": 69

View File

@ -23,6 +23,7 @@ expression: actual
"name": "myBox" "name": "myBox"
}, },
"init": { "init": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 14, "start": 14,
"end": 30, "end": 30,
@ -34,6 +35,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 28, "start": 28,
"end": 29, "end": 29,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "myBox" "name": "myBox"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 14, "start": 14,
"end": 29, "end": 29,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 14, "start": 14,
"end": 18, "end": 18,
@ -39,6 +41,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 16, "start": 16,
"end": 17, "end": 17,
@ -49,6 +52,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 22, "start": 22,
"end": 29, "end": 29,
@ -60,6 +64,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 24, "start": 24,
"end": 25, "end": 25,
@ -67,6 +72,7 @@ expression: actual
"raw": "2" "raw": "2"
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 27, "start": 27,
"end": 28 "end": 28

View File

@ -23,11 +23,13 @@ expression: actual
"name": "myBox" "name": "myBox"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 14, "start": 14,
"end": 49, "end": 49,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 14, "start": 14,
"end": 30, "end": 30,
@ -39,6 +41,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 28, "start": 28,
"end": 29, "end": 29,
@ -48,6 +51,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 34, "start": 34,
"end": 49, "end": 49,
@ -59,11 +63,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 39, "start": 39,
"end": 45, "end": 45,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 40, "start": 40,
"end": 41, "end": 41,
@ -71,6 +77,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 43, "start": 43,
"end": 44, "end": 44,
@ -79,6 +86,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 47, "start": 47,
"end": 48 "end": 48

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 22, "end": 22,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 22, "end": 22,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 21, "end": 21,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 13, "start": 13,
"end": 19, "end": 19,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 14, "start": 14,
"end": 15, "end": 15,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 36, "end": 36,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 36, "end": 36,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 35, "end": 35,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 13, "start": 13,
"end": 19, "end": 19,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 14, "start": 14,
"end": 15, "end": 15,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -70,11 +75,13 @@ expression: actual
"name": "from" "name": "from"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 27, "start": 27,
"end": 33, "end": 33,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 28, "start": 28,
"end": 29, "end": 29,
@ -82,6 +89,7 @@ expression: actual
"raw": "3" "raw": "3"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 31, "start": 31,
"end": 32, "end": 32,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 19, "end": 19,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 19, "end": 19,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 18, "end": 18,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 11, "start": 11,
"end": 17, "end": 17,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 12, "start": 12,
"end": 13, "end": 13,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 15, "start": 15,
"end": 16, "end": 16,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 35, "end": 35,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 35, "end": 35,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 34, "end": 34,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 13, "start": 13,
"end": 19, "end": 19,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 14, "start": 14,
"end": 15, "end": 15,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -70,11 +75,13 @@ expression: actual
"name": "from" "name": "from"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 27, "start": 27,
"end": 33, "end": 33,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 28, "start": 28,
"end": 29, "end": 29,
@ -82,6 +89,7 @@ expression: actual
"raw": "3" "raw": "3"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 31, "start": 31,
"end": 32, "end": 32,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 35, "end": 35,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 35, "end": 35,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 7, "start": 7,
"end": 34, "end": 34,
@ -38,11 +40,13 @@ expression: actual
"name": "to" "name": "to"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 13, "start": 13,
"end": 19, "end": 19,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 14, "start": 14,
"end": 15, "end": 15,
@ -50,6 +54,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -70,11 +75,13 @@ expression: actual
"name": "from" "name": "from"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 26, "start": 26,
"end": 32, "end": 32,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 27, "start": 27,
"end": 28, "end": 28,
@ -82,6 +89,7 @@ expression: actual
"raw": "3" "raw": "3"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 30, "start": 30,
"end": 31, "end": 31,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "mySketch" "name": "mySketch"
}, },
"init": { "init": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 17, "start": 17,
"end": 37, "end": 37,
@ -34,11 +35,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 31, "start": 31,
"end": 36, "end": 36,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 32, "start": 32,
"end": 33, "end": 33,
@ -46,6 +49,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 34, "start": 34,
"end": 35, "end": 35,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 28, "end": 28,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 28, "end": 28,
@ -23,6 +24,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 4, "start": 4,
"end": 5, "end": 5,
@ -30,6 +32,7 @@ expression: actual
"raw": "5" "raw": "5"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 7, "start": 7,
"end": 14, "end": 14,
@ -37,6 +40,7 @@ expression: actual
"raw": "\"hello\"" "raw": "\"hello\""
}, },
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 16, "start": 16,
"end": 27, "end": 27,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 7, "end": 7,
"expression": { "expression": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 0, "start": 0,
"end": 7, "end": 7,

View File

@ -12,6 +12,7 @@ expression: actual
"start": 0, "start": 0,
"end": 15, "end": 15,
"expression": { "expression": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 0, "start": 0,
"end": 15, "end": 15,
@ -23,11 +24,13 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 5, "start": 5,
"end": 11, "end": 11,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 6, "start": 6,
"end": 7, "end": 7,
@ -35,6 +38,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 9, "start": 9,
"end": 10, "end": 10,
@ -43,6 +47,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 13, "start": 13,
"end": 14 "end": 14

View File

@ -23,11 +23,13 @@ expression: actual
"name": "cylinder" "name": "cylinder"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 17, "start": 17,
"end": 107, "end": 107,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 17, "start": 17,
"end": 36, "end": 36,
@ -39,6 +41,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 31, "start": 31,
"end": 35, "end": 35,
@ -49,6 +52,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 44, "start": 44,
"end": 85, "end": 85,
@ -60,6 +64,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 51, "start": 51,
"end": 81, "end": 81,
@ -75,11 +80,13 @@ expression: actual
"name": "center" "name": "center"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 61, "start": 61,
"end": 67, "end": 67,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 62, "start": 62,
"end": 63, "end": 63,
@ -87,6 +94,7 @@ expression: actual
"raw": "0" "raw": "0"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 65, "start": 65,
"end": 66, "end": 66,
@ -107,6 +115,7 @@ expression: actual
"name": "radius" "name": "radius"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 77, "start": 77,
"end": 79, "end": 79,
@ -117,6 +126,7 @@ expression: actual
] ]
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 83, "start": 83,
"end": 84 "end": 84
@ -125,6 +135,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 93, "start": 93,
"end": 107, "end": 107,
@ -136,6 +147,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 101, "start": 101,
"end": 103, "end": 103,
@ -143,6 +155,7 @@ expression: actual
"raw": "14" "raw": "14"
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 105, "start": 105,
"end": 106 "end": 106

View File

@ -23,6 +23,7 @@ expression: actual
"name": "f" "name": "f"
}, },
"init": { "init": {
"type": "FunctionExpression",
"type": "FunctionExpression", "type": "FunctionExpression",
"start": 7, "start": 7,
"end": 49, "end": 49,
@ -48,6 +49,7 @@ expression: actual
"start": 21, "start": 21,
"end": 47, "end": 47,
"argument": { "argument": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 28, "start": 28,
"end": 47, "end": 47,
@ -59,12 +61,14 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 36, "start": 36,
"end": 41, "end": 41,
"name": "angle" "name": "angle"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 43, "start": 43,
"end": 46, "end": 46,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "numbers" "name": "numbers"
}, },
"init": { "init": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 14, "start": 14,
"end": 91, "end": 91,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 28, "start": 28,
"end": 29, "end": 29,
@ -35,6 +37,7 @@ expression: actual
"raw": "1" "raw": "1"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 79, "start": 79,
"end": 80, "end": 80,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "numbers" "name": "numbers"
}, },
"init": { "init": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 14, "start": 14,
"end": 91, "end": 91,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 28, "start": 28,
"end": 29, "end": 29,
@ -35,6 +37,7 @@ expression: actual
"raw": "1" "raw": "1"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 43, "start": 43,
"end": 44, "end": 44,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "props" "name": "props"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 80, "end": 80,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 29, "start": 29,
"end": 30, "end": 30,
@ -56,6 +58,7 @@ expression: actual
"name": "c" "name": "c"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 68, "start": 68,
"end": 69, "end": 69,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "props" "name": "props"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 79, "end": 79,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 29, "start": 29,
"end": 30, "end": 30,
@ -56,6 +58,7 @@ expression: actual
"name": "c" "name": "c"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 68, "start": 68,
"end": 69, "end": 69,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "myVar" "name": "myVar"
}, },
"init": { "init": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 14, "start": 14,
"end": 36, "end": 36,
@ -34,6 +35,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 18, "start": 18,
"end": 19, "end": 19,
@ -41,6 +43,7 @@ expression: actual
"raw": "5" "raw": "5"
}, },
{ {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 22, "start": 22,
"end": 35, "end": 35,
@ -58,6 +61,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 30, "start": 30,
"end": 31, "end": 31,
@ -65,6 +69,7 @@ expression: actual
"raw": "5" "raw": "5"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 33, "start": 33,
"end": 34, "end": 34,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "sketch001" "name": "sketch001"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 19, "start": 19,
"end": 132, "end": 132,
"body": [ "body": [
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 19, "start": 19,
"end": 38, "end": 38,
@ -39,6 +41,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 33, "start": 33,
"end": 37, "end": 37,
@ -49,6 +52,7 @@ expression: actual
"optional": false "optional": false
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 115, "start": 115,
"end": 132, "end": 132,
@ -60,6 +64,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 130, "start": 130,
"end": 131 "end": 131

View File

@ -23,6 +23,7 @@ expression: actual
"name": "my14" "name": "my14"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 14, "start": 14,
"end": 31, "end": 31,

View File

@ -23,10 +23,12 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "IfExpression",
"type": "IfExpression", "type": "IfExpression",
"start": 10, "start": 10,
"end": 74, "end": 74,
"cond": { "cond": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 13, "start": 13,
"end": 17, "end": 17,
@ -43,6 +45,7 @@ expression: actual
"start": 32, "start": 32,
"end": 33, "end": 33,
"expression": { "expression": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 32, "start": 32,
"end": 33, "end": 33,
@ -63,6 +66,7 @@ expression: actual
"start": 63, "start": 63,
"end": 64, "end": 64,
"expression": { "expression": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 63, "start": 63,
"end": 64, "end": 64,

View File

@ -23,10 +23,12 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "IfExpression",
"type": "IfExpression", "type": "IfExpression",
"start": 10, "start": 10,
"end": 121, "end": 121,
"cond": { "cond": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 13, "start": 13,
"end": 17, "end": 17,
@ -43,6 +45,7 @@ expression: actual
"start": 32, "start": 32,
"end": 33, "end": 33,
"expression": { "expression": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 32, "start": 32,
"end": 33, "end": 33,
@ -58,6 +61,7 @@ expression: actual
"start": 44, "start": 44,
"end": 90, "end": 90,
"cond": { "cond": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 52, "start": 52,
"end": 64, "end": 64,
@ -69,6 +73,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 57, "start": 57,
"end": 63, "end": 63,
@ -87,6 +92,7 @@ expression: actual
"start": 79, "start": 79,
"end": 80, "end": 80,
"expression": { "expression": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 79, "start": 79,
"end": 80, "end": 80,
@ -109,6 +115,7 @@ expression: actual
"start": 110, "start": 110,
"end": 111, "end": 111,
"expression": { "expression": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 110, "start": 110,
"end": 111, "end": 111,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 8, "start": 8,
"end": 14, "end": 14,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 8, "start": 8,
"end": 14, "end": 14,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 4, "start": 4,
"end": 5, "end": 5,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 42, "end": 42,
@ -38,11 +39,13 @@ expression: actual
"name": "center" "name": "center"
}, },
"value": { "value": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 22, "start": 22,
"end": 30, "end": 30,
"elements": [ "elements": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 25, "end": 25,
@ -50,6 +53,7 @@ expression: actual
"raw": "10" "raw": "10"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 27, "start": 27,
"end": 29, "end": 29,
@ -70,6 +74,7 @@ expression: actual
"name": "radius" "name": "radius"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 40, "start": 40,
"end": 41, "end": 41,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "myVar" "name": "myVar"
}, },
"init": { "init": {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 14, "start": 14,
"end": 35, "end": 35,
@ -34,6 +35,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "UnaryExpression",
"type": "UnaryExpression", "type": "UnaryExpression",
"start": 18, "start": 18,
"end": 31, "end": 31,
@ -51,6 +53,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 26, "start": 26,
"end": 27, "end": 27,
@ -58,6 +61,7 @@ expression: actual
"raw": "5" "raw": "5"
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 29, "start": 29,
"end": 30, "end": 30,
@ -69,6 +73,7 @@ expression: actual
} }
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 33, "start": 33,
"end": 34, "end": 34,

View File

@ -23,11 +23,13 @@ expression: actual
"name": "myVar" "name": "myVar"
}, },
"init": { "init": {
"type": "PipeExpression",
"type": "PipeExpression", "type": "PipeExpression",
"start": 14, "start": 14,
"end": 36, "end": 36,
"body": [ "body": [
{ {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 14, "start": 14,
"end": 19, "end": 19,
@ -50,6 +52,7 @@ expression: actual
} }
}, },
{ {
"type": "CallExpression",
"type": "CallExpression", "type": "CallExpression",
"start": 23, "start": 23,
"end": 36, "end": 36,
@ -61,6 +64,7 @@ expression: actual
}, },
"arguments": [ "arguments": [
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 30, "start": 30,
"end": 32, "end": 32,
@ -68,6 +72,7 @@ expression: actual
"raw": "45" "raw": "45"
}, },
{ {
"type": "PipeSubstitution",
"type": "PipeSubstitution", "type": "PipeSubstitution",
"start": 34, "start": 34,
"end": 35 "end": 35

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 10, "start": 10,
"end": 27, "end": 27,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 8, "start": 8,
"end": 18, "end": 18,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 10, "start": 10,
"end": 11, "end": 11,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "x" "name": "x"
}, },
"init": { "init": {
"type": "FunctionExpression",
"type": "FunctionExpression", "type": "FunctionExpression",
"start": 7, "start": 7,
"end": 58, "end": 58,
@ -37,6 +38,7 @@ expression: actual
"start": 23, "start": 23,
"end": 32, "end": 32,
"argument": { "argument": {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 30, "start": 30,
"end": 32, "end": 32,
@ -49,6 +51,7 @@ expression: actual
"start": 41, "start": 41,
"end": 50, "end": 50,
"argument": { "argument": {
"type": "Identifier",
"type": "Identifier", "type": "Identifier",
"start": 48, "start": 48,
"end": 50, "end": 50,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,6 +89,7 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 46, "start": 46,
"end": 55, "end": 55,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,6 +89,7 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 47, "start": 47,
"end": 59, "end": 59,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,6 +89,7 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 46, "start": 46,
"end": 58, "end": 58,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,11 +89,13 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 46, "start": 46,
"end": 63, "end": 63,
"elements": [ "elements": [
{ {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 47, "start": 47,
"end": 59, "end": 59,
@ -127,6 +132,7 @@ expression: actual
} }
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 61, "start": 61,
"end": 62, "end": 62,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,11 +89,13 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 46, "start": 46,
"end": 63, "end": 63,
"elements": [ "elements": [
{ {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 47, "start": 47,
"end": 59, "end": 59,
@ -127,6 +132,7 @@ expression: actual
} }
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 61, "start": 61,
"end": 62, "end": 62,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "obj" "name": "obj"
}, },
"init": { "init": {
"type": "ObjectExpression",
"type": "ObjectExpression", "type": "ObjectExpression",
"start": 12, "start": 12,
"end": 26, "end": 26,
@ -38,6 +39,7 @@ expression: actual
"name": "a" "name": "a"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 17, "start": 17,
"end": 18, "end": 18,
@ -56,6 +58,7 @@ expression: actual
"name": "b" "name": "b"
}, },
"value": { "value": {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 23, "start": 23,
"end": 24, "end": 24,
@ -86,11 +89,13 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "ArrayExpression",
"type": "ArrayExpression", "type": "ArrayExpression",
"start": 46, "start": 46,
"end": 62, "end": 62,
"elements": [ "elements": [
{ {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 47, "start": 47,
"end": 58, "end": 58,
@ -127,6 +132,7 @@ expression: actual
} }
}, },
{ {
"type": "Literal",
"type": "Literal", "type": "Literal",
"start": 60, "start": 60,
"end": 61, "end": 61,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "height" "name": "height"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 15, "start": 15,
"end": 24, "end": 24,

View File

@ -23,6 +23,7 @@ expression: actual
"name": "six" "name": "six"
}, },
"init": { "init": {
"type": "BinaryExpression",
"type": "BinaryExpression", "type": "BinaryExpression",
"start": 12, "start": 12,
"end": 21, "end": 21,

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