2024-09-09 18:17:45 -04:00
|
|
|
import { err, reportRejection, trap } from 'lib/trap'
|
2024-11-21 15:04:30 +11:00
|
|
|
import { Selection } from 'lib/selections'
|
2023-01-06 09:29:26 +11:00
|
|
|
import {
|
|
|
|
Program,
|
|
|
|
CallExpression,
|
|
|
|
PipeExpression,
|
|
|
|
VariableDeclaration,
|
2023-02-12 10:56:45 +11:00
|
|
|
VariableDeclarator,
|
2024-08-12 15:38:42 -05:00
|
|
|
Expr,
|
2023-02-12 10:56:45 +11:00
|
|
|
Literal,
|
2024-11-18 10:04:09 -05:00
|
|
|
LiteralValue,
|
2023-02-12 10:56:45 +11:00
|
|
|
PipeSubstitution,
|
|
|
|
Identifier,
|
|
|
|
ArrayExpression,
|
|
|
|
ObjectExpression,
|
2023-03-02 21:19:11 +11:00
|
|
|
UnaryExpression,
|
|
|
|
BinaryExpression,
|
2023-09-29 11:11:01 -07:00
|
|
|
PathToNode,
|
|
|
|
ProgramMemory,
|
2024-05-24 20:54:42 +10:00
|
|
|
SourceRange,
|
2024-09-27 15:44:44 -07:00
|
|
|
sketchFromKclValue,
|
2024-11-18 16:25:25 -05:00
|
|
|
isPathToNodeNumber,
|
2023-09-29 11:11:01 -07:00
|
|
|
} from './wasm'
|
2023-04-01 16:47:00 +11:00
|
|
|
import {
|
2024-05-24 20:54:42 +10:00
|
|
|
isNodeSafeToReplacePath,
|
2023-04-01 16:47:00 +11:00
|
|
|
findAllPreviousVariables,
|
2024-05-24 20:54:42 +10:00
|
|
|
findAllPreviousVariablesPath,
|
2023-04-01 16:47:00 +11:00
|
|
|
getNodeFromPath,
|
|
|
|
getNodePathFromSourceRange,
|
|
|
|
isNodeSafeToReplace,
|
2024-06-29 10:36:04 -07:00
|
|
|
traverse,
|
2023-04-01 16:47:00 +11:00
|
|
|
} from './queryAst'
|
2024-05-24 20:54:42 +10:00
|
|
|
import { addTagForSketchOnFace, getConstraintInfo } from './std/sketch'
|
|
|
|
import {
|
|
|
|
PathToNodeMap,
|
|
|
|
isLiteralArrayOrStatic,
|
|
|
|
removeSingleConstraint,
|
|
|
|
transformAstSketchLines,
|
|
|
|
} from './std/sketchcombos'
|
2024-02-14 08:03:20 +11:00
|
|
|
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
2024-05-24 20:54:42 +10:00
|
|
|
import { isOverlap, roundOff } from 'lib/utils'
|
2024-06-04 13:57:01 -04:00
|
|
|
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
2024-09-13 21:14:14 +10:00
|
|
|
import { SimplifiedArgDetails } from './std/stdTypes'
|
2024-06-24 22:39:04 -07:00
|
|
|
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
2024-06-29 10:36:04 -07:00
|
|
|
import { Models } from '@kittycad/lib'
|
2024-09-26 18:25:05 +10:00
|
|
|
import { ExtrudeFacePlane } from 'machines/modelingMachine'
|
2024-10-30 16:52:17 -04:00
|
|
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
2024-12-09 16:43:58 -05:00
|
|
|
import { KclExpressionWithVariable } from 'lib/commandTypes'
|
2023-01-06 09:29:26 +11:00
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
export function startSketchOnDefault(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2024-02-11 12:59:00 +11:00
|
|
|
axis: DefaultPlaneStr,
|
|
|
|
name = ''
|
2024-10-30 16:52:17 -04:00
|
|
|
): { modifiedAst: Node<Program>; id: string; pathToNode: PathToNode } {
|
2023-09-13 08:36:47 +10:00
|
|
|
const _node = { ...node }
|
2024-06-04 13:57:01 -04:00
|
|
|
const _name =
|
|
|
|
name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH)
|
2023-09-13 08:36:47 +10:00
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
2024-02-11 12:59:00 +11:00
|
|
|
createLiteral(axis),
|
2023-09-13 08:36:47 +10:00
|
|
|
])
|
|
|
|
|
2024-02-11 12:59:00 +11:00
|
|
|
const variableDeclaration = createVariableDeclaration(_name, startSketchOn)
|
2023-09-13 08:36:47 +10:00
|
|
|
_node.body = [...node.body, variableDeclaration]
|
2024-02-11 12:59:00 +11:00
|
|
|
const sketchIndex = _node.body.length - 1
|
2023-09-13 08:36:47 +10:00
|
|
|
|
|
|
|
let pathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
2024-02-11 12:59:00 +11:00
|
|
|
[sketchIndex, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2023-09-13 08:36:47 +10:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
id: _name,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-16 10:34:11 -05:00
|
|
|
export function addStartProfileAt(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2024-12-16 10:34:11 -05:00
|
|
|
pathToNode: PathToNode,
|
|
|
|
at: [number, number]
|
|
|
|
): { modifiedAst: Node<Program>; pathToNode: PathToNode } | Error {
|
|
|
|
const _node1 = getNodeFromPath<VariableDeclaration>(
|
2024-02-11 12:59:00 +11:00
|
|
|
node,
|
2024-12-16 10:34:11 -05:00
|
|
|
pathToNode,
|
|
|
|
'VariableDeclaration'
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
2024-12-16 10:34:11 -05:00
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const variableDeclaration = _node1.node
|
|
|
|
if (variableDeclaration.type !== 'VariableDeclaration') {
|
|
|
|
return new Error('variableDeclaration.init.type !== PipeExpression')
|
|
|
|
}
|
|
|
|
const _node = { ...node }
|
|
|
|
const init = variableDeclaration.declaration.init
|
|
|
|
const startProfileAt = createCallExpressionStdLib('startProfileAt', [
|
|
|
|
createArrayExpression([
|
|
|
|
createLiteral(roundOff(at[0])),
|
|
|
|
createLiteral(roundOff(at[1])),
|
|
|
|
]),
|
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
|
|
|
if (init.type === 'PipeExpression') {
|
|
|
|
init.body.splice(1, 0, startProfileAt)
|
|
|
|
} else {
|
|
|
|
variableDeclaration.declaration.init = createPipeExpression([
|
|
|
|
init,
|
|
|
|
startProfileAt,
|
2024-02-11 12:59:00 +11:00
|
|
|
])
|
2024-12-16 10:34:11 -05:00
|
|
|
}
|
2024-02-11 12:59:00 +11:00
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
2024-12-16 10:34:11 -05:00
|
|
|
pathToNode,
|
2024-02-11 12:59:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-06 09:29:26 +11:00
|
|
|
export function addSketchTo(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2023-01-06 09:29:26 +11:00
|
|
|
axis: 'xy' | 'xz' | 'yz',
|
|
|
|
name = ''
|
2023-04-01 16:47:00 +11:00
|
|
|
): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
|
2023-01-06 09:29:26 +11:00
|
|
|
const _node = { ...node }
|
2024-06-04 13:57:01 -04:00
|
|
|
const _name =
|
|
|
|
name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH)
|
2023-01-06 09:29:26 +11:00
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
const startSketchOn = createCallExpressionStdLib('startSketchOn', [
|
|
|
|
createLiteral(axis.toUpperCase()),
|
2023-02-12 10:56:45 +11:00
|
|
|
])
|
2023-10-05 14:27:48 -07:00
|
|
|
const startProfileAt = createCallExpressionStdLib('startProfileAt', [
|
|
|
|
createLiteral('default'),
|
2023-02-12 10:56:45 +11:00
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-09-05 16:02:27 -07:00
|
|
|
const initialLineTo = createCallExpressionStdLib('line', [
|
2023-03-17 15:53:20 +11:00
|
|
|
createLiteral('default'),
|
2023-02-12 10:56:45 +11:00
|
|
|
createPipeSubstitution(),
|
|
|
|
])
|
2023-01-06 09:29:26 +11:00
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
const pipeBody = [startSketchOn, startProfileAt, initialLineTo]
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
const variableDeclaration = createVariableDeclaration(
|
|
|
|
_name,
|
|
|
|
createPipeExpression(pipeBody)
|
|
|
|
)
|
2023-01-06 09:29:26 +11:00
|
|
|
|
2024-03-01 17:16:18 -08:00
|
|
|
_node.body = [...node.body, variableDeclaration]
|
|
|
|
let sketchIndex = _node.body.length - 1
|
2023-04-01 16:47:00 +11:00
|
|
|
let pathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[sketchIndex, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2023-04-01 16:47:00 +11:00
|
|
|
['init', 'VariableDeclarator'],
|
2023-01-06 09:29:26 +11:00
|
|
|
]
|
|
|
|
if (axis !== 'xy') {
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode = [...pathToNode, ['body', ''], ['0', 'index']]
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2024-03-01 17:16:18 -08:00
|
|
|
modifiedAst: _node,
|
2023-01-06 09:29:26 +11:00
|
|
|
id: _name,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export function findUniqueName(
|
2023-01-06 09:29:26 +11:00
|
|
|
ast: Program | string,
|
|
|
|
name: string,
|
2023-01-09 13:19:14 +11:00
|
|
|
pad = 3,
|
2023-01-06 09:29:26 +11:00
|
|
|
index = 1
|
|
|
|
): string {
|
2024-02-23 11:24:22 -05:00
|
|
|
let searchStr: string = typeof ast === 'string' ? ast : JSON.stringify(ast)
|
|
|
|
const indexStr = String(index).padStart(pad, '0')
|
|
|
|
|
|
|
|
const endingDigitsMatcher = /\d+$/
|
|
|
|
const nameEndsInDigits = name.match(endingDigitsMatcher)
|
|
|
|
let nameIsInString = searchStr.includes(`:"${name}"`)
|
|
|
|
|
|
|
|
if (nameEndsInDigits !== null) {
|
|
|
|
// base case: name is unique and ends in digits
|
|
|
|
if (!nameIsInString) return name
|
|
|
|
|
|
|
|
// recursive case: name is not unique and ends in digits
|
|
|
|
const newPad = nameEndsInDigits[1].length
|
|
|
|
const newIndex = parseInt(nameEndsInDigits[1]) + 1
|
|
|
|
const nameWithoutDigits = name.replace(endingDigitsMatcher, '')
|
|
|
|
|
|
|
|
return findUniqueName(searchStr, nameWithoutDigits, newPad, newIndex)
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
2024-02-23 11:24:22 -05:00
|
|
|
|
2023-01-06 09:29:26 +11:00
|
|
|
const newName = `${name}${indexStr}`
|
2024-02-23 11:24:22 -05:00
|
|
|
nameIsInString = searchStr.includes(`:"${newName}"`)
|
|
|
|
|
|
|
|
// base case: name is unique and does not end in digits
|
|
|
|
if (!nameIsInString) return newName
|
|
|
|
|
|
|
|
// recursive case: name is not unique and does not end in digits
|
2023-01-09 13:19:14 +11:00
|
|
|
return findUniqueName(searchStr, name, pad, index + 1)
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
|
|
|
|
2024-08-12 15:38:42 -05:00
|
|
|
export function mutateArrExp(node: Expr, updateWith: ArrayExpression): boolean {
|
2023-02-12 10:56:45 +11:00
|
|
|
if (node.type === 'ArrayExpression') {
|
|
|
|
node.elements.forEach((element, i) => {
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(element)) {
|
2023-02-12 10:56:45 +11:00
|
|
|
node.elements[i] = updateWith.elements[i]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return true
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return false
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export function mutateObjExpProp(
|
2024-08-12 15:38:42 -05:00
|
|
|
node: Expr,
|
2024-10-30 16:52:17 -04:00
|
|
|
updateWith: Node<Literal> | Node<ArrayExpression>,
|
2023-02-12 10:56:45 +11:00
|
|
|
key: string
|
|
|
|
): boolean {
|
|
|
|
if (node.type === 'ObjectExpression') {
|
|
|
|
const keyIndex = node.properties.findIndex((a) => a.key.name === key)
|
|
|
|
if (keyIndex !== -1) {
|
|
|
|
if (
|
2023-09-13 07:23:14 -07:00
|
|
|
isLiteralArrayOrStatic(updateWith) &&
|
|
|
|
isLiteralArrayOrStatic(node.properties[keyIndex].value)
|
2023-02-12 10:56:45 +11:00
|
|
|
) {
|
|
|
|
node.properties[keyIndex].value = updateWith
|
|
|
|
return true
|
|
|
|
} else if (
|
|
|
|
node.properties[keyIndex].value.type === 'ArrayExpression' &&
|
|
|
|
updateWith.type === 'ArrayExpression'
|
|
|
|
) {
|
|
|
|
const arrExp = node.properties[keyIndex].value as ArrayExpression
|
|
|
|
arrExp.elements.forEach((element, i) => {
|
2023-09-13 07:23:14 -07:00
|
|
|
if (isLiteralArrayOrStatic(element)) {
|
2023-02-12 10:56:45 +11:00
|
|
|
arrExp.elements[i] = updateWith.elements[i]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
node.properties.push({
|
|
|
|
type: 'ObjectProperty',
|
|
|
|
key: createIdentifier(key),
|
|
|
|
value: updateWith,
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-02-12 10:56:45 +11:00
|
|
|
})
|
|
|
|
}
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return false
|
2023-01-06 09:29:26 +11:00
|
|
|
}
|
2023-01-06 12:45:34 +11:00
|
|
|
|
|
|
|
export function extrudeSketch(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2023-04-01 16:47:00 +11:00
|
|
|
pathToNode: PathToNode,
|
2024-12-16 10:34:11 -05:00
|
|
|
shouldPipe = false,
|
2024-09-17 08:29:52 -05:00
|
|
|
distance: Expr = createLiteral(4)
|
2024-06-24 11:45:40 -04:00
|
|
|
):
|
|
|
|
| {
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>
|
2024-06-24 11:45:40 -04:00
|
|
|
pathToNode: PathToNode
|
|
|
|
pathToExtrudeArg: PathToNode
|
|
|
|
}
|
|
|
|
| Error {
|
2024-09-17 08:29:52 -05:00
|
|
|
const _node = structuredClone(node)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNodeFromPath(_node, pathToNode)
|
|
|
|
if (err(_node1)) return _node1
|
2024-12-16 10:34:11 -05:00
|
|
|
const { node: sketchExpression } = _node1
|
2023-01-06 12:45:34 +11:00
|
|
|
|
|
|
|
// determine if sketchExpression is in a pipeExpression or not
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node2 = getNodeFromPath<PipeExpression>(
|
2023-01-06 12:45:34 +11:00
|
|
|
_node,
|
|
|
|
pathToNode,
|
2023-01-13 17:58:37 +11:00
|
|
|
'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(_node2)) return _node2
|
2024-12-16 10:34:11 -05:00
|
|
|
const { node: pipeExpression } = _node2
|
|
|
|
|
|
|
|
const isInPipeExpression = pipeExpression.type === 'PipeExpression'
|
2023-01-13 17:58:37 +11:00
|
|
|
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node3 = getNodeFromPath<VariableDeclarator>(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
|
|
|
if (err(_node3)) return _node3
|
2024-12-16 10:34:11 -05:00
|
|
|
const { node: variableDeclarator, shallowPath: pathToDecleration } = _node3
|
2023-01-06 12:45:34 +11:00
|
|
|
|
2023-09-05 16:02:27 -07:00
|
|
|
const extrudeCall = createCallExpressionStdLib('extrude', [
|
2024-02-23 11:24:22 -05:00
|
|
|
distance,
|
2024-12-16 10:34:11 -05:00
|
|
|
shouldPipe
|
|
|
|
? createPipeSubstitution()
|
|
|
|
: createIdentifier(variableDeclarator.id.name),
|
2023-03-02 21:19:11 +11:00
|
|
|
])
|
|
|
|
|
2024-12-16 10:34:11 -05:00
|
|
|
if (shouldPipe) {
|
|
|
|
const pipeChain = createPipeExpression(
|
|
|
|
isInPipeExpression
|
|
|
|
? [...pipeExpression.body, extrudeCall]
|
|
|
|
: [sketchExpression as any, extrudeCall]
|
|
|
|
)
|
|
|
|
|
|
|
|
variableDeclarator.init = pipeChain
|
|
|
|
const pathToExtrudeArg: PathToNode = [
|
|
|
|
...pathToDecleration,
|
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['body', ''],
|
|
|
|
[pipeChain.body.length - 1, 'index'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
pathToExtrudeArg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-04 13:57:01 -04:00
|
|
|
// We're not creating a pipe expression,
|
|
|
|
// but rather a separate constant for the extrusion
|
|
|
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.EXTRUDE)
|
2023-03-02 21:19:11 +11:00
|
|
|
const VariableDeclaration = createVariableDeclaration(name, extrudeCall)
|
2024-06-04 13:57:01 -04:00
|
|
|
|
2024-12-16 10:34:11 -05:00
|
|
|
const sketchIndexInPathToNode =
|
|
|
|
pathToDecleration.findIndex((a) => a[0] === 'body') + 1
|
|
|
|
const sketchIndexInBody = pathToDecleration[
|
|
|
|
sketchIndexInPathToNode
|
|
|
|
][0] as number
|
2024-06-04 13:57:01 -04:00
|
|
|
_node.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
|
|
|
|
|
2023-04-01 16:47:00 +11:00
|
|
|
const pathToExtrudeArg: PathToNode = [
|
|
|
|
['body', ''],
|
2024-06-04 13:57:01 -04:00
|
|
|
[sketchIndexInBody + 1, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2023-04-01 16:47:00 +11:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
2023-01-13 17:58:37 +11:00
|
|
|
]
|
2023-01-06 12:45:34 +11:00
|
|
|
return {
|
2024-06-04 13:57:01 -04:00
|
|
|
modifiedAst: _node,
|
2024-03-01 17:16:18 -08:00
|
|
|
pathToNode: [...pathToNode.slice(0, -1), [-1, 'index']],
|
2023-01-13 17:58:37 +11:00
|
|
|
pathToExtrudeArg,
|
2023-01-06 12:45:34 +11:00
|
|
|
}
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
|
2024-12-04 17:24:16 -05:00
|
|
|
export function loftSketches(
|
|
|
|
node: Node<Program>,
|
|
|
|
declarators: VariableDeclarator[]
|
|
|
|
): {
|
|
|
|
modifiedAst: Node<Program>
|
|
|
|
pathToNode: PathToNode
|
|
|
|
} {
|
|
|
|
const modifiedAst = structuredClone(node)
|
|
|
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.LOFT)
|
|
|
|
const elements = declarators.map((d) => createIdentifier(d.id.name))
|
|
|
|
const loft = createCallExpressionStdLib('loft', [
|
|
|
|
createArrayExpression(elements),
|
|
|
|
])
|
|
|
|
const declaration = createVariableDeclaration(name, loft)
|
|
|
|
modifiedAst.body.push(declaration)
|
|
|
|
const pathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[modifiedAst.body.length - 1, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2024-12-04 17:24:16 -05:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-11 08:20:49 -05:00
|
|
|
export function addSweep(
|
|
|
|
node: Node<Program>,
|
|
|
|
profileDeclarator: VariableDeclarator,
|
|
|
|
pathDeclarator: VariableDeclarator
|
|
|
|
): {
|
|
|
|
modifiedAst: Node<Program>
|
|
|
|
pathToNode: PathToNode
|
|
|
|
} {
|
|
|
|
const modifiedAst = structuredClone(node)
|
|
|
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SWEEP)
|
|
|
|
const sweep = createCallExpressionStdLib('sweep', [
|
|
|
|
createObjectExpression({ path: createIdentifier(pathDeclarator.id.name) }),
|
|
|
|
createIdentifier(profileDeclarator.id.name),
|
|
|
|
])
|
|
|
|
const declaration = createVariableDeclaration(name, sweep)
|
|
|
|
modifiedAst.body.push(declaration)
|
|
|
|
const pathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[modifiedAst.body.length - 1, 'index'],
|
|
|
|
['declaration', 'VariableDeclaration'],
|
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-17 08:29:52 -05:00
|
|
|
export function revolveSketch(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2024-09-17 08:29:52 -05:00
|
|
|
pathToNode: PathToNode,
|
|
|
|
shouldPipe = false,
|
|
|
|
angle: Expr = createLiteral(4)
|
|
|
|
):
|
|
|
|
| {
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>
|
2024-09-17 08:29:52 -05:00
|
|
|
pathToNode: PathToNode
|
|
|
|
pathToRevolveArg: PathToNode
|
|
|
|
}
|
|
|
|
| Error {
|
|
|
|
const _node = structuredClone(node)
|
|
|
|
const _node1 = getNodeFromPath(_node, pathToNode)
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: sketchExpression } = _node1
|
|
|
|
|
|
|
|
// determine if sketchExpression is in a pipeExpression or not
|
|
|
|
const _node2 = getNodeFromPath<PipeExpression>(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
|
|
|
)
|
|
|
|
if (err(_node2)) return _node2
|
|
|
|
const { node: pipeExpression } = _node2
|
|
|
|
|
|
|
|
const isInPipeExpression = pipeExpression.type === 'PipeExpression'
|
|
|
|
|
|
|
|
const _node3 = getNodeFromPath<VariableDeclarator>(
|
|
|
|
_node,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
|
|
|
if (err(_node3)) return _node3
|
|
|
|
const { node: variableDeclarator, shallowPath: pathToDecleration } = _node3
|
|
|
|
|
|
|
|
const revolveCall = createCallExpressionStdLib('revolve', [
|
|
|
|
createObjectExpression({
|
|
|
|
angle: angle,
|
|
|
|
// TODO: hard coded 'X' axis for revolve MVP, should be changed.
|
|
|
|
axis: createLiteral('X'),
|
|
|
|
}),
|
|
|
|
createIdentifier(variableDeclarator.id.name),
|
|
|
|
])
|
|
|
|
|
|
|
|
if (shouldPipe) {
|
|
|
|
const pipeChain = createPipeExpression(
|
|
|
|
isInPipeExpression
|
|
|
|
? [...pipeExpression.body, revolveCall]
|
|
|
|
: [sketchExpression as any, revolveCall]
|
|
|
|
)
|
|
|
|
|
|
|
|
variableDeclarator.init = pipeChain
|
|
|
|
const pathToRevolveArg: PathToNode = [
|
|
|
|
...pathToDecleration,
|
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['body', ''],
|
|
|
|
[pipeChain.body.length - 1, 'index'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode,
|
|
|
|
pathToRevolveArg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're not creating a pipe expression,
|
|
|
|
// but rather a separate constant for the extrusion
|
|
|
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.REVOLVE)
|
|
|
|
const VariableDeclaration = createVariableDeclaration(name, revolveCall)
|
|
|
|
const sketchIndexInPathToNode =
|
|
|
|
pathToDecleration.findIndex((a) => a[0] === 'body') + 1
|
|
|
|
const sketchIndexInBody = pathToDecleration[sketchIndexInPathToNode][0]
|
|
|
|
if (typeof sketchIndexInBody !== 'number')
|
|
|
|
return new Error('expected sketchIndexInBody to be a number')
|
|
|
|
_node.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration)
|
|
|
|
|
|
|
|
const pathToRevolveArg: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[sketchIndexInBody + 1, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2024-09-17 08:29:52 -05:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode: [...pathToNode.slice(0, -1), [-1, 'index']],
|
|
|
|
pathToRevolveArg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-09 13:19:14 +11:00
|
|
|
export function sketchOnExtrudedFace(
|
2024-10-30 16:52:17 -04:00
|
|
|
node: Node<Program>,
|
2024-06-04 13:57:01 -04:00
|
|
|
sketchPathToNode: PathToNode,
|
|
|
|
extrudePathToNode: PathToNode,
|
2024-09-26 18:25:05 +10:00
|
|
|
info: ExtrudeFacePlane['faceInfo'] = { type: 'wall' }
|
2024-06-24 11:45:40 -04:00
|
|
|
): { modifiedAst: Program; pathToNode: PathToNode } | Error {
|
2023-02-12 10:56:45 +11:00
|
|
|
let _node = { ...node }
|
2024-06-04 13:57:01 -04:00
|
|
|
const newSketchName = findUniqueName(
|
|
|
|
node,
|
|
|
|
KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNodeFromPath<VariableDeclarator>(
|
2024-03-22 10:23:04 +11:00
|
|
|
_node,
|
2024-06-04 13:57:01 -04:00
|
|
|
sketchPathToNode,
|
2024-03-22 10:23:04 +11:00
|
|
|
'VariableDeclarator',
|
|
|
|
true
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: oldSketchNode } = _node1
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
const oldSketchName = oldSketchNode.id.name
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node2 = getNodeFromPath<CallExpression>(
|
2023-01-10 15:40:34 +11:00
|
|
|
_node,
|
2024-06-04 13:57:01 -04:00
|
|
|
sketchPathToNode,
|
2023-02-12 10:56:45 +11:00
|
|
|
'CallExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(_node2)) return _node2
|
|
|
|
const { node: expression } = _node2
|
|
|
|
|
|
|
|
const _node3 = getNodeFromPath<VariableDeclarator>(
|
2024-06-04 13:57:01 -04:00
|
|
|
_node,
|
|
|
|
extrudePathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(_node3)) return _node3
|
|
|
|
const { node: extrudeVarDec } = _node3
|
2024-06-04 13:57:01 -04:00
|
|
|
const extrudeName = extrudeVarDec.id?.name
|
2023-01-09 13:19:14 +11:00
|
|
|
|
2024-09-26 18:25:05 +10:00
|
|
|
let _tag
|
|
|
|
if (info.type !== 'cap') {
|
2024-06-24 11:45:40 -04:00
|
|
|
const __tag = addTagForSketchOnFace(
|
2024-03-22 10:23:04 +11:00
|
|
|
{
|
2024-06-04 13:57:01 -04:00
|
|
|
pathToNode: sketchPathToNode,
|
2024-03-22 10:23:04 +11:00
|
|
|
node: _node,
|
|
|
|
},
|
2024-09-26 18:25:05 +10:00
|
|
|
expression.callee.name,
|
|
|
|
info.type === 'edgeCut' ? info : null
|
2024-03-22 10:23:04 +11:00
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(__tag)) return __tag
|
|
|
|
const { modifiedAst, tag } = __tag
|
2024-06-24 22:39:04 -07:00
|
|
|
_tag = createIdentifier(tag)
|
2024-03-22 10:23:04 +11:00
|
|
|
_node = modifiedAst
|
|
|
|
} else {
|
2024-09-26 18:25:05 +10:00
|
|
|
_tag = createLiteral(info.subType.toUpperCase())
|
2024-03-22 10:23:04 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
const newSketch = createVariableDeclaration(
|
|
|
|
newSketchName,
|
2024-03-22 10:23:04 +11:00
|
|
|
createCallExpressionStdLib('startSketchOn', [
|
2024-06-04 13:57:01 -04:00
|
|
|
createIdentifier(extrudeName ? extrudeName : oldSketchName),
|
2024-06-24 22:39:04 -07:00
|
|
|
_tag,
|
2023-02-12 10:56:45 +11:00
|
|
|
]),
|
2024-10-17 00:48:33 -04:00
|
|
|
undefined,
|
2023-02-12 10:56:45 +11:00
|
|
|
'const'
|
|
|
|
)
|
2024-03-22 10:23:04 +11:00
|
|
|
|
2024-06-04 13:57:01 -04:00
|
|
|
const expressionIndex = Math.max(
|
|
|
|
sketchPathToNode[1][0] as number,
|
|
|
|
extrudePathToNode[1][0] as number
|
|
|
|
)
|
2023-02-12 10:56:45 +11:00
|
|
|
_node.body.splice(expressionIndex + 1, 0, newSketch)
|
2024-03-22 10:23:04 +11:00
|
|
|
const newpathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[expressionIndex + 1, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2024-03-22 10:23:04 +11:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
]
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
return {
|
2024-03-01 17:16:18 -08:00
|
|
|
modifiedAst: _node,
|
2024-03-22 10:23:04 +11:00
|
|
|
pathToNode: newpathToNode,
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
|
2024-11-26 11:36:14 -05:00
|
|
|
/**
|
|
|
|
* Append an offset plane to the AST
|
|
|
|
*/
|
|
|
|
export function addOffsetPlane({
|
|
|
|
node,
|
|
|
|
defaultPlane,
|
|
|
|
offset,
|
|
|
|
}: {
|
|
|
|
node: Node<Program>
|
|
|
|
defaultPlane: DefaultPlaneStr
|
|
|
|
offset: Expr
|
|
|
|
}): { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
|
|
|
const modifiedAst = structuredClone(node)
|
|
|
|
const newPlaneName = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.PLANE)
|
|
|
|
|
|
|
|
const newPlane = createVariableDeclaration(
|
|
|
|
newPlaneName,
|
|
|
|
createCallExpressionStdLib('offsetPlane', [
|
|
|
|
createLiteral(defaultPlane.toUpperCase()),
|
|
|
|
offset,
|
|
|
|
])
|
|
|
|
)
|
|
|
|
|
|
|
|
modifiedAst.body.push(newPlane)
|
|
|
|
const pathToNode: PathToNode = [
|
|
|
|
['body', ''],
|
|
|
|
[modifiedAst.body.length - 1, 'index'],
|
2024-12-07 07:16:04 +13:00
|
|
|
['declaration', 'VariableDeclaration'],
|
2024-11-26 11:36:14 -05:00
|
|
|
['init', 'VariableDeclarator'],
|
|
|
|
['arguments', 'CallExpression'],
|
|
|
|
[0, 'index'],
|
|
|
|
]
|
|
|
|
return {
|
|
|
|
modifiedAst,
|
|
|
|
pathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-09 16:43:58 -05:00
|
|
|
/**
|
|
|
|
* Return a modified clone of an AST with a named constant inserted into the body
|
|
|
|
*/
|
|
|
|
export function insertNamedConstant({
|
|
|
|
node,
|
|
|
|
newExpression,
|
|
|
|
}: {
|
|
|
|
node: Node<Program>
|
|
|
|
newExpression: KclExpressionWithVariable
|
|
|
|
}): Node<Program> {
|
|
|
|
const ast = structuredClone(node)
|
|
|
|
ast.body.splice(
|
|
|
|
newExpression.insertIndex,
|
|
|
|
0,
|
|
|
|
newExpression.variableDeclarationAst
|
|
|
|
)
|
|
|
|
return ast
|
|
|
|
}
|
|
|
|
|
2024-11-18 16:25:25 -05:00
|
|
|
/**
|
|
|
|
* Modify the AST to create a new sketch using the variable declaration
|
|
|
|
* of an offset plane. The new sketch just has to come after the offset
|
|
|
|
* plane declaration.
|
|
|
|
*/
|
|
|
|
export function sketchOnOffsetPlane(
|
|
|
|
node: Node<Program>,
|
|
|
|
offsetPathToNode: PathToNode
|
|
|
|
) {
|
|
|
|
let _node = { ...node }
|
|
|
|
|
|
|
|
// Find the offset plane declaration
|
|
|
|
const offsetPlaneDeclarator = getNodeFromPath<VariableDeclarator>(
|
|
|
|
_node,
|
|
|
|
offsetPathToNode,
|
|
|
|
'VariableDeclarator',
|
|
|
|
true
|
|
|
|
)
|
|
|
|
if (err(offsetPlaneDeclarator)) return offsetPlaneDeclarator
|
|
|
|
const { node: offsetPlaneNode } = offsetPlaneDeclarator
|
|
|
|
const offsetPlaneName = offsetPlaneNode.id.name
|
|
|
|
|
|
|
|
// Create a new sketch declaration
|
|
|
|
const newSketchName = findUniqueName(
|
|
|
|
node,
|
|
|
|
KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH
|
|
|
|
)
|
|
|
|
const newSketch = createVariableDeclaration(
|
|
|
|
newSketchName,
|
|
|
|
createCallExpressionStdLib('startSketchOn', [
|
|
|
|
createIdentifier(offsetPlaneName),
|
|
|
|
]),
|
|
|
|
undefined,
|
|
|
|
'const'
|
|
|
|
)
|
|
|
|
|
|
|
|
// Decide where to insert the new sketch declaration
|
|
|
|
const offsetIndex = offsetPathToNode[1][0]
|
|
|
|
|
|
|
|
if (!isPathToNodeNumber(offsetIndex)) {
|
|
|
|
return new Error('Expected offsetIndex to be a number')
|
|
|
|
}
|
|
|
|
// and insert it
|
|
|
|
_node.body.splice(offsetIndex + 1, 0, newSketch)
|
|
|
|
const newPathToNode = structuredClone(offsetPathToNode)
|
|
|
|
newPathToNode[1][0] = offsetIndex + 1
|
|
|
|
|
|
|
|
// Return the modified AST and the path to the new sketch declaration
|
|
|
|
return {
|
|
|
|
modifiedAst: _node,
|
|
|
|
pathToNode: newPathToNode,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-10 08:35:30 +11:00
|
|
|
export const getLastIndex = (pathToNode: PathToNode): number =>
|
|
|
|
splitPathAtLastIndex(pathToNode).index
|
|
|
|
|
|
|
|
export function splitPathAtLastIndex(pathToNode: PathToNode): {
|
|
|
|
path: PathToNode
|
|
|
|
index: number
|
|
|
|
} {
|
2023-02-12 10:56:45 +11:00
|
|
|
const last = pathToNode[pathToNode.length - 1]
|
2023-04-01 16:47:00 +11:00
|
|
|
if (last && typeof last[0] === 'number') {
|
2023-03-10 08:35:30 +11:00
|
|
|
return {
|
|
|
|
path: pathToNode.slice(0, -1),
|
2023-04-01 16:47:00 +11:00
|
|
|
index: last[0],
|
2023-03-10 08:35:30 +11:00
|
|
|
}
|
2023-03-21 19:02:18 +11:00
|
|
|
} else if (pathToNode.length === 0) {
|
|
|
|
return {
|
|
|
|
path: [],
|
|
|
|
index: -1,
|
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
}
|
2023-03-10 08:35:30 +11:00
|
|
|
return splitPathAtLastIndex(pathToNode.slice(0, -1))
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
|
2023-04-01 16:47:00 +11:00
|
|
|
export function splitPathAtPipeExpression(pathToNode: PathToNode): {
|
|
|
|
path: PathToNode
|
|
|
|
index: number
|
|
|
|
} {
|
|
|
|
const last = pathToNode[pathToNode.length - 1]
|
|
|
|
|
|
|
|
if (
|
|
|
|
last &&
|
|
|
|
last[1] === 'index' &&
|
|
|
|
pathToNode?.[pathToNode.length - 2]?.[1] === 'PipeExpression' &&
|
|
|
|
typeof last[0] === 'number'
|
|
|
|
) {
|
|
|
|
return {
|
|
|
|
path: pathToNode.slice(0, -1),
|
|
|
|
index: last[0],
|
|
|
|
}
|
|
|
|
} else if (pathToNode.length === 0) {
|
|
|
|
return {
|
|
|
|
path: [],
|
|
|
|
index: -1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return splitPathAtPipeExpression(pathToNode.slice(0, -1))
|
|
|
|
}
|
|
|
|
|
2025-01-22 08:29:30 +13:00
|
|
|
export function createLiteral(value: LiteralValue | number): Node<Literal> {
|
|
|
|
const raw = `${value}`
|
|
|
|
if (typeof value === 'number') {
|
|
|
|
value = { value, suffix: 'None' }
|
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'Literal',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-02-12 10:56:45 +11:00
|
|
|
value,
|
2025-01-22 08:29:30 +13:00
|
|
|
raw,
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-30 16:52:17 -04:00
|
|
|
export function createTagDeclarator(value: string): Node<TagDeclarator> {
|
2024-06-24 22:39:04 -07:00
|
|
|
return {
|
|
|
|
type: 'TagDeclarator',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2024-06-24 22:39:04 -07:00
|
|
|
value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-30 16:52:17 -04:00
|
|
|
export function createIdentifier(name: string): Node<Identifier> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'Identifier',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-30 16:52:17 -04:00
|
|
|
export function createPipeSubstitution(): Node<PipeSubstitution> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'PipeSubstitution',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-05 16:02:27 -07:00
|
|
|
export function createCallExpressionStdLib(
|
|
|
|
name: string,
|
|
|
|
args: CallExpression['arguments']
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<CallExpression> {
|
2023-09-05 16:02:27 -07:00
|
|
|
return {
|
|
|
|
type: 'CallExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-09-05 16:02:27 -07:00
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-09-05 16:02:27 -07:00
|
|
|
name,
|
|
|
|
},
|
|
|
|
arguments: args,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export function createCallExpression(
|
|
|
|
name: string,
|
|
|
|
args: CallExpression['arguments']
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<CallExpression> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'CallExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-02-12 10:56:45 +11:00
|
|
|
callee: {
|
|
|
|
type: 'Identifier',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
name,
|
|
|
|
},
|
|
|
|
arguments: args,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createArrayExpression(
|
|
|
|
elements: ArrayExpression['elements']
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<ArrayExpression> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'ArrayExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2024-08-22 13:54:59 -05:00
|
|
|
nonCodeMeta: nonCodeMetaEmpty(),
|
2023-02-12 10:56:45 +11:00
|
|
|
elements,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createPipeExpression(
|
|
|
|
body: PipeExpression['body']
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<PipeExpression> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
2023-01-09 13:19:14 +11:00
|
|
|
type: 'PipeExpression',
|
2023-02-12 10:56:45 +11:00
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
body,
|
2024-08-22 13:54:59 -05:00
|
|
|
nonCodeMeta: nonCodeMetaEmpty(),
|
2023-01-09 13:19:14 +11:00
|
|
|
}
|
2023-02-12 10:56:45 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
export function createVariableDeclaration(
|
|
|
|
varName: string,
|
|
|
|
init: VariableDeclarator['init'],
|
2024-10-17 00:48:33 -04:00
|
|
|
visibility: VariableDeclaration['visibility'] = 'default',
|
2023-02-12 10:56:45 +11:00
|
|
|
kind: VariableDeclaration['kind'] = 'const'
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<VariableDeclaration> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
2023-01-09 13:19:14 +11:00
|
|
|
type: 'VariableDeclaration',
|
2023-02-12 10:56:45 +11:00
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2024-12-07 07:16:04 +13:00
|
|
|
declaration: {
|
|
|
|
type: 'VariableDeclarator',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2024-12-07 07:16:04 +13:00
|
|
|
id: createIdentifier(varName),
|
|
|
|
init,
|
|
|
|
},
|
2024-10-17 00:48:33 -04:00
|
|
|
visibility,
|
2023-02-12 10:56:45 +11:00
|
|
|
kind,
|
2023-01-09 13:19:14 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export function createObjectExpression(properties: {
|
2024-08-12 15:38:42 -05:00
|
|
|
[key: string]: Expr
|
2024-10-30 16:52:17 -04:00
|
|
|
}): Node<ObjectExpression> {
|
2023-02-12 10:56:45 +11:00
|
|
|
return {
|
|
|
|
type: 'ObjectExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2024-08-22 13:54:59 -05:00
|
|
|
nonCodeMeta: nonCodeMetaEmpty(),
|
2023-02-12 10:56:45 +11:00
|
|
|
properties: Object.entries(properties).map(([key, value]) => ({
|
|
|
|
type: 'ObjectProperty',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2023-02-12 10:56:45 +11:00
|
|
|
key: createIdentifier(key),
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
value,
|
|
|
|
})),
|
2023-01-09 13:19:14 +11:00
|
|
|
}
|
|
|
|
}
|
2023-03-02 21:19:11 +11:00
|
|
|
|
|
|
|
export function createUnaryExpression(
|
|
|
|
argument: UnaryExpression['argument'],
|
|
|
|
operator: UnaryExpression['operator'] = '-'
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<UnaryExpression> {
|
2023-03-02 21:19:11 +11:00
|
|
|
return {
|
|
|
|
type: 'UnaryExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
operator,
|
|
|
|
argument,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createBinaryExpression([left, operator, right]: [
|
|
|
|
BinaryExpression['left'],
|
|
|
|
BinaryExpression['operator'],
|
|
|
|
BinaryExpression['right']
|
2024-10-30 16:52:17 -04:00
|
|
|
]): Node<BinaryExpression> {
|
2023-03-02 21:19:11 +11:00
|
|
|
return {
|
|
|
|
type: 'BinaryExpression',
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
2024-11-07 11:23:41 -05:00
|
|
|
moduleId: 0,
|
2024-10-17 16:22:40 -07:00
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
operator,
|
|
|
|
left,
|
|
|
|
right,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-02 17:20:11 +10:00
|
|
|
export function createBinaryExpressionWithUnary([left, right]: [
|
|
|
|
BinaryExpression['left'],
|
|
|
|
BinaryExpression['right']
|
2024-10-30 16:52:17 -04:00
|
|
|
]): Node<BinaryExpression> {
|
2023-04-02 17:20:11 +10:00
|
|
|
if (right.type === 'UnaryExpression' && right.operator === '-')
|
|
|
|
return createBinaryExpression([left, '-', right.argument])
|
|
|
|
return createBinaryExpression([left, '+', right])
|
|
|
|
}
|
|
|
|
|
2023-03-02 21:19:11 +11:00
|
|
|
export function giveSketchFnCallTag(
|
2024-10-30 16:52:17 -04:00
|
|
|
ast: Node<Program>,
|
2024-11-21 15:04:30 +11:00
|
|
|
range: SourceRange,
|
2023-03-07 15:45:59 +11:00
|
|
|
tag?: string
|
2024-06-24 11:45:40 -04:00
|
|
|
):
|
|
|
|
| {
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>
|
2024-06-24 11:45:40 -04:00
|
|
|
tag: string
|
|
|
|
isTagExisting: boolean
|
|
|
|
pathToNode: PathToNode
|
|
|
|
}
|
|
|
|
| Error {
|
2023-04-14 07:49:36 +10:00
|
|
|
const path = getNodePathFromSourceRange(ast, range)
|
2024-06-24 11:45:40 -04:00
|
|
|
const _node1 = getNodeFromPath<CallExpression>(ast, path, 'CallExpression')
|
|
|
|
if (err(_node1)) return _node1
|
|
|
|
const { node: primaryCallExp } = _node1
|
|
|
|
|
2024-03-15 17:03:42 -04:00
|
|
|
// Tag is always 3rd expression now, using arg index feels brittle
|
|
|
|
// but we can come up with a better way to identify tag later.
|
|
|
|
const thirdArg = primaryCallExp.arguments?.[2]
|
2024-06-24 22:39:04 -07:00
|
|
|
const tagDeclarator =
|
|
|
|
thirdArg ||
|
|
|
|
(createTagDeclarator(tag || findUniqueName(ast, 'seg', 2)) as TagDeclarator)
|
2024-03-15 17:03:42 -04:00
|
|
|
const isTagExisting = !!thirdArg
|
|
|
|
if (!isTagExisting) {
|
2024-06-24 22:39:04 -07:00
|
|
|
primaryCallExp.arguments[2] = tagDeclarator
|
2024-03-15 17:03:42 -04:00
|
|
|
}
|
2024-06-24 22:39:04 -07:00
|
|
|
if ('value' in tagDeclarator) {
|
|
|
|
// Now TypeScript knows tagDeclarator has a value property
|
2024-03-15 17:03:42 -04:00
|
|
|
return {
|
|
|
|
modifiedAst: ast,
|
2024-06-24 22:39:04 -07:00
|
|
|
tag: String(tagDeclarator.value),
|
2024-03-15 17:03:42 -04:00
|
|
|
isTagExisting,
|
|
|
|
pathToNode: path,
|
|
|
|
}
|
|
|
|
} else {
|
2024-06-24 11:45:40 -04:00
|
|
|
return new Error('Unable to assign tag without value')
|
2023-03-02 21:19:11 +11:00
|
|
|
}
|
|
|
|
}
|
2023-04-01 16:47:00 +11:00
|
|
|
|
2024-12-09 16:43:58 -05:00
|
|
|
/**
|
|
|
|
* Replace a
|
|
|
|
*/
|
|
|
|
export function replaceValueAtNodePath({
|
|
|
|
ast,
|
|
|
|
pathToNode,
|
|
|
|
newExpressionString,
|
|
|
|
}: {
|
|
|
|
ast: Node<Program>
|
|
|
|
pathToNode: PathToNode
|
|
|
|
newExpressionString: string
|
|
|
|
}) {
|
|
|
|
const replaceCheckResult = isNodeSafeToReplacePath(ast, pathToNode)
|
|
|
|
if (err(replaceCheckResult)) {
|
|
|
|
return replaceCheckResult
|
|
|
|
}
|
|
|
|
const { isSafe, value, replacer } = replaceCheckResult
|
|
|
|
|
|
|
|
if (!isSafe || value.type === 'Identifier') {
|
|
|
|
return new Error('Not safe to replace')
|
|
|
|
}
|
|
|
|
|
|
|
|
return replacer(ast, newExpressionString)
|
|
|
|
}
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
export function moveValueIntoNewVariablePath(
|
2024-10-30 16:52:17 -04:00
|
|
|
ast: Node<Program>,
|
2024-05-24 20:54:42 +10:00
|
|
|
programMemory: ProgramMemory,
|
|
|
|
pathToNode: PathToNode,
|
|
|
|
variableName: string
|
|
|
|
): {
|
|
|
|
modifiedAst: Program
|
|
|
|
pathToReplacedNode?: PathToNode
|
|
|
|
} {
|
2024-06-24 11:45:40 -04:00
|
|
|
const meta = isNodeSafeToReplacePath(ast, pathToNode)
|
|
|
|
if (trap(meta)) return { modifiedAst: ast }
|
|
|
|
const { isSafe, value, replacer } = meta
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
if (!isSafe || value.type === 'Identifier') return { modifiedAst: ast }
|
|
|
|
|
|
|
|
const { insertIndex } = findAllPreviousVariablesPath(
|
|
|
|
ast,
|
|
|
|
programMemory,
|
|
|
|
pathToNode
|
|
|
|
)
|
2024-07-25 20:11:46 -04:00
|
|
|
let _node = structuredClone(ast)
|
2024-05-24 20:54:42 +10:00
|
|
|
const boop = replacer(_node, variableName)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (trap(boop)) return { modifiedAst: ast }
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
_node = boop.modifiedAst
|
|
|
|
_node.body.splice(
|
|
|
|
insertIndex,
|
|
|
|
0,
|
|
|
|
createVariableDeclaration(variableName, value)
|
|
|
|
)
|
|
|
|
return { modifiedAst: _node, pathToReplacedNode: boop.pathToReplaced }
|
|
|
|
}
|
|
|
|
|
2023-04-01 16:47:00 +11:00
|
|
|
export function moveValueIntoNewVariable(
|
2024-10-30 16:52:17 -04:00
|
|
|
ast: Node<Program>,
|
2023-04-01 16:47:00 +11:00
|
|
|
programMemory: ProgramMemory,
|
2024-11-21 15:04:30 +11:00
|
|
|
sourceRange: SourceRange,
|
2023-04-01 16:47:00 +11:00
|
|
|
variableName: string
|
|
|
|
): {
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>
|
2024-05-24 20:54:42 +10:00
|
|
|
pathToReplacedNode?: PathToNode
|
2023-04-01 16:47:00 +11:00
|
|
|
} {
|
2024-06-24 11:45:40 -04:00
|
|
|
const meta = isNodeSafeToReplace(ast, sourceRange)
|
|
|
|
if (trap(meta)) return { modifiedAst: ast }
|
|
|
|
const { isSafe, value, replacer } = meta
|
2023-04-01 16:47:00 +11:00
|
|
|
if (!isSafe || value.type === 'Identifier') return { modifiedAst: ast }
|
|
|
|
|
|
|
|
const { insertIndex } = findAllPreviousVariables(
|
|
|
|
ast,
|
|
|
|
programMemory,
|
|
|
|
sourceRange
|
|
|
|
)
|
2024-07-25 20:11:46 -04:00
|
|
|
let _node = structuredClone(ast)
|
2024-06-24 11:45:40 -04:00
|
|
|
const replaced = replacer(_node, variableName)
|
|
|
|
if (trap(replaced)) return { modifiedAst: ast }
|
|
|
|
|
|
|
|
const { modifiedAst, pathToReplaced } = replaced
|
2024-05-24 20:54:42 +10:00
|
|
|
_node = modifiedAst
|
2023-04-01 16:47:00 +11:00
|
|
|
_node.body.splice(
|
|
|
|
insertIndex,
|
|
|
|
0,
|
|
|
|
createVariableDeclaration(variableName, value)
|
|
|
|
)
|
2024-05-24 20:54:42 +10:00
|
|
|
return { modifiedAst: _node, pathToReplacedNode: pathToReplaced }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deletes a segment from a pipe expression, if the segment has a tag that other segments use, it will remove that value and replace it with the equivalent literal
|
|
|
|
* @param dependentRanges - The ranges of the segments that are dependent on the segment being deleted, this is usually the output of `findUsesOfTagInPipe`
|
|
|
|
*/
|
|
|
|
export function deleteSegmentFromPipeExpression(
|
|
|
|
dependentRanges: SourceRange[],
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>,
|
2024-05-24 20:54:42 +10:00
|
|
|
programMemory: ProgramMemory,
|
|
|
|
code: string,
|
|
|
|
pathToNode: PathToNode
|
2024-10-30 16:52:17 -04:00
|
|
|
): Node<Program> | Error {
|
2024-07-25 20:11:46 -04:00
|
|
|
let _modifiedAst = structuredClone(modifiedAst)
|
2024-05-24 20:54:42 +10:00
|
|
|
|
|
|
|
dependentRanges.forEach((range) => {
|
|
|
|
const path = getNodePathFromSourceRange(_modifiedAst, range)
|
|
|
|
|
2024-10-30 16:52:17 -04:00
|
|
|
const callExp = getNodeFromPath<Node<CallExpression>>(
|
2024-05-24 20:54:42 +10:00
|
|
|
_modifiedAst,
|
|
|
|
path,
|
|
|
|
'CallExpression',
|
|
|
|
true
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(callExp)) return callExp
|
|
|
|
|
2024-05-24 20:54:42 +10:00
|
|
|
const constraintInfo = getConstraintInfo(callExp.node, code, path).find(
|
|
|
|
({ sourceRange }) => isOverlap(sourceRange, range)
|
|
|
|
)
|
|
|
|
if (!constraintInfo) return
|
2024-06-24 11:45:40 -04:00
|
|
|
|
2024-09-13 21:14:14 +10:00
|
|
|
if (!constraintInfo.argPosition) return
|
2024-05-24 20:54:42 +10:00
|
|
|
const transform = removeSingleConstraintInfo(
|
2024-09-13 21:14:14 +10:00
|
|
|
callExp.shallowPath,
|
|
|
|
constraintInfo.argPosition,
|
2024-05-24 20:54:42 +10:00
|
|
|
_modifiedAst,
|
|
|
|
programMemory
|
|
|
|
)
|
|
|
|
if (!transform) return
|
|
|
|
_modifiedAst = transform.modifiedAst
|
|
|
|
})
|
|
|
|
|
|
|
|
const pipeExpression = getNodeFromPath<PipeExpression>(
|
|
|
|
_modifiedAst,
|
|
|
|
pathToNode,
|
|
|
|
'PipeExpression'
|
2024-06-24 11:45:40 -04:00
|
|
|
)
|
|
|
|
if (err(pipeExpression)) return pipeExpression
|
2024-05-24 20:54:42 +10:00
|
|
|
|
|
|
|
const pipeInPathIndex = pathToNode.findIndex(
|
|
|
|
([_, desc]) => desc === 'PipeExpression'
|
|
|
|
)
|
2024-06-24 11:45:40 -04:00
|
|
|
const segmentIndexInPipe = pathToNode[pipeInPathIndex + 1]
|
|
|
|
pipeExpression.node.body.splice(segmentIndexInPipe[0] as number, 1)
|
|
|
|
|
|
|
|
// Move up to the next segment.
|
|
|
|
segmentIndexInPipe[0] = Math.max((segmentIndexInPipe[0] as number) - 1, 0)
|
2024-05-24 20:54:42 +10:00
|
|
|
|
|
|
|
return _modifiedAst
|
|
|
|
}
|
|
|
|
|
|
|
|
export function removeSingleConstraintInfo(
|
2024-09-13 21:14:14 +10:00
|
|
|
pathToCallExp: PathToNode,
|
|
|
|
argDetails: SimplifiedArgDetails,
|
2024-10-30 16:52:17 -04:00
|
|
|
ast: Node<Program>,
|
2024-05-24 20:54:42 +10:00
|
|
|
programMemory: ProgramMemory
|
|
|
|
):
|
|
|
|
| {
|
2024-10-30 16:52:17 -04:00
|
|
|
modifiedAst: Node<Program>
|
2024-05-24 20:54:42 +10:00
|
|
|
pathToNodeMap: PathToNodeMap
|
|
|
|
}
|
|
|
|
| false {
|
|
|
|
const transform = removeSingleConstraint({
|
|
|
|
pathToCallExp,
|
2024-09-13 21:14:14 +10:00
|
|
|
inputDetails: argDetails,
|
2024-05-24 20:54:42 +10:00
|
|
|
ast,
|
|
|
|
})
|
|
|
|
if (!transform) return false
|
2024-06-24 11:45:40 -04:00
|
|
|
const retval = transformAstSketchLines({
|
2024-05-24 20:54:42 +10:00
|
|
|
ast,
|
|
|
|
selectionRanges: [pathToCallExp],
|
|
|
|
transformInfos: [transform],
|
|
|
|
programMemory,
|
|
|
|
referenceSegName: '',
|
|
|
|
})
|
2024-06-24 11:45:40 -04:00
|
|
|
if (err(retval)) return false
|
|
|
|
return retval
|
2023-04-01 16:47:00 +11:00
|
|
|
}
|
2024-06-29 10:36:04 -07:00
|
|
|
|
|
|
|
export async function deleteFromSelection(
|
2024-10-30 16:52:17 -04:00
|
|
|
ast: Node<Program>,
|
2024-06-29 10:36:04 -07:00
|
|
|
selection: Selection,
|
|
|
|
programMemory: ProgramMemory,
|
|
|
|
getFaceDetails: (id: string) => Promise<Models['FaceIsPlanar_type']> = () =>
|
|
|
|
({} as any)
|
2024-10-30 16:52:17 -04:00
|
|
|
): Promise<Node<Program> | Error> {
|
2024-07-25 20:11:46 -04:00
|
|
|
const astClone = structuredClone(ast)
|
2024-06-29 10:36:04 -07:00
|
|
|
const varDec = getNodeFromPath<VariableDeclarator>(
|
|
|
|
ast,
|
2024-11-21 15:04:30 +11:00
|
|
|
selection?.codeRef?.pathToNode,
|
2024-06-29 10:36:04 -07:00
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
|
|
|
if (err(varDec)) return varDec
|
|
|
|
if (
|
2024-12-20 16:19:59 -05:00
|
|
|
((selection?.artifact?.type === 'wall' ||
|
2024-11-21 15:04:30 +11:00
|
|
|
selection?.artifact?.type === 'cap') &&
|
2024-12-20 16:19:59 -05:00
|
|
|
varDec.node.init.type === 'PipeExpression') ||
|
2025-01-09 15:36:50 -05:00
|
|
|
selection.artifact?.type === 'sweep' ||
|
|
|
|
selection.artifact?.type === 'plane' ||
|
|
|
|
!selection.artifact // aka expected to be a shell at this point
|
2024-06-29 10:36:04 -07:00
|
|
|
) {
|
|
|
|
let extrudeNameToDelete = ''
|
2024-12-20 16:19:59 -05:00
|
|
|
let pathToNode: PathToNode | null = null
|
2025-01-09 15:36:50 -05:00
|
|
|
if (
|
|
|
|
selection.artifact &&
|
|
|
|
selection.artifact.type !== 'sweep' &&
|
|
|
|
selection.artifact.type !== 'plane'
|
|
|
|
) {
|
2024-12-20 16:19:59 -05:00
|
|
|
const varDecName = varDec.node.id.name
|
|
|
|
traverse(astClone, {
|
|
|
|
enter: (node, path) => {
|
|
|
|
if (node.type === 'VariableDeclaration') {
|
|
|
|
const dec = node.declaration
|
|
|
|
if (
|
|
|
|
dec.init.type === 'CallExpression' &&
|
|
|
|
(dec.init.callee.name === 'extrude' ||
|
|
|
|
dec.init.callee.name === 'revolve') &&
|
|
|
|
dec.init.arguments?.[1].type === 'Identifier' &&
|
|
|
|
dec.init.arguments?.[1].name === varDecName
|
|
|
|
) {
|
|
|
|
pathToNode = path
|
|
|
|
extrudeNameToDelete = dec.id.name
|
|
|
|
}
|
2025-01-09 15:36:50 -05:00
|
|
|
if (
|
|
|
|
dec.init.type === 'CallExpression' &&
|
|
|
|
dec.init.callee.name === 'loft' &&
|
|
|
|
dec.init.arguments?.[0].type === 'ArrayExpression' &&
|
|
|
|
dec.init.arguments?.[0].elements.some(
|
|
|
|
(a) => a.type === 'Identifier' && a.name === varDecName
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
pathToNode = path
|
|
|
|
extrudeNameToDelete = dec.id.name
|
|
|
|
}
|
2024-06-29 10:36:04 -07:00
|
|
|
}
|
2024-12-20 16:19:59 -05:00
|
|
|
},
|
|
|
|
})
|
|
|
|
if (!pathToNode) return new Error('Could not find extrude variable')
|
|
|
|
} else {
|
|
|
|
pathToNode = selection.codeRef.pathToNode
|
|
|
|
const extrudeVarDec = getNodeFromPath<VariableDeclarator>(
|
|
|
|
astClone,
|
|
|
|
pathToNode,
|
|
|
|
'VariableDeclarator'
|
|
|
|
)
|
|
|
|
if (err(extrudeVarDec)) return extrudeVarDec
|
|
|
|
extrudeNameToDelete = extrudeVarDec.node.id.name
|
|
|
|
}
|
2024-06-29 10:36:04 -07:00
|
|
|
|
|
|
|
const expressionIndex = pathToNode[1][0] as number
|
|
|
|
astClone.body.splice(expressionIndex, 1)
|
|
|
|
if (extrudeNameToDelete) {
|
2024-09-09 18:17:45 -04:00
|
|
|
await new Promise((resolve) => {
|
|
|
|
;(async () => {
|
|
|
|
let currentVariableName = ''
|
|
|
|
const pathsDependingOnExtrude: Array<{
|
|
|
|
path: PathToNode
|
|
|
|
sketchName: string
|
|
|
|
}> = []
|
|
|
|
traverse(astClone, {
|
|
|
|
leave: (node) => {
|
|
|
|
if (node.type === 'VariableDeclaration') {
|
|
|
|
currentVariableName = ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
enter: (node, path) => {
|
|
|
|
;(async () => {
|
|
|
|
if (node.type === 'VariableDeclaration') {
|
2024-12-07 07:16:04 +13:00
|
|
|
currentVariableName = node.declaration.id.name
|
2024-09-09 18:17:45 -04:00
|
|
|
}
|
|
|
|
if (
|
|
|
|
// match startSketchOn(${extrudeNameToDelete})
|
|
|
|
node.type === 'CallExpression' &&
|
|
|
|
node.callee.name === 'startSketchOn' &&
|
|
|
|
node.arguments[0].type === 'Identifier' &&
|
|
|
|
node.arguments[0].name === extrudeNameToDelete
|
|
|
|
) {
|
|
|
|
pathsDependingOnExtrude.push({
|
|
|
|
path,
|
|
|
|
sketchName: currentVariableName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})().catch(reportRejection)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
const roundLiteral = (x: number) => createLiteral(roundOff(x))
|
|
|
|
const modificationDetails: {
|
|
|
|
parent: PipeExpression['body']
|
|
|
|
faceDetails: Models['FaceIsPlanar_type']
|
|
|
|
lastKey: number
|
|
|
|
}[] = []
|
|
|
|
for (const { path, sketchName } of pathsDependingOnExtrude) {
|
|
|
|
const parent = getNodeFromPath<PipeExpression['body']>(
|
|
|
|
astClone,
|
|
|
|
path.slice(0, -1)
|
|
|
|
)
|
|
|
|
if (err(parent)) {
|
|
|
|
return
|
2024-06-29 10:36:04 -07:00
|
|
|
}
|
2024-09-27 15:44:44 -07:00
|
|
|
const sketchToPreserve = sketchFromKclValue(
|
2024-09-09 18:17:45 -04:00
|
|
|
programMemory.get(sketchName),
|
|
|
|
sketchName
|
|
|
|
)
|
|
|
|
if (err(sketchToPreserve)) return sketchToPreserve
|
|
|
|
// Can't kick off multiple requests at once as getFaceDetails
|
|
|
|
// is three engine calls in one and they conflict
|
|
|
|
const faceDetails = await getFaceDetails(sketchToPreserve.on.id)
|
2024-06-29 10:36:04 -07:00
|
|
|
if (
|
2024-09-09 18:17:45 -04:00
|
|
|
!(
|
|
|
|
faceDetails.origin &&
|
|
|
|
faceDetails.x_axis &&
|
|
|
|
faceDetails.y_axis &&
|
|
|
|
faceDetails.z_axis
|
|
|
|
)
|
2024-06-29 10:36:04 -07:00
|
|
|
) {
|
2024-09-09 18:17:45 -04:00
|
|
|
return
|
2024-06-29 10:36:04 -07:00
|
|
|
}
|
2024-09-09 18:17:45 -04:00
|
|
|
const lastKey = Number(path.slice(-1)[0][0])
|
|
|
|
modificationDetails.push({
|
|
|
|
parent: parent.node,
|
|
|
|
faceDetails,
|
|
|
|
lastKey,
|
|
|
|
})
|
2024-06-29 10:36:04 -07:00
|
|
|
}
|
2024-09-09 18:17:45 -04:00
|
|
|
for (const { parent, faceDetails, lastKey } of modificationDetails) {
|
|
|
|
if (
|
|
|
|
!(
|
|
|
|
faceDetails.origin &&
|
|
|
|
faceDetails.x_axis &&
|
|
|
|
faceDetails.y_axis &&
|
|
|
|
faceDetails.z_axis
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
parent[lastKey] = createCallExpressionStdLib('startSketchOn', [
|
|
|
|
createObjectExpression({
|
|
|
|
plane: createObjectExpression({
|
|
|
|
origin: createObjectExpression({
|
|
|
|
x: roundLiteral(faceDetails.origin.x),
|
|
|
|
y: roundLiteral(faceDetails.origin.y),
|
|
|
|
z: roundLiteral(faceDetails.origin.z),
|
|
|
|
}),
|
2025-01-07 19:10:53 -08:00
|
|
|
xAxis: createObjectExpression({
|
2024-09-09 18:17:45 -04:00
|
|
|
x: roundLiteral(faceDetails.x_axis.x),
|
|
|
|
y: roundLiteral(faceDetails.x_axis.y),
|
|
|
|
z: roundLiteral(faceDetails.x_axis.z),
|
|
|
|
}),
|
2025-01-07 19:10:53 -08:00
|
|
|
yAxis: createObjectExpression({
|
2024-09-09 18:17:45 -04:00
|
|
|
x: roundLiteral(faceDetails.y_axis.x),
|
|
|
|
y: roundLiteral(faceDetails.y_axis.y),
|
|
|
|
z: roundLiteral(faceDetails.y_axis.z),
|
|
|
|
}),
|
2025-01-07 19:10:53 -08:00
|
|
|
zAxis: createObjectExpression({
|
2024-09-09 18:17:45 -04:00
|
|
|
x: roundLiteral(faceDetails.z_axis.x),
|
|
|
|
y: roundLiteral(faceDetails.z_axis.y),
|
|
|
|
z: roundLiteral(faceDetails.z_axis.z),
|
|
|
|
}),
|
2024-06-29 10:36:04 -07:00
|
|
|
}),
|
|
|
|
}),
|
2024-09-09 18:17:45 -04:00
|
|
|
])
|
|
|
|
}
|
|
|
|
resolve(true)
|
|
|
|
})().catch(reportRejection)
|
2024-06-29 10:36:04 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
// await prom
|
|
|
|
return astClone
|
|
|
|
} else if (varDec.node.init.type === 'PipeExpression') {
|
|
|
|
const pipeBody = varDec.node.init.body
|
|
|
|
if (
|
|
|
|
pipeBody[0].type === 'CallExpression' &&
|
2024-12-16 10:34:11 -05:00
|
|
|
pipeBody[0].callee.name === 'startSketchOn'
|
2024-06-29 10:36:04 -07:00
|
|
|
) {
|
|
|
|
// remove varDec
|
|
|
|
const varDecIndex = varDec.shallowPath[1][0] as number
|
|
|
|
astClone.body.splice(varDecIndex, 1)
|
|
|
|
return astClone
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Error('Selection not recognised, could not delete')
|
|
|
|
}
|
2024-08-22 13:54:59 -05:00
|
|
|
|
|
|
|
const nonCodeMetaEmpty = () => {
|
2024-10-30 16:52:17 -04:00
|
|
|
return { nonCodeNodes: {}, startNodes: [], start: 0, end: 0 }
|
2024-08-22 13:54:59 -05:00
|
|
|
}
|