Stop throwing in frontend code (#2654)

Return error instead of throw
This commit is contained in:
49fl
2024-06-24 11:45:40 -04:00
committed by GitHub
parent f7196e7eb0
commit f4877cb160
67 changed files with 5127 additions and 4523 deletions

View File

@ -25,6 +25,7 @@ import {
getConstraintLevelFromSourceRange,
getConstraintType,
} from './std/sketchcombos'
import { err } from 'lib/trap'
/**
* Retrieves a node from a given path within a Program node structure, optionally stopping at a specified node type.
@ -38,49 +39,41 @@ export function getNodeFromPath<T>(
path: PathToNode,
stopAt?: SyntaxType | SyntaxType[],
returnEarly = false
): {
node: T
shallowPath: PathToNode
deepPath: PathToNode
} {
):
| {
node: T
shallowPath: PathToNode
deepPath: PathToNode
}
| Error {
let currentNode = node as any
let stopAtNode = null
let successfulPaths: PathToNode = []
let pathsExplored: PathToNode = []
for (const pathItem of path) {
try {
if (typeof currentNode[pathItem[0]] !== 'object')
throw new Error('not an object')
currentNode = currentNode?.[pathItem[0]]
successfulPaths.push(pathItem)
if (!stopAtNode) {
pathsExplored.push(pathItem)
}
if (
typeof stopAt !== 'undefined' &&
(Array.isArray(stopAt)
? stopAt.includes(currentNode.type)
: currentNode.type === stopAt)
) {
// it will match the deepest node of the type
// instead of returning at the first match
stopAtNode = currentNode
if (returnEarly) {
return {
node: stopAtNode,
shallowPath: pathsExplored,
deepPath: successfulPaths,
}
if (typeof currentNode[pathItem[0]] !== 'object')
return new Error('not an object')
currentNode = currentNode?.[pathItem[0]]
successfulPaths.push(pathItem)
if (!stopAtNode) {
pathsExplored.push(pathItem)
}
if (
typeof stopAt !== 'undefined' &&
(Array.isArray(stopAt)
? stopAt.includes(currentNode.type)
: currentNode.type === stopAt)
) {
// it will match the deepest node of the type
// instead of returning at the first match
stopAtNode = currentNode
if (returnEarly) {
return {
node: stopAtNode,
shallowPath: pathsExplored,
deepPath: successfulPaths,
}
}
} catch (e) {
// console.error(
// `Could not find path ${pathItem} in node ${JSON.stringify(
// currentNode,
// null,
// 2
// )}, successful path was ${successfulPaths}`
// )
}
}
return {
@ -99,17 +92,16 @@ export function getNodeFromPathCurry(
): <T>(
stopAt?: SyntaxType | SyntaxType[],
returnEarly?: boolean
) => {
node: T
path: PathToNode
} {
) =>
| {
node: T
path: PathToNode
}
| Error {
return <T>(stopAt?: SyntaxType | SyntaxType[], returnEarly = false) => {
const { node: _node, shallowPath } = getNodeFromPath<T>(
node,
path,
stopAt,
returnEarly
)
const _node1 = getNodeFromPath<T>(node, path, stopAt, returnEarly)
if (err(_node1)) return _node1
const { node: _node, shallowPath } = _node1
return {
node: _node,
path: shallowPath,
@ -374,17 +366,31 @@ export function findAllPreviousVariablesPath(
bodyPath: PathToNode
insertIndex: number
} {
const { shallowPath: pathToDec, node } = getNodeFromPath(
ast,
path,
'VariableDeclaration'
)
const _node1 = getNodeFromPath(ast, path, 'VariableDeclaration')
if (err(_node1)) {
console.error(_node1)
return {
variables: [],
bodyPath: [],
insertIndex: 0,
}
}
const { shallowPath: pathToDec, node } = _node1
const startRange = (node as any).start
const { index: insertIndex, path: bodyPath } = splitPathAtLastIndex(pathToDec)
const { node: bodyItems } = getNodeFromPath<Program['body']>(ast, bodyPath)
const _node2 = getNodeFromPath<Program['body']>(ast, bodyPath)
if (err(_node2)) {
console.error(_node2)
return {
variables: [],
bodyPath: [],
insertIndex: 0,
}
}
const { node: bodyItems } = _node2
const variables: PrevVariable<any>[] = []
bodyItems?.forEach?.((item) => {
@ -422,16 +428,18 @@ export function findAllPreviousVariables(
type ReplacerFn = (
_ast: Program,
varName: string
) => { modifiedAst: Program; pathToReplaced: PathToNode }
) => { modifiedAst: Program; pathToReplaced: PathToNode } | Error
export function isNodeSafeToReplacePath(
ast: Program,
path: PathToNode
): {
isSafe: boolean
value: Value
replacer: ReplacerFn
} {
):
| {
isSafe: boolean
value: Value
replacer: ReplacerFn
}
| Error {
if (path[path.length - 1][0] === 'callee') {
path = path.slice(0, -1)
}
@ -442,16 +450,14 @@ export function isNodeSafeToReplacePath(
'Literal',
'UnaryExpression',
]
const { node: value, deepPath: outPath } = getNodeFromPath(
ast,
path,
acceptedNodeTypes
)
const { node: binValue, shallowPath: outBinPath } = getNodeFromPath(
ast,
path,
'BinaryExpression'
)
const _node1 = getNodeFromPath(ast, path, acceptedNodeTypes)
if (err(_node1)) return _node1
const { node: value, deepPath: outPath } = _node1
const _node2 = getNodeFromPath(ast, path, 'BinaryExpression')
if (err(_node2)) return _node2
const { node: binValue, shallowPath: outBinPath } = _node2
// binaryExpression should take precedence
const [finVal, finPath] =
(binValue as Value)?.type === 'BinaryExpression'
@ -464,7 +470,9 @@ export function isNodeSafeToReplacePath(
const pathToReplaced = JSON.parse(JSON.stringify(finPath))
pathToReplaced[1][0] = pathToReplaced[1][0] + 1
const startPath = finPath.slice(0, -1)
const nodeToReplace = getNodeFromPath(_ast, startPath).node as any
const _nodeToReplace = getNodeFromPath(_ast, startPath)
if (err(_nodeToReplace)) return _nodeToReplace
const nodeToReplace = _nodeToReplace.node as any
nodeToReplace[last[0]] = identifier
return { modifiedAst: _ast, pathToReplaced }
}
@ -485,11 +493,13 @@ export function isNodeSafeToReplacePath(
export function isNodeSafeToReplace(
ast: Program,
sourceRange: [number, number]
): {
isSafe: boolean
value: Value
replacer: ReplacerFn
} {
):
| {
isSafe: boolean
value: Value
replacer: ReplacerFn
}
| Error {
let path = getNodePathFromSourceRange(ast, sourceRange)
return isNodeSafeToReplacePath(ast, path)
}
@ -546,28 +556,38 @@ export function isLinesParallelAndConstrained(
programMemory: ProgramMemory,
primaryLine: Selection,
secondaryLine: Selection
): {
isParallelAndConstrained: boolean
sourceRange: SourceRange
} {
):
| {
isParallelAndConstrained: boolean
sourceRange: SourceRange
}
| Error {
try {
const EPSILON = 0.005
const primaryPath = getNodePathFromSourceRange(ast, primaryLine.range)
const secondaryPath = getNodePathFromSourceRange(ast, secondaryLine.range)
const secondaryNode = getNodeFromPath<CallExpression>(
const _secondaryNode = getNodeFromPath<CallExpression>(
ast,
secondaryPath,
'CallExpression'
).node
const varDec = getNodeFromPath(ast, primaryPath, 'VariableDeclaration').node
)
if (err(_secondaryNode)) return _secondaryNode
const secondaryNode = _secondaryNode.node
const _varDec = getNodeFromPath(ast, primaryPath, 'VariableDeclaration')
if (err(_varDec)) return _varDec
const varDec = _varDec.node
const varName = (varDec as VariableDeclaration)?.declarations[0]?.id?.name
const path = programMemory?.root[varName] as SketchGroup
const primarySegment = getSketchSegmentFromSourceRange(
const _primarySegment = getSketchSegmentFromSourceRange(
path,
primaryLine.range
).segment
const { segment: secondarySegment, index: secondaryIndex } =
getSketchSegmentFromSourceRange(path, secondaryLine.range)
)
if (err(_primarySegment)) return _primarySegment
const primarySegment = _primarySegment.segment
const _segment = getSketchSegmentFromSourceRange(path, secondaryLine.range)
if (err(_segment)) return _segment
const { segment: secondarySegment, index: secondaryIndex } = _segment
const primaryAngle = getAngle(primarySegment.from, primarySegment.to)
const secondaryAngle = getAngle(secondarySegment.from, secondarySegment.to)
const secondaryAngleAlt = getAngle(
@ -580,14 +600,26 @@ export function isLinesParallelAndConstrained(
// is secordary line fully constrain, or has constrain type of 'angle'
const secondaryFirstArg = getFirstArg(secondaryNode)
if (err(secondaryFirstArg)) return secondaryFirstArg
const constraintType = getConstraintType(
secondaryFirstArg.val,
secondaryNode.callee.name as ToolTip
)
const constraintLevel = getConstraintLevelFromSourceRange(
const constraintLevelMeta = getConstraintLevelFromSourceRange(
secondaryLine.range,
ast
).level
)
if (err(constraintLevelMeta)) {
console.error(constraintLevelMeta)
return {
isParallelAndConstrained: false,
sourceRange: [0, 0],
}
}
const constraintLevel = constraintLevelMeta.level
const isConstrained =
constraintType === 'angle' || constraintLevel === 'full'
@ -622,11 +654,16 @@ export function doesPipeHaveCallExp({
selection: Selection
}): boolean {
const pathToNode = getNodePathFromSourceRange(ast, selection.range)
const pipeExpression = getNodeFromPath<PipeExpression>(
const pipeExpressionMeta = getNodeFromPath<PipeExpression>(
ast,
pathToNode,
'PipeExpression'
).node
)
if (err(pipeExpressionMeta)) {
console.error(pipeExpressionMeta)
return false
}
const pipeExpression = pipeExpressionMeta.node
if (pipeExpression.type !== 'PipeExpression') return false
return pipeExpression.body.some(
(expression) =>
@ -645,11 +682,16 @@ export function hasExtrudeSketchGroup({
programMemory: ProgramMemory
}): boolean {
const pathToNode = getNodePathFromSourceRange(ast, selection.range)
const varDec = getNodeFromPath<VariableDeclaration>(
const varDecMeta = getNodeFromPath<VariableDeclaration>(
ast,
pathToNode,
'VariableDeclaration'
).node
)
if (err(varDecMeta)) {
console.error(varDecMeta)
return false
}
const varDec = varDecMeta.node
if (varDec.type !== 'VariableDeclaration') return false
const varName = varDec.declarations[0].id.name
const varValue = programMemory?.root[varName]
@ -679,11 +721,16 @@ export function findUsesOfTagInPipe(
'segEndY',
'segLen',
]
const node = getNodeFromPath<CallExpression>(
const nodeMeta = getNodeFromPath<CallExpression>(
ast,
pathToNode,
'CallExpression'
).node
)
if (err(nodeMeta)) {
console.error(nodeMeta)
return []
}
const node = nodeMeta.node
if (node.type !== 'CallExpression') return []
const tagIndex = node.callee.name === 'close' ? 1 : 2
const thirdParam = node.arguments[tagIndex]
@ -694,10 +741,14 @@ export function findUsesOfTagInPipe(
ast,
pathToNode,
'VariableDeclaration'
).node
)
if (err(varDec)) {
console.error(varDec)
return []
}
const dependentRanges: SourceRange[] = []
traverse(varDec, {
traverse(varDec.node, {
enter: (node) => {
if (
node.type !== 'CallExpression' ||
@ -715,17 +766,17 @@ export function findUsesOfTagInPipe(
export function hasSketchPipeBeenExtruded(selection: Selection, ast: Program) {
const path = getNodePathFromSourceRange(ast, selection.range)
const { node: pipeExpression } = getNodeFromPath<PipeExpression>(
ast,
path,
'PipeExpression'
)
const _node = getNodeFromPath<PipeExpression>(ast, path, 'PipeExpression')
if (err(_node)) return false
const { node: pipeExpression } = _node
if (pipeExpression.type !== 'PipeExpression') return false
const varDec = getNodeFromPath<VariableDeclarator>(
const _varDec = getNodeFromPath<VariableDeclarator>(
ast,
path,
'VariableDeclarator'
).node
)
if (err(_varDec)) return false
const varDec = _varDec.node
let extruded = false
traverse(ast as any, {
enter(node) {