mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
JSX namespace names should not be considered expressions (#54104)
This commit is contained in:
+18
-5
@@ -776,6 +776,7 @@ import {
|
||||
JSDocVariadicType,
|
||||
JsxAttribute,
|
||||
JsxAttributeLike,
|
||||
JsxAttributeName,
|
||||
JsxAttributes,
|
||||
JsxChild,
|
||||
JsxClosingElement,
|
||||
@@ -17026,19 +17027,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(name: PropertyName) {
|
||||
function getLiteralTypeFromPropertyName(name: PropertyName | JsxAttributeName) {
|
||||
if (isPrivateIdentifier(name)) {
|
||||
return neverType;
|
||||
}
|
||||
return isIdentifier(name) ? getStringLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
|
||||
getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
|
||||
if (isNumericLiteral(name)) {
|
||||
return getRegularTypeOfLiteralType(checkExpression(name));
|
||||
}
|
||||
if (isComputedPropertyName(name)) {
|
||||
return getRegularTypeOfLiteralType(checkComputedPropertyName(name));
|
||||
}
|
||||
const propertyName = getPropertyNameForPropertyNameNode(name);
|
||||
if (propertyName !== undefined) {
|
||||
return getStringLiteralType(unescapeLeadingUnderscores(propertyName));
|
||||
}
|
||||
if (isExpression(name)) {
|
||||
return getRegularTypeOfLiteralType(checkExpression(name));
|
||||
}
|
||||
return neverType;
|
||||
}
|
||||
|
||||
function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags, includeNonPublic?: boolean) {
|
||||
if (includeNonPublic || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
|
||||
let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType;
|
||||
if (!type) {
|
||||
const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
|
||||
const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName | JsxAttributeName;
|
||||
type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") :
|
||||
name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined);
|
||||
}
|
||||
@@ -32647,7 +32660,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (getJsxNamespaceContainerForImplicitImport(node)) {
|
||||
return true; // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet)
|
||||
}
|
||||
const tagType = isJsxOpeningElement(node) || isJsxSelfClosingElement(node) && !isJsxIntrinsicTagName(node.tagName) ? checkExpression(node.tagName) : undefined;
|
||||
const tagType = (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) && !(isJsxIntrinsicTagName(node.tagName) || isJsxNamespacedName(node.tagName)) ? checkExpression(node.tagName) : undefined;
|
||||
if (!tagType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+11
-4
@@ -179,6 +179,7 @@ import {
|
||||
getSyntheticLeadingComments,
|
||||
getSyntheticTrailingComments,
|
||||
getTextOfJSDocComment,
|
||||
getTextOfJsxNamespacedName,
|
||||
getTrailingCommentRanges,
|
||||
getTrailingSemicolonDeferringWriter,
|
||||
getTransformers,
|
||||
@@ -228,6 +229,7 @@ import {
|
||||
isJSDocLikeText,
|
||||
isJsonSourceFile,
|
||||
isJsxClosingElement,
|
||||
isJsxNamespacedName,
|
||||
isJsxOpeningElement,
|
||||
isKeyword,
|
||||
isLet,
|
||||
@@ -2066,6 +2068,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
|
||||
return emitJsxSpreadAttribute(node as JsxSpreadAttribute);
|
||||
case SyntaxKind.JsxExpression:
|
||||
return emitJsxExpression(node as JsxExpression);
|
||||
case SyntaxKind.JsxNamespacedName:
|
||||
return emitJsxNamespacedName(node as JsxNamespacedName);
|
||||
|
||||
// Clauses
|
||||
case SyntaxKind.CaseClause:
|
||||
@@ -2283,8 +2287,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
|
||||
return emitJsxSelfClosingElement(node as JsxSelfClosingElement);
|
||||
case SyntaxKind.JsxFragment:
|
||||
return emitJsxFragment(node as JsxFragment);
|
||||
case SyntaxKind.JsxNamespacedName:
|
||||
return emitJsxNamespacedName(node as JsxNamespacedName);
|
||||
|
||||
// Synthesized list
|
||||
case SyntaxKind.SyntaxList:
|
||||
@@ -5528,7 +5530,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
|
||||
return node;
|
||||
}
|
||||
|
||||
function getTextOfNode(node: Identifier | PrivateIdentifier | LiteralExpression, includeTrivia?: boolean): string {
|
||||
function getTextOfNode(node: Identifier | PrivateIdentifier | LiteralExpression | JsxNamespacedName, includeTrivia?: boolean): string {
|
||||
if (isGeneratedIdentifier(node) || isGeneratedPrivateIdentifier(node)) {
|
||||
return generateName(node);
|
||||
}
|
||||
@@ -5542,6 +5544,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
|
||||
return idText(node);
|
||||
}
|
||||
}
|
||||
else if (isJsxNamespacedName(node)) {
|
||||
if (!canUseSourceFile || getSourceFileOfNode(node) !== getOriginalNode(sourceFile)) {
|
||||
return getTextOfJsxNamespacedName(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assertNode(node, isLiteralExpression); // not strictly necessary
|
||||
if (!canUseSourceFile) {
|
||||
@@ -5554,7 +5561,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
|
||||
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
|
||||
if (node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).textSourceNode) {
|
||||
const textSourceNode = (node as StringLiteral).textSourceNode!;
|
||||
if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode)) {
|
||||
if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode) || isJsxNamespacedName(textSourceNode)) {
|
||||
const text = isNumericLiteral(textSourceNode) ? textSourceNode.text : getTextOfNode(textSourceNode);
|
||||
return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` :
|
||||
neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(text)}"` :
|
||||
|
||||
@@ -147,6 +147,7 @@ import {
|
||||
isJSDocNullableType,
|
||||
isJSDocReturnTag,
|
||||
isJSDocTypeTag,
|
||||
isJsxNamespacedName,
|
||||
isJsxOpeningElement,
|
||||
isJsxOpeningFragment,
|
||||
isKeyword,
|
||||
@@ -228,7 +229,6 @@ import {
|
||||
JsxSelfClosingElement,
|
||||
JsxSpreadAttribute,
|
||||
JsxTagNameExpression,
|
||||
JsxTagNamePropertyAccess,
|
||||
JsxText,
|
||||
JsxTokenSyntaxKind,
|
||||
LabeledStatement,
|
||||
@@ -6122,11 +6122,15 @@ namespace Parser {
|
||||
// primaryExpression in the form of an identifier and "this" keyword
|
||||
// We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
|
||||
// We only want to consider "this" as a primaryExpression
|
||||
let expression: JsxTagNameExpression = parseJsxTagName();
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess;
|
||||
const initialExpression = parseJsxTagName();
|
||||
if (isJsxNamespacedName(initialExpression)) {
|
||||
return initialExpression; // `a:b.c` is invalid syntax, don't even look for the `.` if we parse `a:b`, and let `parseAttribute` report "unexpected :" instead.
|
||||
}
|
||||
return expression;
|
||||
let expression: PropertyAccessExpression | Identifier | ThisExpression = initialExpression;
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos);
|
||||
}
|
||||
return expression as JsxTagNameExpression;
|
||||
}
|
||||
|
||||
function parseJsxTagName(): Identifier | JsxNamespacedName | ThisExpression {
|
||||
|
||||
@@ -1722,11 +1722,9 @@ export type PropertyName = Identifier | StringLiteral | NumericLiteral | Compute
|
||||
export type MemberName = Identifier | PrivateIdentifier;
|
||||
|
||||
export type DeclarationName =
|
||||
| Identifier
|
||||
| PrivateIdentifier
|
||||
| PropertyName
|
||||
| JsxAttributeName
|
||||
| StringLiteralLike
|
||||
| NumericLiteral
|
||||
| ComputedPropertyName
|
||||
| ElementAccessExpression
|
||||
| BindingPattern
|
||||
| EntityNameExpression;
|
||||
@@ -2332,7 +2330,7 @@ export interface LiteralTypeNode extends TypeNode {
|
||||
|
||||
export interface StringLiteral extends LiteralExpression, Declaration {
|
||||
readonly kind: SyntaxKind.StringLiteral;
|
||||
/** @internal */ readonly textSourceNode?: Identifier | StringLiteralLike | NumericLiteral | PrivateIdentifier; // Allows a StringLiteral to get its text from another node (used by transforms).
|
||||
/** @internal */ readonly textSourceNode?: Identifier | StringLiteralLike | NumericLiteral | PrivateIdentifier | JsxNamespacedName; // Allows a StringLiteral to get its text from another node (used by transforms).
|
||||
/**
|
||||
* Note: this is only set when synthesizing a node, not during parsing.
|
||||
*
|
||||
@@ -2342,7 +2340,7 @@ export interface StringLiteral extends LiteralExpression, Declaration {
|
||||
}
|
||||
|
||||
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral;
|
||||
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName;
|
||||
|
||||
export interface TemplateLiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.TemplateLiteralType,
|
||||
@@ -3191,7 +3189,7 @@ export type JsxTagNameExpression =
|
||||
;
|
||||
|
||||
export interface JsxTagNamePropertyAccess extends PropertyAccessExpression {
|
||||
readonly expression: JsxTagNameExpression;
|
||||
readonly expression: Identifier | ThisExpression | JsxTagNamePropertyAccess;
|
||||
}
|
||||
|
||||
export interface JsxAttributes extends PrimaryExpression, Declaration {
|
||||
@@ -3200,7 +3198,7 @@ export interface JsxAttributes extends PrimaryExpression, Declaration {
|
||||
readonly parent: JsxOpeningLikeElement;
|
||||
}
|
||||
|
||||
export interface JsxNamespacedName extends PrimaryExpression {
|
||||
export interface JsxNamespacedName extends Node {
|
||||
readonly kind: SyntaxKind.JsxNamespacedName;
|
||||
readonly name: Identifier;
|
||||
readonly namespace: Identifier;
|
||||
|
||||
@@ -293,6 +293,7 @@ import {
|
||||
isJSDocTypeTag,
|
||||
isJsxChild,
|
||||
isJsxFragment,
|
||||
isJsxNamespacedName,
|
||||
isJsxOpeningLikeElement,
|
||||
isJsxText,
|
||||
isLeftHandSideExpression,
|
||||
@@ -2024,7 +2025,7 @@ export function isComputedNonLiteralName(name: PropertyName): boolean {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral): __String | undefined {
|
||||
export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral | JsxAttributeName): __String | undefined {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
@@ -2036,13 +2037,15 @@ export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemp
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
if (isStringOrNumericLiteralLike(name.expression)) return escapeLeadingUnderscores(name.expression.text);
|
||||
return undefined;
|
||||
case SyntaxKind.JsxNamespacedName:
|
||||
return getEscapedTextOfJsxNamespacedName(name);
|
||||
default:
|
||||
return Debug.assertNever(name);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral): __String {
|
||||
export function getTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral | JsxAttributeName): __String {
|
||||
return Debug.checkDefined(tryGetTextOfPropertyName(name));
|
||||
}
|
||||
|
||||
@@ -3074,7 +3077,7 @@ export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNam
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getInvokedExpression(node: CallLikeExpression): Expression {
|
||||
export function getInvokedExpression(node: CallLikeExpression): Expression | JsxTagNameExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return node.tag;
|
||||
@@ -4954,7 +4957,7 @@ export function isDynamicName(name: DeclarationName): boolean {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined {
|
||||
export function getPropertyNameForPropertyNameNode(name: PropertyName | JsxAttributeName): __String | undefined {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
@@ -4974,6 +4977,8 @@ export function getPropertyNameForPropertyNameNode(name: PropertyName): __String
|
||||
return nameExpression.operand.text as __String;
|
||||
}
|
||||
return undefined;
|
||||
case SyntaxKind.JsxNamespacedName:
|
||||
return getEscapedTextOfJsxNamespacedName(name);
|
||||
default:
|
||||
return Debug.assertNever(name);
|
||||
}
|
||||
@@ -4993,12 +4998,12 @@ export function isPropertyNameLiteral(node: Node): node is PropertyNameLiteral {
|
||||
}
|
||||
/** @internal */
|
||||
export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral | PrivateIdentifier): string {
|
||||
return isMemberName(node) ? idText(node) : node.text;
|
||||
return isMemberName(node) ? idText(node) : isJsxNamespacedName(node) ? getTextOfJsxNamespacedName(node) : node.text;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String {
|
||||
return isMemberName(node) ? node.escapedText : escapeLeadingUnderscores(node.text);
|
||||
return isMemberName(node) ? node.escapedText : isJsxNamespacedName(node) ? getEscapedTextOfJsxNamespacedName(node) : escapeLeadingUnderscores(node.text);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -7025,7 +7030,7 @@ export function isPropertyAccessEntityNameExpression(node: Node): node is Proper
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetPropertyAccessOrIdentifierToString(expr: Expression): string | undefined {
|
||||
export function tryGetPropertyAccessOrIdentifierToString(expr: Expression | JsxTagNameExpression): string | undefined {
|
||||
if (isPropertyAccessExpression(expr)) {
|
||||
const baseStr = tryGetPropertyAccessOrIdentifierToString(expr.expression);
|
||||
if (baseStr !== undefined) {
|
||||
@@ -7041,6 +7046,9 @@ export function tryGetPropertyAccessOrIdentifierToString(expr: Expression): stri
|
||||
else if (isIdentifier(expr)) {
|
||||
return unescapeLeadingUnderscores(expr.escapedText);
|
||||
}
|
||||
else if (isJsxNamespacedName(expr)) {
|
||||
return getTextOfJsxNamespacedName(expr);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1941,7 +1941,6 @@ function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean {
|
||||
case SyntaxKind.JsxElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxFragment:
|
||||
case SyntaxKind.JsxNamespacedName:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
isTemplateSpan,
|
||||
isTemplateTail,
|
||||
isTransientSymbol,
|
||||
JsxTagNameExpression,
|
||||
last,
|
||||
lastOrUndefined,
|
||||
ListFormat,
|
||||
@@ -599,7 +600,7 @@ function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node,
|
||||
return children[indexOfOpenerToken + 1];
|
||||
}
|
||||
|
||||
function getExpressionFromInvocation(invocation: CallInvocation | TypeArgsInvocation): Expression {
|
||||
function getExpressionFromInvocation(invocation: CallInvocation | TypeArgsInvocation): Expression | JsxTagNameExpression {
|
||||
return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +261,7 @@ import {
|
||||
JsTyping,
|
||||
JsxEmit,
|
||||
JsxOpeningLikeElement,
|
||||
JsxTagNameExpression,
|
||||
LabeledStatement,
|
||||
LanguageServiceHost,
|
||||
last,
|
||||
@@ -617,7 +618,7 @@ function selectTagNameOfJsxOpeningLikeElement(node: JsxOpeningLikeElement) {
|
||||
return node.tagName;
|
||||
}
|
||||
|
||||
function isCalleeWorker<T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement>(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) {
|
||||
function isCalleeWorker<T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement>(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression | JsxTagNameExpression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) {
|
||||
let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node);
|
||||
if (skipPastOuterExpressions) {
|
||||
target = skipOuterExpressions(target);
|
||||
|
||||
Reference in New Issue
Block a user