multi-profile follow up. (#4802)
* multi-profile work * fix enter sketch on cap * fix coderef problem for walls and caps * allow sketch mode entry from circle * clean up * update snapshot * Look at this (photo)Graph *in the voice of Nickelback* * trigger CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * add test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * fix how expression index is corrected, to make compatible with offset planes * another test * tweak test * more test tweaks * break up test to fix it hopfully * fix onboarding test * remove bad comment --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -216,7 +216,7 @@ export class SceneFixture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectPixelColor = async (
|
expectPixelColor = async (
|
||||||
colour: [number, number, number],
|
colour: [number, number, number] | [number, number, number][],
|
||||||
coords: { x: number; y: number },
|
coords: { x: number; y: number },
|
||||||
diff: number
|
diff: number
|
||||||
) => {
|
) => {
|
||||||
@ -237,22 +237,36 @@ export class SceneFixture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isColourArray(
|
||||||
|
colour: [number, number, number] | [number, number, number][]
|
||||||
|
): colour is [number, number, number][] {
|
||||||
|
return Array.isArray(colour[0])
|
||||||
|
}
|
||||||
|
|
||||||
export async function expectPixelColor(
|
export async function expectPixelColor(
|
||||||
page: Page,
|
page: Page,
|
||||||
colour: [number, number, number],
|
colour: [number, number, number] | [number, number, number][],
|
||||||
coords: { x: number; y: number },
|
coords: { x: number; y: number },
|
||||||
diff: number
|
diff: number
|
||||||
) {
|
) {
|
||||||
let finalValue = colour
|
let finalValue = colour
|
||||||
await expect
|
await expect
|
||||||
.poll(async () => {
|
.poll(
|
||||||
|
async () => {
|
||||||
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
|
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
|
||||||
if (!pixel) return null
|
if (!pixel) return null
|
||||||
finalValue = pixel
|
finalValue = pixel
|
||||||
|
if (!isColourArray(colour)) {
|
||||||
return pixel.every(
|
return pixel.every(
|
||||||
(channel, index) => Math.abs(channel - colour[index]) < diff
|
(channel, index) => Math.abs(channel - colour[index]) < diff
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
return colour.some((c) =>
|
||||||
|
c.every((channel, index) => Math.abs(pixel[index] - channel) < diff)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ timeout: 10_000 }
|
||||||
|
)
|
||||||
.toBeTruthy()
|
.toBeTruthy()
|
||||||
.catch((cause) => {
|
.catch((cause) => {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
PERSIST_MODELING_CONTEXT,
|
PERSIST_MODELING_CONTEXT,
|
||||||
setup,
|
setup,
|
||||||
tearDown,
|
tearDown,
|
||||||
|
TEST_COLORS,
|
||||||
} from './test-utils'
|
} from './test-utils'
|
||||||
import { uuidv4, roundOff } from 'lib/utils'
|
import { uuidv4, roundOff } from 'lib/utils'
|
||||||
|
|
||||||
@ -1350,7 +1351,7 @@ test2.describe('Sketch mode should be toleratant to syntax errors', () => {
|
|||||||
|
|
||||||
const [objClick] = scene.makeMouseHelpers(600, 250)
|
const [objClick] = scene.makeMouseHelpers(600, 250)
|
||||||
const arrowHeadLocation = { x: 604, y: 129 } as const
|
const arrowHeadLocation = { x: 604, y: 129 } as const
|
||||||
const arrowHeadWhite: [number, number, number] = [255, 255, 255]
|
const arrowHeadWhite = TEST_COLORS.WHITE
|
||||||
const backgroundGray: [number, number, number] = [28, 28, 28]
|
const backgroundGray: [number, number, number] = [28, 28, 28]
|
||||||
const verifyArrowHeadColor = async (c: [number, number, number]) =>
|
const verifyArrowHeadColor = async (c: [number, number, number]) =>
|
||||||
scene.expectPixelColor(c, arrowHeadLocation, 15)
|
scene.expectPixelColor(c, arrowHeadLocation, 15)
|
||||||
@ -1993,4 +1994,334 @@ extrude001 = extrude(75, thePart)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
test2(
|
||||||
|
'Can enter sketch on sketch of wall and cap for segment, solid2d, extrude-wall, extrude-cap selections',
|
||||||
|
async ({ app, scene, toolbar, editor }) => {
|
||||||
|
// TODO this test should include a test for selecting revolve walls and caps
|
||||||
|
await app.initialise(`sketch001 = startSketchOn('XZ')
|
||||||
|
profile001 = startProfileAt([6.71, -3.66], sketch001)
|
||||||
|
|> line([2.65, 9.02], %, $seg02)
|
||||||
|
|> line([3.73, -9.36], %, $seg01)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(20, profile001)
|
||||||
|
sketch002 = startSketchOn(extrude001, seg01)
|
||||||
|
profile002 = startProfileAt([0.75, 13.46], sketch002)
|
||||||
|
|> line([4.52, 3.79], %)
|
||||||
|
|> line([5.98, -2.81], %)
|
||||||
|
profile003 = startProfileAt([3.19, 13.3], sketch002)
|
||||||
|
|> angledLine([0, 6.64], %, $rectangleSegmentA001)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA001) - 90,
|
||||||
|
2.81
|
||||||
|
], %)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA001),
|
||||||
|
-segLen(rectangleSegmentA001)
|
||||||
|
], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
profile004 = startProfileAt([3.15, 9.39], sketch002)
|
||||||
|
|> xLine(6.92, %)
|
||||||
|
|> line([-7.41, -2.85], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
profile005 = circle({ center = [5.15, 4.34], radius = 1.66 }, sketch002)
|
||||||
|
profile006 = startProfileAt([9.65, 3.82], sketch002)
|
||||||
|
|> line([2.38, 5.62], %)
|
||||||
|
|> line([2.13, -5.57], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
revolve001 = revolve({
|
||||||
|
angle = 45,
|
||||||
|
axis = getNextAdjacentEdge(seg01)
|
||||||
|
}, profile004)
|
||||||
|
extrude002 = extrude(4, profile006)
|
||||||
|
sketch003 = startSketchOn('-XZ')
|
||||||
|
profile007 = startProfileAt([4.8, 7.55], sketch003)
|
||||||
|
|> line([7.39, 2.58], %)
|
||||||
|
|> line([7.02, -2.85], %)
|
||||||
|
profile008 = startProfileAt([5.54, 5.49], sketch003)
|
||||||
|
|> line([6.34, 2.64], %)
|
||||||
|
|> line([6.33, -2.96], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
profile009 = startProfileAt([5.23, 1.95], sketch003)
|
||||||
|
|> line([6.8, 2.17], %)
|
||||||
|
|> line([7.34, -2.75], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
profile010 = circle({
|
||||||
|
center = [7.18, -2.11],
|
||||||
|
radius = 2.67
|
||||||
|
}, sketch003)
|
||||||
|
profile011 = startProfileAt([5.07, -6.39], sketch003)
|
||||||
|
|> angledLine([0, 4.54], %, $rectangleSegmentA002)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA002) - 90,
|
||||||
|
4.17
|
||||||
|
], %)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA002),
|
||||||
|
-segLen(rectangleSegmentA002)
|
||||||
|
], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude003 = extrude(2.5, profile011)
|
||||||
|
revolve002 = revolve({ angle = 45, axis = seg02 }, profile008)
|
||||||
|
`)
|
||||||
|
|
||||||
|
const camPositionForSelectingSketchOnWallProfiles = () =>
|
||||||
|
scene.moveCameraTo(
|
||||||
|
{ x: 834, y: -680, z: 534 },
|
||||||
|
{ x: -54, y: -476, z: 148 }
|
||||||
|
)
|
||||||
|
const camPositionForSelectingSketchOnCapProfiles = () =>
|
||||||
|
scene.moveCameraTo(
|
||||||
|
{ x: 404, y: 690, z: 38 },
|
||||||
|
{ x: 16, y: -140, z: -10 }
|
||||||
|
)
|
||||||
|
const wallSelectionOptions = [
|
||||||
|
{
|
||||||
|
title: 'select wall segment',
|
||||||
|
selectClick: scene.makeMouseHelpers(598, 211)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select wall solid 2d',
|
||||||
|
selectClick: scene.makeMouseHelpers(677, 236)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select wall circle',
|
||||||
|
selectClick: scene.makeMouseHelpers(811, 247)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select wall extrude wall',
|
||||||
|
selectClick: scene.makeMouseHelpers(793, 136)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select wall extrude cap',
|
||||||
|
selectClick: scene.makeMouseHelpers(836, 103)[0],
|
||||||
|
},
|
||||||
|
] as const
|
||||||
|
const capSelectionOptions = [
|
||||||
|
{
|
||||||
|
title: 'select cap segment',
|
||||||
|
selectClick: scene.makeMouseHelpers(688, 91)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select cap solid 2d',
|
||||||
|
selectClick: scene.makeMouseHelpers(733, 204)[0],
|
||||||
|
},
|
||||||
|
// TODO keeps failing
|
||||||
|
// {
|
||||||
|
// title: 'select cap circle',
|
||||||
|
// selectClick: scene.makeMouseHelpers(679, 290)[0],
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: 'select cap extrude wall',
|
||||||
|
selectClick: scene.makeMouseHelpers(649, 402)[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'select cap extrude cap',
|
||||||
|
selectClick: scene.makeMouseHelpers(693, 408)[0],
|
||||||
|
},
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const verifyWallProfilesAreDrawn = async () =>
|
||||||
|
test2.step('verify wall profiles are drawn', async () => {
|
||||||
|
// open polygon
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 599, y: 168 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// closed polygon
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 656, y: 171 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// revolved profile
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 655, y: 264 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// extruded profile
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 808, y: 396 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// circle
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
[
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
|
||||||
|
],
|
||||||
|
{ x: 742, y: 386 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const verifyCapProfilesAreDrawn = async () =>
|
||||||
|
test2.step('verify wall profiles are drawn', async () => {
|
||||||
|
// open polygon
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
// TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
|
||||||
|
{ x: 620, y: 58 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// revolved profile
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 641, y: 110 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// closed polygon
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 632, y: 200 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// extruded profile
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
{ x: 628, y: 410 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
// circle
|
||||||
|
await scene.expectPixelColor(
|
||||||
|
[
|
||||||
|
TEST_COLORS.WHITE,
|
||||||
|
TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
|
||||||
|
],
|
||||||
|
{ x: 681, y: 303 },
|
||||||
|
15
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
await test2.step('select wall profiles', async () => {
|
||||||
|
for (const { title, selectClick } of wallSelectionOptions) {
|
||||||
|
await test2.step(title, async () => {
|
||||||
|
await camPositionForSelectingSketchOnWallProfiles()
|
||||||
|
await selectClick()
|
||||||
|
await toolbar.editSketch()
|
||||||
|
await app.page.waitForTimeout(600)
|
||||||
|
await verifyWallProfilesAreDrawn()
|
||||||
|
await toolbar.exitSketchBtn.click()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await test2.step('select cap profiles', async () => {
|
||||||
|
for (const { title, selectClick } of capSelectionOptions) {
|
||||||
|
await test2.step(title, async () => {
|
||||||
|
await camPositionForSelectingSketchOnCapProfiles()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
await selectClick()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
await toolbar.editSketch()
|
||||||
|
await app.page.waitForTimeout(600)
|
||||||
|
await verifyCapProfilesAreDrawn()
|
||||||
|
await toolbar.exitSketchBtn.click()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
test2(
|
||||||
|
'Can enter sketch loft edges, base and continue sketch',
|
||||||
|
async ({ app, scene, toolbar, editor }) => {
|
||||||
|
await app.initialise(`sketch001 = startSketchOn('XZ')
|
||||||
|
profile001 = startProfileAt([34, 42.66], sketch001)
|
||||||
|
|> line([102.65, 151.99], %)
|
||||||
|
|> line([76, -138.66], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
plane001 = offsetPlane('XZ', 50)
|
||||||
|
sketch002 = startSketchOn(plane001)
|
||||||
|
profile002 = startProfileAt([39.43, 172.21], sketch002)
|
||||||
|
|> xLine(183.99, %)
|
||||||
|
|> line([-77.95, -145.93], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
|
||||||
|
loft([profile001, profile002])
|
||||||
|
`)
|
||||||
|
const [baseProfileEdgeClick] = scene.makeMouseHelpers(621, 292)
|
||||||
|
|
||||||
|
const [rect1Crn1] = scene.makeMouseHelpers(592, 283)
|
||||||
|
const [rect1Crn2] = scene.makeMouseHelpers(797, 268)
|
||||||
|
|
||||||
|
await baseProfileEdgeClick()
|
||||||
|
await toolbar.editSketch()
|
||||||
|
await app.page.waitForTimeout(600)
|
||||||
|
await scene.expectPixelColor(TEST_COLORS.WHITE, { x: 562, y: 172 }, 15)
|
||||||
|
|
||||||
|
await toolbar.rectangleBtn.click()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
await rect1Crn1()
|
||||||
|
await editor.expectEditor.toContain(
|
||||||
|
`profile003 = startProfileAt([50.72, -18.19], sketch001)`
|
||||||
|
)
|
||||||
|
await rect1Crn2()
|
||||||
|
await editor.expectEditor.toContain(
|
||||||
|
`angledLine([0, 113.01], %, $rectangleSegmentA001)`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
test2(
|
||||||
|
'Can enter sketch loft edges offsetPlane and continue sketch',
|
||||||
|
async ({ app, scene, toolbar, editor }) => {
|
||||||
|
await app.initialise(`sketch001 = startSketchOn('XZ')
|
||||||
|
profile001 = startProfileAt([34, 42.66], sketch001)
|
||||||
|
|> line([102.65, 151.99], %)
|
||||||
|
|> line([76, -138.66], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
plane001 = offsetPlane('XZ', 50)
|
||||||
|
sketch002 = startSketchOn(plane001)
|
||||||
|
profile002 = startProfileAt([39.43, 172.21], sketch002)
|
||||||
|
|> xLine(183.99, %)
|
||||||
|
|> line([-77.95, -145.93], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
|
||||||
|
loft([profile001, profile002])
|
||||||
|
`)
|
||||||
|
const topProfileEdgeClickCoords = { x: 602, y: 185 } as const
|
||||||
|
const [topProfileEdgeClick] = scene.makeMouseHelpers(
|
||||||
|
topProfileEdgeClickCoords.x,
|
||||||
|
topProfileEdgeClickCoords.y
|
||||||
|
)
|
||||||
|
|
||||||
|
const [rect1Crn1] = scene.makeMouseHelpers(592, 283)
|
||||||
|
const [rect1Crn2] = scene.makeMouseHelpers(797, 268)
|
||||||
|
|
||||||
|
await scene.moveCameraTo(
|
||||||
|
{ x: 8171, y: -7740, z: 1624 },
|
||||||
|
{ x: 3302, y: -627, z: 2892 }
|
||||||
|
)
|
||||||
|
|
||||||
|
await topProfileEdgeClick()
|
||||||
|
await toolbar.editSketch()
|
||||||
|
await app.page.waitForTimeout(600)
|
||||||
|
await scene.expectPixelColor(TEST_COLORS.BLUE, { x: 788, y: 188 }, 15)
|
||||||
|
|
||||||
|
await toolbar.rectangleBtn.click()
|
||||||
|
await app.page.waitForTimeout(100)
|
||||||
|
await rect1Crn1()
|
||||||
|
await editor.expectEditor.toContain(
|
||||||
|
`profile003 = startProfileAt([47.76, -17.13], plane001)`
|
||||||
|
)
|
||||||
|
await rect1Crn2()
|
||||||
|
await editor.expectEditor.toContain(
|
||||||
|
`angledLine([0, 106.42], %, $rectangleSegmentA001)`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
@ -1776,8 +1776,7 @@ export class SceneEntities {
|
|||||||
structuredClone(pathToNode)
|
structuredClone(pathToNode)
|
||||||
nodePathWithCorrectedIndexForTruncatedAst[1][0] =
|
nodePathWithCorrectedIndexForTruncatedAst[1][0] =
|
||||||
Number(nodePathWithCorrectedIndexForTruncatedAst[1][0]) -
|
Number(nodePathWithCorrectedIndexForTruncatedAst[1][0]) -
|
||||||
Number(planeNodePath[1][0]) -
|
Number(sketchNodePaths[0][1][0])
|
||||||
1
|
|
||||||
|
|
||||||
const _node = getNodeFromPath<Node<CallExpression>>(
|
const _node = getNodeFromPath<Node<CallExpression>>(
|
||||||
modifiedAst,
|
modifiedAst,
|
||||||
|
@ -2,7 +2,12 @@ import { SVGProps } from 'react'
|
|||||||
|
|
||||||
export const Spinner = (props: SVGProps<SVGSVGElement>) => {
|
export const Spinner = (props: SVGProps<SVGSVGElement>) => {
|
||||||
return (
|
return (
|
||||||
<svg viewBox="0 0 10 10" className={'w-8 h-8'} {...props}>
|
<svg
|
||||||
|
data-testid="spinner"
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
className={'w-8 h-8'}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
<circle
|
<circle
|
||||||
cx="5"
|
cx="5"
|
||||||
cy="5"
|
cy="5"
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
PathToNode,
|
PathToNode,
|
||||||
Expr,
|
Expr,
|
||||||
CallExpression,
|
CallExpression,
|
||||||
PipeExpression,
|
|
||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
} from 'lang/wasm'
|
} from 'lang/wasm'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
@ -15,7 +14,6 @@ import {
|
|||||||
createCallExpressionStdLib,
|
createCallExpressionStdLib,
|
||||||
createObjectExpression,
|
createObjectExpression,
|
||||||
createIdentifier,
|
createIdentifier,
|
||||||
createPipeExpression,
|
|
||||||
findUniqueName,
|
findUniqueName,
|
||||||
createVariableDeclaration,
|
createVariableDeclaration,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
@ -24,12 +22,13 @@ import {
|
|||||||
mutateAstWithTagForSketchSegment,
|
mutateAstWithTagForSketchSegment,
|
||||||
getEdgeTagCall,
|
getEdgeTagCall,
|
||||||
} from 'lang/modifyAst/addEdgeTreatment'
|
} from 'lang/modifyAst/addEdgeTreatment'
|
||||||
|
import { Artifact, getPathsFromArtifact } from 'lang/std/artifactGraph'
|
||||||
export function revolveSketch(
|
export function revolveSketch(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
pathToSketchNode: PathToNode,
|
pathToSketchNode: PathToNode,
|
||||||
shouldPipe = false,
|
|
||||||
angle: Expr = createLiteral(4),
|
angle: Expr = createLiteral(4),
|
||||||
axis: Selections
|
axis: Selections,
|
||||||
|
artifact?: Artifact
|
||||||
):
|
):
|
||||||
| {
|
| {
|
||||||
modifiedAst: Node<Program>
|
modifiedAst: Node<Program>
|
||||||
@ -37,6 +36,11 @@ export function revolveSketch(
|
|||||||
pathToRevolveArg: PathToNode
|
pathToRevolveArg: PathToNode
|
||||||
}
|
}
|
||||||
| Error {
|
| Error {
|
||||||
|
const orderedSketchNodePaths = getPathsFromArtifact({
|
||||||
|
artifact: artifact,
|
||||||
|
sketchPathToNode: pathToSketchNode,
|
||||||
|
})
|
||||||
|
if (err(orderedSketchNodePaths)) return orderedSketchNodePaths
|
||||||
const clonedAst = structuredClone(ast)
|
const clonedAst = structuredClone(ast)
|
||||||
const sketchNode = getNodeFromPath(clonedAst, pathToSketchNode)
|
const sketchNode = getNodeFromPath(clonedAst, pathToSketchNode)
|
||||||
if (err(sketchNode)) return sketchNode
|
if (err(sketchNode)) return sketchNode
|
||||||
@ -67,29 +71,13 @@ export function revolveSketch(
|
|||||||
if (err(tagResult)) return tagResult
|
if (err(tagResult)) return tagResult
|
||||||
const { tag } = tagResult
|
const { tag } = tagResult
|
||||||
|
|
||||||
/* Original Code */
|
|
||||||
const { node: sketchExpression } = sketchNode
|
|
||||||
|
|
||||||
// determine if sketchExpression is in a pipeExpression or not
|
|
||||||
const sketchPipeExpressionNode = getNodeFromPath<PipeExpression>(
|
|
||||||
clonedAst,
|
|
||||||
pathToSketchNode,
|
|
||||||
'PipeExpression'
|
|
||||||
)
|
|
||||||
if (err(sketchPipeExpressionNode)) return sketchPipeExpressionNode
|
|
||||||
const { node: sketchPipeExpression } = sketchPipeExpressionNode
|
|
||||||
const isInPipeExpression = sketchPipeExpression.type === 'PipeExpression'
|
|
||||||
|
|
||||||
const sketchVariableDeclaratorNode = getNodeFromPath<VariableDeclarator>(
|
const sketchVariableDeclaratorNode = getNodeFromPath<VariableDeclarator>(
|
||||||
clonedAst,
|
clonedAst,
|
||||||
pathToSketchNode,
|
pathToSketchNode,
|
||||||
'VariableDeclarator'
|
'VariableDeclarator'
|
||||||
)
|
)
|
||||||
if (err(sketchVariableDeclaratorNode)) return sketchVariableDeclaratorNode
|
if (err(sketchVariableDeclaratorNode)) return sketchVariableDeclaratorNode
|
||||||
const {
|
const { node: sketchVariableDeclarator } = sketchVariableDeclaratorNode
|
||||||
node: sketchVariableDeclarator,
|
|
||||||
shallowPath: sketchPathToDecleration,
|
|
||||||
} = sketchVariableDeclaratorNode
|
|
||||||
|
|
||||||
const axisSelection = axis?.graphSelections[0]?.artifact
|
const axisSelection = axis?.graphSelections[0]?.artifact
|
||||||
|
|
||||||
@ -103,37 +91,13 @@ export function revolveSketch(
|
|||||||
createIdentifier(sketchVariableDeclarator.id.name),
|
createIdentifier(sketchVariableDeclarator.id.name),
|
||||||
])
|
])
|
||||||
|
|
||||||
if (shouldPipe) {
|
|
||||||
const pipeChain = createPipeExpression(
|
|
||||||
isInPipeExpression
|
|
||||||
? [...sketchPipeExpression.body, revolveCall]
|
|
||||||
: [sketchExpression as any, revolveCall]
|
|
||||||
)
|
|
||||||
|
|
||||||
sketchVariableDeclarator.init = pipeChain
|
|
||||||
const pathToRevolveArg: PathToNode = [
|
|
||||||
...sketchPathToDecleration,
|
|
||||||
['init', 'VariableDeclarator'],
|
|
||||||
['body', ''],
|
|
||||||
[pipeChain.body.length - 1, 'index'],
|
|
||||||
['arguments', 'CallExpression'],
|
|
||||||
[0, 'index'],
|
|
||||||
]
|
|
||||||
|
|
||||||
return {
|
|
||||||
modifiedAst: clonedAst,
|
|
||||||
pathToSketchNode,
|
|
||||||
pathToRevolveArg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not creating a pipe expression,
|
// We're not creating a pipe expression,
|
||||||
// but rather a separate constant for the extrusion
|
// but rather a separate constant for the extrusion
|
||||||
const name = findUniqueName(clonedAst, KCL_DEFAULT_CONSTANT_PREFIXES.REVOLVE)
|
const name = findUniqueName(clonedAst, KCL_DEFAULT_CONSTANT_PREFIXES.REVOLVE)
|
||||||
const VariableDeclaration = createVariableDeclaration(name, revolveCall)
|
const VariableDeclaration = createVariableDeclaration(name, revolveCall)
|
||||||
const sketchIndexInPathToNode =
|
const lastSketchNodePath =
|
||||||
sketchPathToDecleration.findIndex((a) => a[0] === 'body') + 1
|
orderedSketchNodePaths[orderedSketchNodePaths.length - 1]
|
||||||
const sketchIndexInBody = sketchPathToDecleration[sketchIndexInPathToNode][0]
|
const sketchIndexInBody = Number(lastSketchNodePath[1][0])
|
||||||
if (typeof sketchIndexInBody !== 'number')
|
if (typeof sketchIndexInBody !== 'number')
|
||||||
return new Error('expected sketchIndexInBody to be a number')
|
return new Error('expected sketchIndexInBody to be a number')
|
||||||
clonedAst.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
|
clonedAst.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
|
||||||
|
@ -212,19 +212,7 @@ Map {
|
|||||||
"type": "wall",
|
"type": "wall",
|
||||||
},
|
},
|
||||||
"UUID-10" => {
|
"UUID-10" => {
|
||||||
"codeRef": {
|
"codeRef": undefined,
|
||||||
"pathToNode": [
|
|
||||||
[
|
|
||||||
"body",
|
|
||||||
"",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
"range": [
|
|
||||||
501,
|
|
||||||
522,
|
|
||||||
true,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"edgeCutEdgeIds": [],
|
"edgeCutEdgeIds": [],
|
||||||
"id": "UUID",
|
"id": "UUID",
|
||||||
"pathIds": [
|
"pathIds": [
|
||||||
|
@ -22,6 +22,7 @@ import * as d3 from 'd3-force'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import pixelmatch from 'pixelmatch'
|
import pixelmatch from 'pixelmatch'
|
||||||
import { PNG } from 'pngjs'
|
import { PNG } from 'pngjs'
|
||||||
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note this is an integration test, these tests connect to our real dev server and make websocket commands.
|
Note this is an integration test, these tests connect to our real dev server and make websocket commands.
|
||||||
@ -171,7 +172,7 @@ afterAll(() => {
|
|||||||
|
|
||||||
describe('testing createArtifactGraph', () => {
|
describe('testing createArtifactGraph', () => {
|
||||||
describe('code with offset planes and a sketch:', () => {
|
describe('code with offset planes and a sketch:', () => {
|
||||||
let ast: Program
|
let ast: Node<Program>
|
||||||
let theMap: ReturnType<typeof createArtifactGraph>
|
let theMap: ReturnType<typeof createArtifactGraph>
|
||||||
|
|
||||||
it('setup', () => {
|
it('setup', () => {
|
||||||
@ -217,7 +218,7 @@ describe('testing createArtifactGraph', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('code with an extrusion, fillet and sketch of face:', () => {
|
describe('code with an extrusion, fillet and sketch of face:', () => {
|
||||||
let ast: Program
|
let ast: Node<Program>
|
||||||
let theMap: ReturnType<typeof createArtifactGraph>
|
let theMap: ReturnType<typeof createArtifactGraph>
|
||||||
it('setup', () => {
|
it('setup', () => {
|
||||||
// putting this logic in here because describe blocks runs before beforeAll has finished
|
// putting this logic in here because describe blocks runs before beforeAll has finished
|
||||||
@ -312,7 +313,7 @@ describe('testing createArtifactGraph', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe(`code with sketches but no extrusions or other 3D elements`, () => {
|
describe(`code with sketches but no extrusions or other 3D elements`, () => {
|
||||||
let ast: Program
|
let ast: Node<Program>
|
||||||
let theMap: ReturnType<typeof createArtifactGraph>
|
let theMap: ReturnType<typeof createArtifactGraph>
|
||||||
it(`setup`, () => {
|
it(`setup`, () => {
|
||||||
// putting this logic in here because describe blocks runs before beforeAll has finished
|
// putting this logic in here because describe blocks runs before beforeAll has finished
|
||||||
@ -377,7 +378,7 @@ describe('testing createArtifactGraph', () => {
|
|||||||
|
|
||||||
describe('capture graph of sketchOnFaceOnFace...', () => {
|
describe('capture graph of sketchOnFaceOnFace...', () => {
|
||||||
describe('code with an extrusion, fillet and sketch of face:', () => {
|
describe('code with an extrusion, fillet and sketch of face:', () => {
|
||||||
let ast: Program
|
let ast: Node<Program>
|
||||||
let theMap: ReturnType<typeof createArtifactGraph>
|
let theMap: ReturnType<typeof createArtifactGraph>
|
||||||
it('setup', async () => {
|
it('setup', async () => {
|
||||||
// putting this logic in here because describe blocks runs before beforeAll has finished
|
// putting this logic in here because describe blocks runs before beforeAll has finished
|
||||||
@ -399,7 +400,9 @@ describe('capture graph of sketchOnFaceOnFace...', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function getCommands(codeKey: CodeKey): CacheShape[CodeKey] & { ast: Program } {
|
function getCommands(
|
||||||
|
codeKey: CodeKey
|
||||||
|
): CacheShape[CodeKey] & { ast: Node<Program> } {
|
||||||
const ast = assertParse(codeKey)
|
const ast = assertParse(codeKey)
|
||||||
const file = fs.readFileSync(fullPath, 'utf-8')
|
const file = fs.readFileSync(fullPath, 'utf-8')
|
||||||
const parsed: CacheShape = JSON.parse(file)
|
const parsed: CacheShape = JSON.parse(file)
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
import { Expr, PathToNode, Program, SourceRange } from 'lang/wasm'
|
import {
|
||||||
|
Expr,
|
||||||
|
PathToNode,
|
||||||
|
Program,
|
||||||
|
SourceRange,
|
||||||
|
VariableDeclaration,
|
||||||
|
} from 'lang/wasm'
|
||||||
import { Models } from '@kittycad/lib'
|
import { Models } from '@kittycad/lib'
|
||||||
import { getNodePathFromSourceRange } from 'lang/queryAst'
|
import {
|
||||||
|
getNodeFromPath,
|
||||||
|
getNodePathFromSourceRange,
|
||||||
|
traverse,
|
||||||
|
} from 'lang/queryAst'
|
||||||
import { err } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
export type ArtifactId = string
|
export type ArtifactId = string
|
||||||
|
|
||||||
@ -42,7 +53,7 @@ interface Solid2DArtifact extends BaseArtifact {
|
|||||||
export interface PathArtifactRich extends BaseArtifact {
|
export interface PathArtifactRich extends BaseArtifact {
|
||||||
type: 'path'
|
type: 'path'
|
||||||
/** A path must always lie on a plane */
|
/** A path must always lie on a plane */
|
||||||
plane: PlaneArtifact | WallArtifact
|
plane: PlaneArtifact | WallArtifact | CapArtifact
|
||||||
/** A path must always contain 0 or more segments */
|
/** A path must always contain 0 or more segments */
|
||||||
segments: Array<SegmentArtifact>
|
segments: Array<SegmentArtifact>
|
||||||
/** A path may not result in a sweep artifact */
|
/** A path may not result in a sweep artifact */
|
||||||
@ -101,6 +112,9 @@ interface CapArtifact extends BaseArtifact {
|
|||||||
edgeCutEdgeIds: Array<ArtifactId>
|
edgeCutEdgeIds: Array<ArtifactId>
|
||||||
sweepId: ArtifactId
|
sweepId: ArtifactId
|
||||||
pathIds: Array<ArtifactId>
|
pathIds: Array<ArtifactId>
|
||||||
|
// codeRef is for the sketchOnFace plane, not for the wall itself
|
||||||
|
// traverse to the extrude and or segment to get the wall's codeRef
|
||||||
|
codeRef?: CodeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SweepEdgeArtifact extends BaseArtifact {
|
interface SweepEdgeArtifact extends BaseArtifact {
|
||||||
@ -163,7 +177,7 @@ export function createArtifactGraph({
|
|||||||
}: {
|
}: {
|
||||||
orderedCommands: Array<OrderedCommand>
|
orderedCommands: Array<OrderedCommand>
|
||||||
responseMap: ResponseMap
|
responseMap: ResponseMap
|
||||||
ast: Program
|
ast: Node<Program>
|
||||||
}) {
|
}) {
|
||||||
const myMap = new Map<ArtifactId, Artifact>()
|
const myMap = new Map<ArtifactId, Artifact>()
|
||||||
|
|
||||||
@ -242,7 +256,7 @@ export function getArtifactsToUpdate({
|
|||||||
/** Passing in a getter because we don't wan this function to update the map directly */
|
/** Passing in a getter because we don't wan this function to update the map directly */
|
||||||
getArtifact: (id: ArtifactId) => Artifact | undefined
|
getArtifact: (id: ArtifactId) => Artifact | undefined
|
||||||
currentPlaneId: ArtifactId
|
currentPlaneId: ArtifactId
|
||||||
ast: Program
|
ast: Node<Program>
|
||||||
}): Array<{
|
}): Array<{
|
||||||
id: ArtifactId
|
id: ArtifactId
|
||||||
artifact: Artifact
|
artifact: Artifact
|
||||||
@ -278,6 +292,13 @@ export function getArtifactsToUpdate({
|
|||||||
plane?.type === 'plane' ? plane?.codeRef : { range, pathToNode }
|
plane?.type === 'plane' ? plane?.codeRef : { range, pathToNode }
|
||||||
const existingPlane = getArtifact(currentPlaneId)
|
const existingPlane = getArtifact(currentPlaneId)
|
||||||
if (existingPlane?.type === 'wall') {
|
if (existingPlane?.type === 'wall') {
|
||||||
|
let existingPlaneCodeRef = existingPlane.codeRef
|
||||||
|
if (!existingPlaneCodeRef) {
|
||||||
|
const astWalkCodeRef = getWallOrCapPlaneCodeRef(ast, codeRef.pathToNode)
|
||||||
|
if (!err(astWalkCodeRef)) {
|
||||||
|
existingPlaneCodeRef = astWalkCodeRef
|
||||||
|
}
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: currentPlaneId,
|
id: currentPlaneId,
|
||||||
@ -288,7 +309,29 @@ export function getArtifactsToUpdate({
|
|||||||
edgeCutEdgeIds: existingPlane.edgeCutEdgeIds,
|
edgeCutEdgeIds: existingPlane.edgeCutEdgeIds,
|
||||||
sweepId: existingPlane.sweepId,
|
sweepId: existingPlane.sweepId,
|
||||||
pathIds: existingPlane.pathIds,
|
pathIds: existingPlane.pathIds,
|
||||||
codeRef,
|
codeRef: existingPlaneCodeRef,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else if (existingPlane?.type === 'cap') {
|
||||||
|
let existingPlaneCodeRef = existingPlane.codeRef
|
||||||
|
if (!existingPlaneCodeRef) {
|
||||||
|
const astWalkCodeRef = getWallOrCapPlaneCodeRef(ast, codeRef.pathToNode)
|
||||||
|
if (!err(astWalkCodeRef)) {
|
||||||
|
existingPlaneCodeRef = astWalkCodeRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: currentPlaneId,
|
||||||
|
artifact: {
|
||||||
|
type: 'cap',
|
||||||
|
subType: existingPlane.subType,
|
||||||
|
id: currentPlaneId,
|
||||||
|
edgeCutEdgeIds: existingPlane.edgeCutEdgeIds,
|
||||||
|
sweepId: existingPlane.sweepId,
|
||||||
|
pathIds: existingPlane.pathIds,
|
||||||
|
codeRef: existingPlaneCodeRef,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -333,6 +376,18 @@ export function getArtifactsToUpdate({
|
|||||||
pathIds: [id],
|
pathIds: [id],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
} else if (plane?.type === 'cap') {
|
||||||
|
returnArr.push({
|
||||||
|
id: currentPlaneId,
|
||||||
|
artifact: {
|
||||||
|
type: 'cap',
|
||||||
|
id: currentPlaneId,
|
||||||
|
subType: plane.subType,
|
||||||
|
edgeCutEdgeIds: plane.edgeCutEdgeIds,
|
||||||
|
sweepId: plane.sweepId,
|
||||||
|
pathIds: [id],
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return returnArr
|
return returnArr
|
||||||
} else if (cmd.type === 'extend_path' || cmd.type === 'close_path') {
|
} else if (cmd.type === 'extend_path' || cmd.type === 'close_path') {
|
||||||
@ -880,9 +935,9 @@ export function codeRefFromRange(range: SourceRange, ast: Program): CodeRef {
|
|||||||
function getPlaneFromPath(
|
function getPlaneFromPath(
|
||||||
path: PathArtifact,
|
path: PathArtifact,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
const plane = getArtifactOfTypes(
|
const plane = getArtifactOfTypes(
|
||||||
{ key: path.planeId, types: ['plane', 'wall'] },
|
{ key: path.planeId, types: ['plane', 'wall', 'cap'] },
|
||||||
graph
|
graph
|
||||||
)
|
)
|
||||||
if (err(plane)) return plane
|
if (err(plane)) return plane
|
||||||
@ -892,7 +947,7 @@ function getPlaneFromPath(
|
|||||||
function getPlaneFromSegment(
|
function getPlaneFromSegment(
|
||||||
segment: SegmentArtifact,
|
segment: SegmentArtifact,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
const path = getArtifactOfTypes(
|
const path = getArtifactOfTypes(
|
||||||
{ key: segment.pathId, types: ['path'] },
|
{ key: segment.pathId, types: ['path'] },
|
||||||
graph
|
graph
|
||||||
@ -903,7 +958,7 @@ function getPlaneFromSegment(
|
|||||||
function getPlaneFromSolid2D(
|
function getPlaneFromSolid2D(
|
||||||
solid2D: Solid2DArtifact,
|
solid2D: Solid2DArtifact,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
const path = getArtifactOfTypes(
|
const path = getArtifactOfTypes(
|
||||||
{ key: solid2D.pathId, types: ['path'] },
|
{ key: solid2D.pathId, types: ['path'] },
|
||||||
graph
|
graph
|
||||||
@ -914,7 +969,7 @@ function getPlaneFromSolid2D(
|
|||||||
function getPlaneFromCap(
|
function getPlaneFromCap(
|
||||||
cap: CapArtifact,
|
cap: CapArtifact,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
const sweep = getArtifactOfTypes(
|
const sweep = getArtifactOfTypes(
|
||||||
{ key: cap.sweepId, types: ['sweep'] },
|
{ key: cap.sweepId, types: ['sweep'] },
|
||||||
graph
|
graph
|
||||||
@ -927,7 +982,7 @@ function getPlaneFromCap(
|
|||||||
function getPlaneFromWall(
|
function getPlaneFromWall(
|
||||||
wall: WallArtifact,
|
wall: WallArtifact,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
const sweep = getArtifactOfTypes(
|
const sweep = getArtifactOfTypes(
|
||||||
{ key: wall.sweepId, types: ['sweep'] },
|
{ key: wall.sweepId, types: ['sweep'] },
|
||||||
graph
|
graph
|
||||||
@ -951,7 +1006,7 @@ function getPlaneFromSweepEdge(edge: SweepEdgeArtifact, graph: ArtifactGraph) {
|
|||||||
export function getPlaneFromArtifact(
|
export function getPlaneFromArtifact(
|
||||||
artifact: Artifact | undefined,
|
artifact: Artifact | undefined,
|
||||||
graph: ArtifactGraph
|
graph: ArtifactGraph
|
||||||
): PlaneArtifact | WallArtifact | Error {
|
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||||
if (!artifact) return new Error(`Artifact is undefined`)
|
if (!artifact) return new Error(`Artifact is undefined`)
|
||||||
if (artifact.type === 'plane') return artifact
|
if (artifact.type === 'plane') return artifact
|
||||||
if (artifact.type === 'path') return getPlaneFromPath(artifact, graph)
|
if (artifact.type === 'path') return getPlaneFromPath(artifact, graph)
|
||||||
@ -1075,3 +1130,82 @@ function isNodeSafe(node: Expr): boolean {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@deprecated} this information should come from the ArtifactGraph not digging around in the AST */
|
||||||
|
function getWallOrCapPlaneCodeRef(
|
||||||
|
ast: Node<Program>,
|
||||||
|
pathToNode: PathToNode
|
||||||
|
): CodeRef | Error {
|
||||||
|
const varDec = getNodeFromPath<VariableDeclaration>(
|
||||||
|
ast,
|
||||||
|
pathToNode,
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (err(varDec)) return varDec
|
||||||
|
if (varDec.node.type !== 'VariableDeclaration')
|
||||||
|
return new Error('Expected VariableDeclaration')
|
||||||
|
const init = varDec.node.declaration.init
|
||||||
|
let varName = ''
|
||||||
|
if (
|
||||||
|
init.type === 'CallExpression' &&
|
||||||
|
init.callee.type === 'Identifier' &&
|
||||||
|
(init.callee.name === 'circle' || init.callee.name === 'startProfileAt')
|
||||||
|
) {
|
||||||
|
const secondArg = init.arguments[1]
|
||||||
|
if (secondArg.type === 'Identifier') {
|
||||||
|
varName = secondArg.name
|
||||||
|
}
|
||||||
|
} else if (init.type === 'PipeExpression') {
|
||||||
|
const firstExpr = init.body[0]
|
||||||
|
if (
|
||||||
|
firstExpr.type === 'CallExpression' &&
|
||||||
|
firstExpr.callee.type === 'Identifier' &&
|
||||||
|
firstExpr.callee.name === 'startProfileAt'
|
||||||
|
) {
|
||||||
|
const secondArg = firstExpr.arguments[1]
|
||||||
|
if (secondArg.type === 'Identifier') {
|
||||||
|
varName = secondArg.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (varName === '') return new Error('Could not find variable name')
|
||||||
|
|
||||||
|
let currentVariableName = ''
|
||||||
|
const planeCodeRef: Array<{
|
||||||
|
path: PathToNode
|
||||||
|
sketchName: string
|
||||||
|
range: SourceRange
|
||||||
|
}> = []
|
||||||
|
traverse(ast, {
|
||||||
|
leave: (node) => {
|
||||||
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
currentVariableName = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enter: (node, path) => {
|
||||||
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
currentVariableName = node.declaration.id.name
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
// match `${varName} = startSketchOn(...)`
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === 'startSketchOn' &&
|
||||||
|
node.arguments[0].type === 'Identifier' &&
|
||||||
|
currentVariableName === varName
|
||||||
|
) {
|
||||||
|
planeCodeRef.push({
|
||||||
|
path,
|
||||||
|
sketchName: currentVariableName,
|
||||||
|
range: [node.start, node.end, true],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!planeCodeRef.length)
|
||||||
|
return new Error('No paths found depending on extrude')
|
||||||
|
|
||||||
|
return {
|
||||||
|
pathToNode: planeCodeRef[0].path,
|
||||||
|
range: planeCodeRef[0].range,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 568 KiB After Width: | Height: | Size: 560 KiB |
@ -37,6 +37,7 @@ import { KclManager } from 'lang/KclSingleton'
|
|||||||
import { reportRejection } from 'lib/trap'
|
import { reportRejection } from 'lib/trap'
|
||||||
import { markOnce } from 'lib/performance'
|
import { markOnce } from 'lib/performance'
|
||||||
import { MachineManager } from 'components/MachineManagerProvider'
|
import { MachineManager } from 'components/MachineManagerProvider'
|
||||||
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
// TODO(paultag): This ought to be tweakable.
|
// TODO(paultag): This ought to be tweakable.
|
||||||
const pingIntervalMs = 5_000
|
const pingIntervalMs = 5_000
|
||||||
@ -2115,7 +2116,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
Object.values(this.pendingCommands).map((a) => a.promise)
|
Object.values(this.pendingCommands).map((a) => a.promise)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
updateArtifactGraph(ast: Program) {
|
updateArtifactGraph(ast: Node<Program>) {
|
||||||
this.artifactGraph = createArtifactGraph({
|
this.artifactGraph = createArtifactGraph({
|
||||||
orderedCommands: this.orderedCommands,
|
orderedCommands: this.orderedCommands,
|
||||||
responseMap: this.responseMap,
|
responseMap: this.responseMap,
|
||||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user