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);
}