diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 06b15c7718d..782363dd6df 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -260,7 +260,7 @@ namespace ts { const name = getNameOfDeclaration(node); if (name) { if (isAmbientModule(node)) { - const moduleName = getTextOfIdentifierOrLiteral(name); + const moduleName = getTextOfIdentifierOrLiteral(name as Identifier | StringLiteral); return (isGlobalScopeAugmentation(node) ? "__global" : `"${moduleName}"`) as __String; } if (name.kind === SyntaxKind.ComputedPropertyName) { @@ -273,7 +273,7 @@ namespace ts { Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); } - return getEscapedTextOfIdentifierOrLiteral(name); + return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } switch (node.kind) { case SyntaxKind.Constructor: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2768c142f5a..00353c1c391 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23753,7 +23753,11 @@ namespace ts { function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { const moduleName = getExternalModuleName(node); - if (!nodeIsMissing(moduleName) && moduleName.kind !== SyntaxKind.StringLiteral) { + if (nodeIsMissing(moduleName)) { + // Should be a parse error. + return false; + } + if (!isStringLiteral(moduleName)) { error(moduleName, Diagnostics.String_literal_expected); return false; } @@ -23764,7 +23768,7 @@ namespace ts { Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module); return false; } - if (inAmbientExternalModule && isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(moduleName))) { + if (inAmbientExternalModule && isExternalModuleNameRelative(moduleName.text)) { // we have already reported errors on top level imports\exports in external module augmentations in checkModuleDeclaration // no need to do this again. if (!isTopLevelInExternalModuleAugmentation(node)) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 647ae6983fa..92d353aeb0e 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -101,7 +101,7 @@ namespace ts { return node; } - function createLiteralFromNode(sourceNode: StringLiteralLike | NumericLiteral | Identifier): StringLiteral { + function createLiteralFromNode(sourceNode: PropertyNameLiteral): StringLiteral { const node = createStringLiteral(getTextOfIdentifierOrLiteral(sourceNode)); node.textSourceNode = sourceNode; return node; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 63214d68e5d..c6861380d8d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2159,34 +2159,24 @@ namespace ts { return undefined; } - export function getTextOfIdentifierOrLiteral(node: Identifier | LiteralLikeNode) { - if (node) { - if (node.kind === SyntaxKind.Identifier) { - return idText(node as Identifier); - } - if (node.kind === SyntaxKind.StringLiteral || - node.kind === SyntaxKind.NumericLiteral) { - - return node.text; - } + export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral; + export function isPropertyNameLiteral(node: Node): node is PropertyNameLiteral { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.NumericLiteral: + return true; + default: + return false; } - - return undefined; + } + export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral): string { + return node.kind === SyntaxKind.Identifier ? idText(node) : node.text; } - export function getEscapedTextOfIdentifierOrLiteral(node: Identifier | LiteralLikeNode) { - if (node) { - if (node.kind === SyntaxKind.Identifier) { - return (node as Identifier).escapedText; - } - if (node.kind === SyntaxKind.StringLiteral || - node.kind === SyntaxKind.NumericLiteral) { - - return escapeLeadingUnderscores(node.text); - } - } - - return undefined; + export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String { + return node.kind === SyntaxKind.Identifier ? node.escapedText : escapeLeadingUnderscores(node.text); } export function getPropertyNameForKnownSymbolName(symbolName: string): __String { diff --git a/src/services/completions.ts b/src/services/completions.ts index a77185ab94e..c49f758392a 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1999,7 +1999,7 @@ namespace ts.Completions { // NOTE: if one only performs this step when m.name is an identifier, // things like '__proto__' are not filtered out. const name = getNameOfDeclaration(m); - existingName = getEscapedTextOfIdentifierOrLiteral(name as (Identifier | LiteralExpression)); + existingName = isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } existingMemberNames.set(existingName, true); diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 3b5e5ee59ba..21d8a792759 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -89,45 +89,37 @@ namespace ts.NavigateTo { } function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]): boolean { - if (declaration) { - const name = getNameOfDeclaration(declaration); - if (name) { - const text = getTextOfIdentifierOrLiteral(name as (Identifier | LiteralExpression)); - if (text !== undefined) { - containers.unshift(text); - } - else if (name.kind === SyntaxKind.ComputedPropertyName) { - return tryAddComputedPropertyName(name.expression, containers, /*includeLastPortion*/ true); - } - else { - // Don't know how to add this. - return false; - } - } + const name = getNameOfDeclaration(declaration); + if (name && isPropertyNameLiteral(name)) { + containers.unshift(getTextOfIdentifierOrLiteral(name)); + return true; + } + else if (name && name.kind === SyntaxKind.ComputedPropertyName) { + return tryAddComputedPropertyName(name.expression, containers, /*includeLastPortion*/ true); + } + else { + // Don't know how to add this. + return false; } - - return true; } // Only added the names of computed properties if they're simple dotted expressions, like: // // [X.Y.Z]() { } function tryAddComputedPropertyName(expression: Expression, containers: string[], includeLastPortion: boolean): boolean { - const text = getTextOfIdentifierOrLiteral(expression as LiteralExpression); - if (text !== undefined) { + if (isPropertyNameLiteral(expression)) { + const text = getTextOfIdentifierOrLiteral(expression); if (includeLastPortion) { containers.unshift(text); } return true; } - - if (expression.kind === SyntaxKind.PropertyAccessExpression) { - const propertyAccess = expression; + if (isPropertyAccessExpression(expression)) { if (includeLastPortion) { - containers.unshift(propertyAccess.name.text); + containers.unshift(expression.name.text); } - return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion*/ true); + return tryAddComputedPropertyName(expression.expression, containers, /*includeLastPortion*/ true); } return false; diff --git a/src/services/services.ts b/src/services/services.ts index 991b6c10606..fe7606fd8ad 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -721,23 +721,8 @@ namespace ts { function getDeclarationName(declaration: Declaration) { const name = getNameOfDeclaration(declaration); - if (name) { - const result = getTextOfIdentifierOrLiteral(name as (Identifier | LiteralExpression)); - if (result !== undefined) { - return result; - } - - if (name.kind === SyntaxKind.ComputedPropertyName) { - const expr = name.expression; - if (expr.kind === SyntaxKind.PropertyAccessExpression) { - return (expr).name.text; - } - - return getTextOfIdentifierOrLiteral(expr as (Identifier | LiteralExpression)); - } - } - - return undefined; + return name && (isPropertyNameLiteral(name) ? getTextOfIdentifierOrLiteral(name) : + name.kind === SyntaxKind.ComputedPropertyName && isPropertyAccessExpression(name.expression) ? name.expression.name.text : undefined); } function visit(node: Node): void {