From 0c1eef70b0dfb731dbf2a94eaf46acebdf94082d Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Sat, 29 Apr 2017 15:18:34 -0700 Subject: [PATCH] Add support for declaration emit --- src/compiler/checker.ts | 15 +++++++- src/compiler/declarationEmitter.ts | 56 ++++++++++++++++++++---------- src/compiler/types.ts | 1 + 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7db62ed487d..b091388ed8e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2184,7 +2184,9 @@ namespace ts { function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult { // get symbol of the first identifier of the entityName let meaning: SymbolFlags; - if (entityName.parent.kind === SyntaxKind.TypeQuery || isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent)) { + if (entityName.parent.kind === SyntaxKind.TypeQuery || + isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent) || + entityName.parent.kind === SyntaxKind.ComputedPropertyName) { // Typeof value meaning = SymbolFlags.Value | SymbolFlags.ExportValue; } @@ -22822,6 +22824,16 @@ namespace ts { return undefined; } + function isLiteralDynamicName(name: ComputedPropertyName) { + name = getParseTreeNode(name, isComputedPropertyName); + if (name) { + // TODO(rbuckton): ESSymbolLiteral + const nameType = checkComputedPropertyName(name); + return (nameType.flags & TypeFlags.StringOrNumberLiteral) !== 0; + } + return false; + } + function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { if (isConst(node)) { const type = getTypeOfSymbol(getSymbolOfNode(node)); @@ -22895,6 +22907,7 @@ namespace ts { getTypeReferenceDirectivesForEntityName, getTypeReferenceDirectivesForSymbol, isLiteralConstDeclaration, + isLiteralDynamicName, writeLiteralConstValue, getJsxFactoryEntity: () => _jsxFactoryEntity }; diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 2bd8d5971fb..ec123a7488d 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -452,19 +452,6 @@ namespace ts { return emitTypePredicate(type); } - function writeEntityName(entityName: EntityName | Expression) { - if (entityName.kind === SyntaxKind.Identifier) { - writeTextOfNode(currentText, entityName); - } - else { - const left = entityName.kind === SyntaxKind.QualifiedName ? (entityName).left : (entityName).expression; - const right = entityName.kind === SyntaxKind.QualifiedName ? (entityName).right : (entityName).name; - writeEntityName(left); - write("."); - writeTextOfNode(currentText, right); - } - } - function emitEntityName(entityName: EntityNameOrEntityNameExpression) { const visibilityResult = resolver.isEntityNameVisible(entityName, // Aliases can be written asynchronously so use correct enclosing declaration @@ -584,6 +571,19 @@ namespace ts { } } + function writeEntityName(entityName: EntityName | Expression) { + if (entityName.kind === SyntaxKind.Identifier) { + writeTextOfNode(currentText, entityName); + } + else { + const left = entityName.kind === SyntaxKind.QualifiedName ? (entityName).left : (entityName).expression; + const right = entityName.kind === SyntaxKind.QualifiedName ? (entityName).right : (entityName).name; + writeEntityName(left); + write("."); + writeTextOfNode(currentText, right); + } + } + function emitSourceFile(node: SourceFile) { currentText = node.text; currentLineMap = getLineStarts(node); @@ -1202,7 +1202,7 @@ namespace ts { } function emitPropertyDeclaration(node: Declaration) { - if (hasDynamicName(node)) { + if (hasDynamicName(node) && !resolver.isLiteralDynamicName(node.name)) { return; } @@ -1221,10 +1221,17 @@ namespace ts { emitBindingPattern(node.name); } else { - // If this node is a computed name, it can only be a symbol, because we've already skipped - // it if it's not a well known symbol. In that case, the text of the name will be exactly - // what we want, namely the name expression enclosed in brackets. - writeTextOfNode(currentText, node.name); + if (isDynamicName(node.name)) { + // If this node has a dynamic name, it can only be an identifier or property access because + // we've already skipped it otherwise. + emitDynamicName((node.name).expression); + } + else { + // If this node is a computed name, it can only be a symbol, because we've already skipped + // it if it's not a well known symbol. In that case, the text of the name will be exactly + // what we want, namely the name expression enclosed in brackets. + writeTextOfNode(currentText, node.name); + } // If optional property emit ? but in the case of parameterProperty declaration with "?" indicating optional parameter for the constructor // we don't want to emit property declaration with "?" if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature || @@ -1287,6 +1294,19 @@ namespace ts { } : undefined; } + function emitDynamicName(entityName: EntityNameExpression) { + writer.getSymbolAccessibilityDiagnostic = getVariableDeclarationTypeVisibilityError; + const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration); + if (visibilityResult.accessibility !== SymbolAccessibility.Accessible) { + resolver.writeTypeOfExpression(entityName, enclosingDeclaration, TypeFormatFlags.None, writer); + } + else { + handleSymbolAccessibilityError(visibilityResult); + recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName)); + writeTextOfNode(currentText, node.name); + } + } + function emitBindingPattern(bindingPattern: BindingPattern) { // Only select non-omitted expression from the bindingPattern's elements. // We have to do this to avoid emitting trailing commas. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bbe5dff8ef2..8b00f8f27b6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2721,6 +2721,7 @@ namespace ts { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + isLiteralDynamicName(node: ComputedPropertyName): boolean; collectLinkedAliases(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; isRequiredInitializedParameter(node: ParameterDeclaration): boolean;