Revert multi-profile (#4812)
* Revert "multi-profile follow up. (#4802)" This reverts commit2b2ed470c1
. * Revert "multi profile (#4532)" This reverts commit04e586d07b
. * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * Re-run CI after snapshots * Re-run CI after snapshots * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Re-run CI after snapshots * Add `fixme` to onboarding test --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -1,19 +1,7 @@
|
||||
import {
|
||||
Expr,
|
||||
PathToNode,
|
||||
Program,
|
||||
SourceRange,
|
||||
VariableDeclaration,
|
||||
} from 'lang/wasm'
|
||||
import { PathToNode, Program, SourceRange } from 'lang/wasm'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import {
|
||||
getNodeFromPath,
|
||||
getNodePathFromSourceRange,
|
||||
traverse,
|
||||
} from 'lang/queryAst'
|
||||
import { getNodePathFromSourceRange } from 'lang/queryAst'
|
||||
import { err } from 'lib/trap'
|
||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||
|
||||
export type ArtifactId = string
|
||||
|
||||
@ -46,14 +34,14 @@ export interface PathArtifact extends BaseArtifact {
|
||||
codeRef: CodeRef
|
||||
}
|
||||
|
||||
interface Solid2DArtifact extends BaseArtifact {
|
||||
interface solid2D extends BaseArtifact {
|
||||
type: 'solid2D'
|
||||
pathId: ArtifactId
|
||||
}
|
||||
export interface PathArtifactRich extends BaseArtifact {
|
||||
type: 'path'
|
||||
/** A path must always lie on a plane */
|
||||
plane: PlaneArtifact | WallArtifact | CapArtifact
|
||||
plane: PlaneArtifact | WallArtifact
|
||||
/** A path must always contain 0 or more segments */
|
||||
segments: Array<SegmentArtifact>
|
||||
/** A path may not result in a sweep artifact */
|
||||
@ -73,7 +61,7 @@ interface SegmentArtifactRich extends BaseArtifact {
|
||||
type: 'segment'
|
||||
path: PathArtifact
|
||||
surf: WallArtifact
|
||||
edges: Array<SweepEdgeArtifact>
|
||||
edges: Array<SweepEdge>
|
||||
edgeCut?: EdgeCut
|
||||
codeRef: CodeRef
|
||||
}
|
||||
@ -92,7 +80,7 @@ interface SweepArtifactRich extends BaseArtifact {
|
||||
subType: 'extrusion' | 'revolve'
|
||||
path: PathArtifact
|
||||
surfaces: Array<WallArtifact | CapArtifact>
|
||||
edges: Array<SweepEdgeArtifact>
|
||||
edges: Array<SweepEdge>
|
||||
codeRef: CodeRef
|
||||
}
|
||||
|
||||
@ -102,9 +90,6 @@ interface WallArtifact extends BaseArtifact {
|
||||
edgeCutEdgeIds: Array<ArtifactId>
|
||||
sweepId: 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 CapArtifact extends BaseArtifact {
|
||||
type: 'cap'
|
||||
@ -112,12 +97,9 @@ interface CapArtifact extends BaseArtifact {
|
||||
edgeCutEdgeIds: Array<ArtifactId>
|
||||
sweepId: 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 SweepEdge extends BaseArtifact {
|
||||
type: 'sweepEdge'
|
||||
segId: ArtifactId
|
||||
sweepId: ArtifactId
|
||||
@ -147,10 +129,10 @@ export type Artifact =
|
||||
| SweepArtifact
|
||||
| WallArtifact
|
||||
| CapArtifact
|
||||
| SweepEdgeArtifact
|
||||
| SweepEdge
|
||||
| EdgeCut
|
||||
| EdgeCutEdge
|
||||
| Solid2DArtifact
|
||||
| solid2D
|
||||
|
||||
export type ArtifactGraph = Map<ArtifactId, Artifact>
|
||||
|
||||
@ -177,7 +159,7 @@ export function createArtifactGraph({
|
||||
}: {
|
||||
orderedCommands: Array<OrderedCommand>
|
||||
responseMap: ResponseMap
|
||||
ast: Node<Program>
|
||||
ast: Program
|
||||
}) {
|
||||
const myMap = new Map<ArtifactId, Artifact>()
|
||||
|
||||
@ -256,7 +238,7 @@ export function getArtifactsToUpdate({
|
||||
/** Passing in a getter because we don't wan this function to update the map directly */
|
||||
getArtifact: (id: ArtifactId) => Artifact | undefined
|
||||
currentPlaneId: ArtifactId
|
||||
ast: Node<Program>
|
||||
ast: Program
|
||||
}): Array<{
|
||||
id: ArtifactId
|
||||
artifact: Artifact
|
||||
@ -292,13 +274,6 @@ export function getArtifactsToUpdate({
|
||||
plane?.type === 'plane' ? plane?.codeRef : { range, pathToNode }
|
||||
const existingPlane = getArtifact(currentPlaneId)
|
||||
if (existingPlane?.type === 'wall') {
|
||||
let existingPlaneCodeRef = existingPlane.codeRef
|
||||
if (!existingPlaneCodeRef) {
|
||||
const astWalkCodeRef = getWallOrCapPlaneCodeRef(ast, codeRef.pathToNode)
|
||||
if (!err(astWalkCodeRef)) {
|
||||
existingPlaneCodeRef = astWalkCodeRef
|
||||
}
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: currentPlaneId,
|
||||
@ -309,29 +284,6 @@ export function getArtifactsToUpdate({
|
||||
edgeCutEdgeIds: existingPlane.edgeCutEdgeIds,
|
||||
sweepId: existingPlane.sweepId,
|
||||
pathIds: existingPlane.pathIds,
|
||||
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,
|
||||
},
|
||||
},
|
||||
]
|
||||
@ -376,18 +328,6 @@ export function getArtifactsToUpdate({
|
||||
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
|
||||
} else if (cmd.type === 'extend_path' || cmd.type === 'close_path') {
|
||||
@ -793,7 +733,7 @@ export function getCapCodeRef(
|
||||
}
|
||||
|
||||
export function getSolid2dCodeRef(
|
||||
solid2D: Solid2DArtifact,
|
||||
solid2D: solid2D,
|
||||
artifactGraph: ArtifactGraph
|
||||
): CodeRef | Error {
|
||||
const path = getArtifactOfTypes(
|
||||
@ -817,7 +757,7 @@ export function getWallCodeRef(
|
||||
}
|
||||
|
||||
export function getSweepEdgeCodeRef(
|
||||
edge: SweepEdgeArtifact,
|
||||
edge: SweepEdge,
|
||||
artifactGraph: ArtifactGraph
|
||||
): CodeRef | Error {
|
||||
const seg = getArtifactOfTypes(
|
||||
@ -931,281 +871,3 @@ export function codeRefFromRange(range: SourceRange, ast: Program): CodeRef {
|
||||
pathToNode: getNodePathFromSourceRange(ast, range),
|
||||
}
|
||||
}
|
||||
|
||||
function getPlaneFromPath(
|
||||
path: PathArtifact,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
const plane = getArtifactOfTypes(
|
||||
{ key: path.planeId, types: ['plane', 'wall', 'cap'] },
|
||||
graph
|
||||
)
|
||||
if (err(plane)) return plane
|
||||
return plane
|
||||
}
|
||||
|
||||
function getPlaneFromSegment(
|
||||
segment: SegmentArtifact,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
const path = getArtifactOfTypes(
|
||||
{ key: segment.pathId, types: ['path'] },
|
||||
graph
|
||||
)
|
||||
if (err(path)) return path
|
||||
return getPlaneFromPath(path, graph)
|
||||
}
|
||||
function getPlaneFromSolid2D(
|
||||
solid2D: Solid2DArtifact,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
const path = getArtifactOfTypes(
|
||||
{ key: solid2D.pathId, types: ['path'] },
|
||||
graph
|
||||
)
|
||||
if (err(path)) return path
|
||||
return getPlaneFromPath(path, graph)
|
||||
}
|
||||
function getPlaneFromCap(
|
||||
cap: CapArtifact,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
const sweep = getArtifactOfTypes(
|
||||
{ key: cap.sweepId, types: ['sweep'] },
|
||||
graph
|
||||
)
|
||||
if (err(sweep)) return sweep
|
||||
const path = getArtifactOfTypes({ key: sweep.pathId, types: ['path'] }, graph)
|
||||
if (err(path)) return path
|
||||
return getPlaneFromPath(path, graph)
|
||||
}
|
||||
function getPlaneFromWall(
|
||||
wall: WallArtifact,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
const sweep = getArtifactOfTypes(
|
||||
{ key: wall.sweepId, types: ['sweep'] },
|
||||
graph
|
||||
)
|
||||
if (err(sweep)) return sweep
|
||||
const path = getArtifactOfTypes({ key: sweep.pathId, types: ['path'] }, graph)
|
||||
if (err(path)) return path
|
||||
return getPlaneFromPath(path, graph)
|
||||
}
|
||||
function getPlaneFromSweepEdge(edge: SweepEdgeArtifact, graph: ArtifactGraph) {
|
||||
const sweep = getArtifactOfTypes(
|
||||
{ key: edge.sweepId, types: ['sweep'] },
|
||||
graph
|
||||
)
|
||||
if (err(sweep)) return sweep
|
||||
const path = getArtifactOfTypes({ key: sweep.pathId, types: ['path'] }, graph)
|
||||
if (err(path)) return path
|
||||
return getPlaneFromPath(path, graph)
|
||||
}
|
||||
|
||||
export function getPlaneFromArtifact(
|
||||
artifact: Artifact | undefined,
|
||||
graph: ArtifactGraph
|
||||
): PlaneArtifact | WallArtifact | CapArtifact | Error {
|
||||
if (!artifact) return new Error(`Artifact is undefined`)
|
||||
if (artifact.type === 'plane') return artifact
|
||||
if (artifact.type === 'path') return getPlaneFromPath(artifact, graph)
|
||||
if (artifact.type === 'segment') return getPlaneFromSegment(artifact, graph)
|
||||
if (artifact.type === 'solid2D') return getPlaneFromSolid2D(artifact, graph)
|
||||
if (artifact.type === 'cap') return getPlaneFromCap(artifact, graph)
|
||||
if (artifact.type === 'wall') return getPlaneFromWall(artifact, graph)
|
||||
if (artifact.type === 'sweepEdge')
|
||||
return getPlaneFromSweepEdge(artifact, graph)
|
||||
return new Error(`Artifact type ${artifact.type} does not have a plane`)
|
||||
}
|
||||
|
||||
const isExprSafe = (index: number): boolean => {
|
||||
const expr = kclManager.ast.body?.[index]
|
||||
if (!expr) {
|
||||
return false
|
||||
}
|
||||
if (expr.type === 'ImportStatement' || expr.type === 'ReturnStatement') {
|
||||
return false
|
||||
}
|
||||
if (expr.type === 'VariableDeclaration') {
|
||||
const init = expr.declaration?.init
|
||||
if (!init) return false
|
||||
if (init.type === 'CallExpression') {
|
||||
return false
|
||||
}
|
||||
if (init.type === 'BinaryExpression' && isNodeSafe(init)) {
|
||||
return true
|
||||
}
|
||||
if (init.type === 'Literal' || init.type === 'MemberExpression') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const onlyConsecutivePaths = (
|
||||
orderedNodePaths: PathToNode[],
|
||||
originalPath: PathToNode
|
||||
): PathToNode[] => {
|
||||
const originalIndex = Number(
|
||||
orderedNodePaths.find(
|
||||
(path) => path[1][0] === originalPath[1][0]
|
||||
)?.[1]?.[0] || 0
|
||||
)
|
||||
|
||||
const minIndex = Number(orderedNodePaths[0][1][0])
|
||||
const maxIndex = Number(orderedNodePaths[orderedNodePaths.length - 1][1][0])
|
||||
const pathIndexMap: any = {}
|
||||
orderedNodePaths.forEach((path) => {
|
||||
const bodyIndex = Number(path[1][0])
|
||||
pathIndexMap[bodyIndex] = path
|
||||
})
|
||||
const safePaths: PathToNode[] = []
|
||||
|
||||
// traverse expressions in either direction from the profile selected
|
||||
// when the user entered sketch mode
|
||||
for (let i = originalIndex; i <= maxIndex; i++) {
|
||||
if (pathIndexMap[i]) {
|
||||
safePaths.push(pathIndexMap[i])
|
||||
} else if (!isExprSafe(i)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
for (let i = originalIndex - 1; i >= minIndex; i--) {
|
||||
if (pathIndexMap[i]) {
|
||||
safePaths.unshift(pathIndexMap[i])
|
||||
} else if (!isExprSafe(i)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return safePaths
|
||||
}
|
||||
|
||||
export function getPathsFromPlaneArtifact(planeArtifact: PlaneArtifact) {
|
||||
const nodePaths: PathToNode[] = []
|
||||
for (const pathId of planeArtifact.pathIds) {
|
||||
const path = engineCommandManager.artifactGraph.get(pathId)
|
||||
if (!path) continue
|
||||
if ('codeRef' in path && path.codeRef) {
|
||||
// TODO should figure out why upstream the path is bad
|
||||
const isNodePathBad = path.codeRef.pathToNode.length < 2
|
||||
nodePaths.push(
|
||||
isNodePathBad
|
||||
? getNodePathFromSourceRange(kclManager.ast, path.codeRef.range)
|
||||
: path.codeRef.pathToNode
|
||||
)
|
||||
}
|
||||
}
|
||||
return onlyConsecutivePaths(nodePaths, nodePaths[0])
|
||||
}
|
||||
|
||||
export function getPathsFromArtifact({
|
||||
sketchPathToNode,
|
||||
artifact,
|
||||
}: {
|
||||
sketchPathToNode: PathToNode
|
||||
artifact?: Artifact
|
||||
}): PathToNode[] | Error {
|
||||
const plane = getPlaneFromArtifact(
|
||||
artifact,
|
||||
engineCommandManager.artifactGraph
|
||||
)
|
||||
if (err(plane)) return plane
|
||||
const paths = getArtifactsOfTypes(
|
||||
{ keys: plane.pathIds, types: ['path'] },
|
||||
engineCommandManager.artifactGraph
|
||||
)
|
||||
let nodePaths = [...paths.values()]
|
||||
.map((path) => path.codeRef.pathToNode)
|
||||
.sort((a, b) => Number(a[1][0]) - Number(b[1][0]))
|
||||
return onlyConsecutivePaths(nodePaths, sketchPathToNode)
|
||||
}
|
||||
|
||||
function isNodeSafe(node: Expr): boolean {
|
||||
if (node.type === 'Literal' || node.type === 'MemberExpression') {
|
||||
return true
|
||||
}
|
||||
if (node.type === 'BinaryExpression') {
|
||||
return isNodeSafe(node.left) && isNodeSafe(node.right)
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user