Repository: babel/babel
File: packages/babel-parser/src/plugins/estree.ts (TypeScript)

Code before:
              this.resetStartLocation(
                node,
                // For compatibility with ESLint's keyword-spacing rule, which assumes that an
                // export declaration must start with export.
                // https://github.com/babel/babel/issues/15085
                // Here we reset export declaration's start to be the start of the export token
                exportStartLoc,
              );
            }
          }

          break;
      }

      return node;
    }

    stopParseSubscript(base: N.Expression, state: N.ParseSubscriptState) {
      const node = super.stopParseSubscript(base, state);
      if (state.optionalChainMember) {
        // Todo: refactor TSInstantiationExpression parsing such that
        // ChainExpression is created before TSInstantiationExpression
        if (node.type === "TSInstantiationExpression") {
          node.expression = this.estreeParseChainExpression(node.expression);
          if (process.env.BABEL_8_BREAKING) {
            this.resetEndLocation(
              node.expression,
              node.typeArguments.loc.start,
            );
          } else {
            this.resetEndLocation(
              node.expression,
              node.typeParameters.loc.start,
            );
          }
        } else {
          return this.estreeParseChainExpression(node);
        }
      }
      return node;
    }

    parseMember(
      base: N.Expression,
      startLoc: Position,
      state: N.ParseSubscriptState,
      computed: boolean,
      optional: boolean,
    ) {
      const node = super.parseMember(base, startLoc, state, computed, optional);
      if (node.type === "OptionalMemberExpression") {

Review comment (refactor):
This change is not sufficient, we have to fix the end location of the member expression as well. At this point it seems we have to refactor TSInstantiationExpression parsing anyway.

Code after:
              // decorator comes before export
              declaration.start === node.start
            ) {
              this.resetStartLocation(
                node,
                // For compatibility with ESLint's keyword-spacing rule, which assumes that an
                // export declaration must start with export.
                // https://github.com/babel/babel/issues/15085
                // Here we reset export declaration's start to be the start of the export token
                exportStartLoc,
              );
            }
          }

          break;
      }

      return node;
    }

    stopParseSubscript(base: N.Expression, state: N.ParseSubscriptState) {
      const node = super.stopParseSubscript(base, state);
      if (state.optionalChainMember) {
        return this.estreeParseChainExpression(node, base.loc.end);
      }
      return node;
    }

    parseMember(
      base: N.Expression,
      startLoc: Position,
      state: N.ParseSubscriptState,
      computed: boolean,
      optional: boolean,
    ) {
      const node = super.parseMember(base, startLoc, state, computed, optional);
      if (node.type === "OptionalMemberExpression") {
        this.castNodeTo(node, "MemberExpression");
      } else {
        node.optional = false;
      }
      return node;
    }

    isOptionalMemberExpression(node: N.Node) {
      if (node.type === "ChainExpression") {
        return node.expression.type === "MemberExpression";
      }
      return super.isOptionalMemberExpression(node);
    }