Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compat/deprecations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ namespace ts {
}, factoryDeprecation);

/** @deprecated Use `factory.createJSDocParameterTag` or the factory supplied by your transformation context instead. */
export const createJSDocParamTag = Debug.deprecate(function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
export const createJSDocParamTag = Debug.deprecate(function createJSDocParamTag(name: EntityNameNoRootLiteral, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
return factory.createJSDocParameterTag(/*tagName*/ undefined, name, isBracketed, typeExpression, /*isNameFirst*/ false, comment);
}, factoryDeprecation);

Expand Down
142 changes: 69 additions & 73 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4218,7 +4218,7 @@ namespace ts {
}

// @api
function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocParameterTag {
function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityNameNoRootLiteral, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocParameterTag {
const node = createBaseJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, tagName ?? createIdentifier("param"), comment);
node.typeExpression = typeExpression;
node.name = name;
Expand All @@ -4228,7 +4228,7 @@ namespace ts {
}

// @api
function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocParameterTag {
function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityNameNoRootLiteral, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocParameterTag {
return node.tagName !== tagName
|| node.name !== name
|| node.isBracketed !== isBracketed
Expand All @@ -4240,7 +4240,7 @@ namespace ts {
}

// @api
function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocPropertyTag {
function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityNameNoRootLiteral, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocPropertyTag {
const node = createBaseJSDocTag<JSDocPropertyTag>(SyntaxKind.JSDocPropertyTag, tagName ?? createIdentifier("prop"), comment);
node.typeExpression = typeExpression;
node.name = name;
Expand All @@ -4250,7 +4250,7 @@ namespace ts {
}

// @api
function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocPropertyTag {
function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityNameNoRootLiteral, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocPropertyTag {
return node.tagName !== tagName
|| node.name !== name
|| node.isBracketed !== isBracketed
Expand Down
8 changes: 3 additions & 5 deletions src/compiler/factory/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ namespace ts {
function createJsxFactoryExpressionFromEntityName(factory: NodeFactory, jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression {
if (isQualifiedName(jsxFactory)) {
const left = createJsxFactoryExpressionFromEntityName(factory, jsxFactory.left, parent);
const right = factory.createIdentifier(idText(jsxFactory.right)) as Mutable<Identifier>;
right.escapedText = jsxFactory.right.escapedText;
return factory.createPropertyAccessExpression(left, right);
return isStringLiteralLike(jsxFactory.right) ? factory.createElementAccessExpression(left, factory.createStringLiteral(jsxFactory.right.text)) : factory.createPropertyAccessExpression(left, factory.createIdentifier(idText(jsxFactory.right)));
}
else {
return createReactNamespace(idText(jsxFactory), parent);
return createReactNamespace(qualifiedNameText(jsxFactory), parent);
}
}

Expand Down Expand Up @@ -162,7 +160,7 @@ namespace ts {
const left = createExpressionFromEntityName(factory, node.left);
// TODO(rbuckton): Does this need to be parented?
const right = setParent(setTextRange(factory.cloneNode(node.right), node.right), node.right.parent);
return setTextRange(factory.createPropertyAccessExpression(left, right), node);
return setTextRange(isStringLiteralLike(right) ? factory.createElementAccessExpression(left, right) : factory.createPropertyAccessExpression(left, right), node);
}
else {
// TODO(rbuckton): Does this need to be parented?
Expand Down
39 changes: 24 additions & 15 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2503,21 +2503,23 @@ namespace ts {
return createMissingList<T>();
}

function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
function parseEntityName(allowReservedWords: boolean, allowLeadingLiteral?: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
const pos = getNodePos();
let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
let entity: EntityName = (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NoSubstitutionTemplateLiteral) && allowLeadingLiteral ? parseLiteralLikeNode(token()) as StringLiteralLike : allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
let dotPos = getNodePos();
while (parseOptional(SyntaxKind.DotToken)) {
if (token() === SyntaxKind.LessThanToken) {
// the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
entity.jsdocDotPos = dotPos;
// the entity is part of a JSDoc-style generic, so report an error
if (!(contextFlags & NodeFlags.JSDoc)) {
parseErrorAt(dotPos, dotPos + 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
break;
}
dotPos = getNodePos();
entity = finishNode(
factory.createQualifiedName(
entity,
parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier
parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false, /*allowStringLike*/ true)
),
pos
);
Expand All @@ -2529,7 +2531,10 @@ namespace ts {
return finishNode(factory.createQualifiedName(entity, name), entity.pos);
}

function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier {
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: true): Identifier | PrivateIdentifier;
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: false): Identifier;
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: false, allowStringLike: true): Identifier | StringLiteralLike;
function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean, allowStringLike?: boolean): Identifier | PrivateIdentifier | StringLiteralLike {
// Technically a keyword is valid here as all identifiers and keywords are identifier names.
// However, often we'll encounter this in error situations when the identifier or keyword
// is actually starting another valid construct.
Expand Down Expand Up @@ -2565,6 +2570,10 @@ namespace ts {
return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
}

if (allowStringLike && token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NoSubstitutionTemplateLiteral) {
return parseLiteralLikeNode(token()) as StringLiteralLike;
}

return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
}

Expand Down Expand Up @@ -2701,8 +2710,8 @@ namespace ts {

// TYPES

function parseEntityNameOfTypeReference() {
return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
function parseEntityNameOfTypeReference(allowLeadingLiteral?: boolean) {
return parseEntityName(/*allowReservedWords*/ true, allowLeadingLiteral, Diagnostics.Type_expected);
}

function parseTypeArgumentsOfTypeReference() {
Expand Down Expand Up @@ -3413,7 +3422,7 @@ namespace ts {
parseExpected(SyntaxKind.OpenParenToken);
const type = parseType();
parseExpected(SyntaxKind.CloseParenToken);
const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined;
const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference(/*allowLeadingLiteral*/ true) : undefined;
const typeArguments = parseTypeArgumentsOfTypeReference();
return finishNode(factory.createImportTypeNode(type, qualifier, typeArguments, isTypeOf), pos);
}
Expand Down Expand Up @@ -7630,7 +7639,7 @@ namespace ts {
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
}

function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
function parseBracketNameInPropertyAndParamTag(): { name: EntityNameNoRootLiteral, isBracketed: boolean } {
// Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
if (isBracketed) {
Expand Down Expand Up @@ -7965,16 +7974,16 @@ namespace ts {
}

function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
while (isQualifiedName(a) || isQualifiedName(b)) {
if (isQualifiedName(a) && isQualifiedName(b) && qualifiedNameTextRaw(a.right) === qualifiedNameTextRaw(b.right)) {
a = a.left;
b = b.left;
}
else {
return false;
}
}
return a.escapedText === b.escapedText;
return qualifiedNameTextRaw(a) === qualifiedNameTextRaw(b);
}

function parseChildPropertyTag(indent: number) {
Expand Down Expand Up @@ -8089,8 +8098,8 @@ namespace ts {
return false;
}

function parseJSDocEntityName(): EntityName {
let entity: EntityName = parseJSDocIdentifierName();
function parseJSDocEntityName(): EntityNameNoRootLiteral {
let entity: EntityNameNoRootLiteral = parseJSDocIdentifierName();
if (parseOptional(SyntaxKind.OpenBracketToken)) {
parseExpected(SyntaxKind.CloseBracketToken);
// Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
Expand Down
15 changes: 12 additions & 3 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ namespace ts {
return false;
}

type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression;
type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression | ElementAccessExpression;
type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression;

function getAccessorTypeNode(node: AccessorDeclaration) {
Expand Down Expand Up @@ -1730,6 +1730,9 @@ namespace ts {
const copied = serializeEntityNameAsExpression(node);
return createCheckedValue(copied, copied);
}
if (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral) {
return Debug.failBadSyntaxKind(node);
}
if (node.left.kind === SyntaxKind.Identifier) {
// A.B -> typeof A !== undefined && A.B
return createCheckedValue(serializeEntityNameAsExpression(node.left), serializeEntityNameAsExpression(node));
Expand All @@ -1742,7 +1745,7 @@ namespace ts {
left.left,
factory.createStrictInequality(factory.createAssignment(temp, left.right), factory.createVoidZero())
),
factory.createPropertyAccessExpression(temp, node.right)
isStringLiteralLike(node.right) ? factory.createElementAccessExpression(temp, factory.createStringLiteral(node.right.text)) : factory.createPropertyAccessExpression(temp, node.right)
);
}

Expand All @@ -1763,6 +1766,10 @@ namespace ts {

case SyntaxKind.QualifiedName:
return serializeQualifiedNameAsExpression(node);

case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
return Debug.failBadSyntaxKind(node);
}
}

Expand All @@ -1774,7 +1781,9 @@ namespace ts {
* qualified name at runtime.
*/
function serializeQualifiedNameAsExpression(node: QualifiedName): SerializedEntityNameAsExpression {
return factory.createPropertyAccessExpression(serializeEntityNameAsExpression(node.left), node.right);
return isStringLiteralLike(node.right)
? factory.createElementAccessExpression(serializeEntityNameAsExpression(node.left), factory.createStringLiteral(node.right.text))
: factory.createPropertyAccessExpression(serializeEntityNameAsExpression(node.left), node.right);
}

/**
Expand Down
Loading