defineVueVisitor(context, visitor) {
    /** @type {VueObjectData | null} */
    let vueStack = null

    /**
     * @param {string} key
     * @param {ESNode} node
     */
    function callVisitor(key, node) {
      if (visitor[key] && vueStack) {
        // @ts-expect-error
        visitor[key](node, vueStack)
      }
    }

    /** @type {NodeListener} */
    const vueVisitor = {}
    for (const key in visitor) {
      vueVisitor[key] = (node) => callVisitor(key, node)
    }

    /**
     * @param {ObjectExpression} node
     */
    vueVisitor.ObjectExpression = (node) => {
      const type = getVueObjectType(context, node)
      if (type) {
        vueStack = {
          node,
          type,
          parent: vueStack,
          get functional() {
            const functional = node.properties.find(
              /**
               * @param {Property | SpreadElement} p
               * @returns {p is Property}
               */
              (p) =>
                p.type === 'Property' &&
                getStaticPropertyName(p) === 'functional'
            )
            if (!functional) {
              return false
            }
            if (
              functional.value.type === 'Literal' &&
              functional.value.value === false
            ) {
              return false
            }
            return true
          }
        }
        callVisitor('onVueObjectEnter', node)
      }
      callVisitor('ObjectExpression', node)
    }
    vueVisitor['ObjectExpression:exit'] = (node) => {
      callVisitor('ObjectExpression:exit', node)
      if (vueStack && vueStack.node === node) {
        callVisitor('onVueObjectExit', node)
        vueStack = vueStack.parent
      }
    }
    if (
      visitor.onSetupFunctionEnter ||
      visitor.onSetupFunctionExit ||
      visitor.onRenderFunctionEnter
    ) {
      const setups = new Set()
      /** @param { (FunctionExpression | ArrowFunctionExpression) & { parent: Property } } node */
      vueVisitor[
        'Property[value.type=/^(Arrow)?FunctionExpression$/] > :function'
      ] = (node) => {
        /** @type {Property} */
        const prop = node.parent
        if (vueStack && prop.parent === vueStack.node && prop.value === node) {
          const name = getStaticPropertyName(prop)
          if (name === 'setup') {
            callVisitor('onSetupFunctionEnter', node)
            setups.add(node)
          } else if (name === 'render') {
            callVisitor('onRenderFunctionEnter', node)
          }
        }
        callVisitor(
          'Property[value.type=/^(Arrow)?FunctionExpression$/] > :function',
          node
        )
      }
      if (visitor.onSetupFunctionExit) {
        /** @param { (FunctionExpression | ArrowFunctionExpression) & { parent: Property } } node */
        vueVisitor[
          'Property[value.type=/^(Arrow)?FunctionExpression$/] > :function:exit'
        ] = (node) => {
          if (setups.has(node)) {
            callVisitor('onSetupFunctionExit', node)
            setups.delete(node)
          }
        }
      }
    }

    return vueVisitor
  }
Define handlers to traverse the Vue Objects.
Some special events are available to visitor.

- `onVueObjectEnter` ... Event when Vue Object is found.
- `onVueObjectExit` ... Event when Vue Object visit ends.
- `onSetupFunctionEnter` ... Event when setup function found.
- `onRenderFunctionEnter` ... Event when render function found.

@param {RuleContext} context The ESLint rule context object.
@param {VueVisitor} visitor The visitor to traverse the Vue Objects.