Fix crash while editing code while in sketch mode (#7284)
* Fix crash by checking bounds * Add unit test
This commit is contained in:
		@ -245,6 +245,38 @@ ${insertCode}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
describe('testing getConstraintInfo', () => {
 | 
			
		||||
  describe('when user edits KCL to be invalid', () => {
 | 
			
		||||
    const code = `part001 = startSketchOn(XZ)
 | 
			
		||||
  |> startProfile(at = [0,]) // Missing y coordinate
 | 
			
		||||
  |> line(end = [3, 4])`
 | 
			
		||||
    test.each([
 | 
			
		||||
      [
 | 
			
		||||
        'startProfile',
 | 
			
		||||
        [
 | 
			
		||||
          // No constraints
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
    ])('testing %s when inputs are unconstrained', (functionName, expected) => {
 | 
			
		||||
      const ast = assertParse(code)
 | 
			
		||||
      const match = new RegExp(functionName).exec(code)
 | 
			
		||||
      expect(match).toBeTruthy()
 | 
			
		||||
      if (match === null) {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      const start = code.indexOf(match[0])
 | 
			
		||||
      expect(start).toBeGreaterThanOrEqual(0)
 | 
			
		||||
      const sourceRange = topLevelRange(start, start + functionName.length)
 | 
			
		||||
      if (err(ast)) return ast
 | 
			
		||||
      const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
 | 
			
		||||
      const callExp = getNodeFromPath<Node<CallExpressionKw>>(ast, pathToNode, [
 | 
			
		||||
        'CallExpressionKw',
 | 
			
		||||
      ])
 | 
			
		||||
      if (err(callExp)) return callExp
 | 
			
		||||
      const result = getConstraintInfoKw(callExp.node, code, pathToNode)
 | 
			
		||||
      expect(result).toEqual(expected)
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  describe('object notation', () => {
 | 
			
		||||
    const code = `part001 = startSketchOn(-XZ)
 | 
			
		||||
  |> startProfile(at = [0,0])
 | 
			
		||||
 | 
			
		||||
@ -1183,7 +1183,7 @@ export const startProfile: SketchLineHelperKw = {
 | 
			
		||||
      return []
 | 
			
		||||
    }
 | 
			
		||||
    const argIndex = findKwArgAnyIndex([ARG_AT], callExp)
 | 
			
		||||
    if (argIndex === undefined) {
 | 
			
		||||
    if (argIndex === undefined || expr.elements.length < 2) {
 | 
			
		||||
      return []
 | 
			
		||||
    }
 | 
			
		||||
    const pathToXYArray: PathToNode = [
 | 
			
		||||
@ -1471,7 +1471,9 @@ export const circle: SketchLineHelperKw = {
 | 
			
		||||
          key: ARG_RADIUS,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
    ]
 | 
			
		||||
    if (centerInfo.expr.elements.length >= 2) {
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circle',
 | 
			
		||||
        type: 'xAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(centerInfo.expr.elements[0]),
 | 
			
		||||
@ -1489,8 +1491,8 @@ export const circle: SketchLineHelperKw = {
 | 
			
		||||
          index: 0,
 | 
			
		||||
          key: ARG_CIRCLE_CENTER,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circle',
 | 
			
		||||
        type: 'yAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(centerInfo.expr.elements[1]),
 | 
			
		||||
@ -1508,8 +1510,8 @@ export const circle: SketchLineHelperKw = {
 | 
			
		||||
          index: 1,
 | 
			
		||||
          key: 'center',
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    ]
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    return constraints
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
@ -2256,134 +2258,103 @@ export const circleThreePoint: SketchLineHelperKw = {
 | 
			
		||||
    const pathToP3XArg: PathToNode = [...pathToP3ArrayExpression, [0, 'index']]
 | 
			
		||||
    const pathToP3YArg: PathToNode = [...pathToP3ArrayExpression, [1, 'index']]
 | 
			
		||||
 | 
			
		||||
    const constraints: (ConstrainInfo & { filterValue: string })[] = [
 | 
			
		||||
      {
 | 
			
		||||
    const constraints: (ConstrainInfo & { filterValue: string })[] = []
 | 
			
		||||
    if (p1Details.expr.elements.length >= 2) {
 | 
			
		||||
      const p1XArg = p1Details.expr.elements[0]
 | 
			
		||||
      const p1YArg = p1Details.expr.elements[1]
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'xAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[0]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p1Details.expr.elements[0].start,
 | 
			
		||||
          p1Details.expr.elements[0].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p1XArg),
 | 
			
		||||
        sourceRange: topLevelRange(p1XArg.start, p1XArg.end),
 | 
			
		||||
        pathToNode: pathToP1XArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p1Details.expr.elements[0].start,
 | 
			
		||||
          p1Details.expr.elements[0].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p1XArg.start, p1XArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 0,
 | 
			
		||||
          key: 'p1',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p1',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'yAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p1Details.expr.elements[1]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p1Details.expr.elements[1].start,
 | 
			
		||||
          p1Details.expr.elements[1].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p1YArg),
 | 
			
		||||
        sourceRange: topLevelRange(p1YArg.start, p1YArg.end),
 | 
			
		||||
        pathToNode: pathToP1YArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p1Details.expr.elements[1].start,
 | 
			
		||||
          p1Details.expr.elements[1].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p1YArg.start, p1YArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 1,
 | 
			
		||||
          key: 'p1',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p1',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    if (p2Details.expr.elements.length >= 2) {
 | 
			
		||||
      const p2XArg = p2Details.expr.elements[0]
 | 
			
		||||
      const p2YArg = p2Details.expr.elements[1]
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'xAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[0]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p2Details.expr.elements[0].start,
 | 
			
		||||
          p2Details.expr.elements[0].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p2XArg),
 | 
			
		||||
        sourceRange: topLevelRange(p2XArg.start, p2XArg.end),
 | 
			
		||||
        pathToNode: pathToP2XArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p2Details.expr.elements[0].start,
 | 
			
		||||
          p2Details.expr.elements[0].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p2XArg.start, p2XArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 0,
 | 
			
		||||
          key: 'p2',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p2',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'yAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p2Details.expr.elements[1]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p2Details.expr.elements[1].start,
 | 
			
		||||
          p2Details.expr.elements[1].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p2YArg),
 | 
			
		||||
        sourceRange: topLevelRange(p2YArg.start, p2YArg.end),
 | 
			
		||||
        pathToNode: pathToP2YArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p2Details.expr.elements[1].start,
 | 
			
		||||
          p2Details.expr.elements[1].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p2YArg.start, p2YArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 1,
 | 
			
		||||
          key: 'p2',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p2',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    if (p3Details.expr.elements.length >= 2) {
 | 
			
		||||
      const p3XArg = p3Details.expr.elements[0]
 | 
			
		||||
      const p3YArg = p3Details.expr.elements[1]
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'xAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[0]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p3Details.expr.elements[0].start,
 | 
			
		||||
          p3Details.expr.elements[0].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p3XArg),
 | 
			
		||||
        sourceRange: topLevelRange(p3XArg.start, p3XArg.end),
 | 
			
		||||
        pathToNode: pathToP3XArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p3Details.expr.elements[0].start,
 | 
			
		||||
          p3Details.expr.elements[0].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p3XArg.start, p3XArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 0,
 | 
			
		||||
          key: 'p3',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p3',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
      })
 | 
			
		||||
      constraints.push({
 | 
			
		||||
        stdLibFnName: 'circleThreePoint',
 | 
			
		||||
        type: 'yAbsolute',
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p3Details.expr.elements[1]),
 | 
			
		||||
        sourceRange: [
 | 
			
		||||
          p3Details.expr.elements[1].start,
 | 
			
		||||
          p3Details.expr.elements[1].end,
 | 
			
		||||
          0,
 | 
			
		||||
        ],
 | 
			
		||||
        isConstrained: isNotLiteralArrayOrStatic(p3YArg),
 | 
			
		||||
        sourceRange: topLevelRange(p3YArg.start, p3YArg.end),
 | 
			
		||||
        pathToNode: pathToP3YArg,
 | 
			
		||||
        value: code.slice(
 | 
			
		||||
          p3Details.expr.elements[1].start,
 | 
			
		||||
          p3Details.expr.elements[1].end
 | 
			
		||||
        ),
 | 
			
		||||
        value: code.slice(p3YArg.start, p3YArg.end),
 | 
			
		||||
        argPosition: {
 | 
			
		||||
          type: 'labeledArgArrayItem',
 | 
			
		||||
          index: 1,
 | 
			
		||||
          key: 'p3',
 | 
			
		||||
        },
 | 
			
		||||
        filterValue: 'p3',
 | 
			
		||||
      },
 | 
			
		||||
    ]
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    const finalConstraints: ConstrainInfo[] = []
 | 
			
		||||
    constraints.forEach((constraint) => {
 | 
			
		||||
      if (!filterValue) {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user