private _parseMemberReference()

in tsdoc/src/parser/NodeParser.ts [1501:1620]


  private _parseMemberReference(
    tokenReader: TokenReader,
    expectingDot: boolean,
    tokenSequenceForErrorContext: TokenSequence,
    nodeForErrorContext: DocNode
  ): DocMemberReference | undefined {
    const parameters: IDocMemberReferenceParsedParameters = {
      parsed: true,
      configuration: this._configuration
    };

    // Read the dot operator
    if (expectingDot) {
      if (tokenReader.peekTokenKind() !== TokenKind.Period) {
        this._parserContext.log.addMessageForTokenSequence(
          TSDocMessageId.ReferenceMissingDot,
          'Expecting a period before the next component of a declaration reference',
          tokenSequenceForErrorContext,
          nodeForErrorContext
        );
        return undefined;
      }
      tokenReader.readToken();
      parameters.dotExcerpt = tokenReader.extractAccumulatedSequence();

      parameters.spacingAfterDotExcerpt = this._tryReadSpacingAndNewlines(tokenReader);
    }

    // Read the left parenthesis if there is one
    if (tokenReader.peekTokenKind() === TokenKind.LeftParenthesis) {
      tokenReader.readToken();
      parameters.leftParenthesisExcerpt = tokenReader.extractAccumulatedSequence();

      parameters.spacingAfterLeftParenthesisExcerpt = this._tryReadSpacingAndNewlines(tokenReader);
    }

    // Read the member identifier or symbol
    if (tokenReader.peekTokenKind() === TokenKind.LeftSquareBracket) {
      parameters.memberSymbol = this._parseMemberSymbol(tokenReader, nodeForErrorContext);
      if (!parameters.memberSymbol) {
        return undefined;
      }
    } else {
      parameters.memberIdentifier = this._parseMemberIdentifier(
        tokenReader,
        tokenSequenceForErrorContext,
        nodeForErrorContext
      );

      if (!parameters.memberIdentifier) {
        return undefined;
      }
    }
    parameters.spacingAfterMemberExcerpt = this._tryReadSpacingAndNewlines(tokenReader);

    // Read the colon
    if (tokenReader.peekTokenKind() === TokenKind.Colon) {
      tokenReader.readToken();

      parameters.colonExcerpt = tokenReader.extractAccumulatedSequence();

      parameters.spacingAfterColonExcerpt = this._tryReadSpacingAndNewlines(tokenReader);

      if (!parameters.leftParenthesisExcerpt) {
        // In the current TSDoc draft standard, a member reference with a selector requires the parentheses.
        // It would be reasonable to make the parentheses optional, and we are contemplating simplifying the
        // notation in the future.  But for now the parentheses are required.
        this._parserContext.log.addMessageForTokenSequence(
          TSDocMessageId.ReferenceSelectorMissingParens,
          'Syntax error in declaration reference: the member selector must be enclosed in parentheses',
          parameters.colonExcerpt,
          nodeForErrorContext
        );
        return undefined;
      }

      // If there is a colon, then read the selector
      parameters.selector = this._parseMemberSelector(
        tokenReader,
        parameters.colonExcerpt,
        nodeForErrorContext
      );
      if (!parameters.selector) {
        return undefined;
      }

      parameters.spacingAfterSelectorExcerpt = this._tryReadSpacingAndNewlines(tokenReader);
    } else {
      if (parameters.leftParenthesisExcerpt) {
        this._parserContext.log.addMessageForTokenSequence(
          TSDocMessageId.ReferenceMissingColon,
          'Expecting a colon after the identifier because the expression is in parentheses',
          parameters.leftParenthesisExcerpt,
          nodeForErrorContext
        );
        return undefined;
      }
    }

    // Read the right parenthesis
    if (parameters.leftParenthesisExcerpt) {
      if (tokenReader.peekTokenKind() !== TokenKind.RightParenthesis) {
        this._parserContext.log.addMessageForTokenSequence(
          TSDocMessageId.ReferenceMissingRightParen,
          'Expecting a matching right parenthesis',
          parameters.leftParenthesisExcerpt,
          nodeForErrorContext
        );
        return undefined;
      }

      tokenReader.readToken();

      parameters.rightParenthesisExcerpt = tokenReader.extractAccumulatedSequence();

      parameters.spacingAfterRightParenthesisExcerpt = this._tryReadSpacingAndNewlines(tokenReader);
    }

    return new DocMemberReference(parameters);
  }