diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f2e5e9e0f..e426a7bdba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2279,7 +2279,7 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.ignoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); Debug.assert(typeNode !== undefined, "should always get typenode?"); const options = { removeComments: true }; const writer = createTextWriter(""); @@ -2361,7 +2361,7 @@ namespace ts { function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { const inTypeAlias = context.flags & NodeBuilderFlags.InTypeAlias; - context.flags &= ~(NodeBuilderFlags.InTypeAlias); + context.flags &= ~NodeBuilderFlags.InTypeAlias; if (!type) { context.encounteredError = true; @@ -2419,7 +2419,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.ObjectKeyword); } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { - if (context.flags & NodeBuilderFlags.inObjectTypeLiteral) { + if (context.flags & NodeBuilderFlags.InObjectTypeLiteral) { if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowThisInObjectLiteral)) { context.encounteredError = true; } @@ -2441,12 +2441,12 @@ namespace ts { if (!inTypeAlias && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { const name = symbolToTypeReferenceName(type.aliasSymbol); - const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, context); + const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; - const typeNodes = types && mapToTypeNodeArray(types, context); + const typeNodes = mapToTypeNodes(types, context); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); return unionOrIntersectionTypeNode; @@ -2567,7 +2567,7 @@ namespace ts { } const savedFlags = context.flags; - context.flags |= NodeBuilderFlags.inObjectTypeLiteral; + context.flags |= NodeBuilderFlags.InObjectTypeLiteral; const members = createTypeNodesFromResolvedType(resolved); context.flags = savedFlags; const typeLiteralNode = createTypeLiteralNode(members); @@ -2598,8 +2598,7 @@ namespace ts { } else if (type.target.objectFlags & ObjectFlags.Tuple) { if (typeArguments.length > 0) { - const slice = typeArguments.slice(0, getTypeReferenceArity(type)); - const tupleConstituentNodes = slice && mapToTypeNodeArray(slice, context); + const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, getTypeReferenceArity(type)), context); if (tupleConstituentNodes && tupleConstituentNodes.length > 0) { return createTupleTypeNode(tupleConstituentNodes); } @@ -2625,8 +2624,8 @@ namespace ts { // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const slice = typeArguments.slice(start, i); - const typeArgumentNodes = slice && createNodeArray(mapToTypeNodeArray(slice, context)); + const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); + const typeArgumentNodes = typeArgumentSlice && createNodeArray(typeArgumentSlice); const namePart = symbolToTypeReferenceName(parent); (namePart.kind === SyntaxKind.Identifier ? namePart : namePart.right).typeArguments = typeArgumentNodes; @@ -2654,10 +2653,9 @@ namespace ts { } let typeArgumentNodes: TypeNode[] | undefined; - if (some(typeArguments)) { + if (typeArguments.length > 0) { const typeParameterCount = (type.target.typeParameters || emptyArray).length; - const slice = typeArguments && typeArguments.slice(i, typeParameterCount); - typeArgumentNodes = slice && mapToTypeNodeArray(slice, context); + typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context); } if (typeArgumentNodes) { @@ -2740,17 +2738,19 @@ namespace ts { } } - function mapToTypeNodeArray(types: Type[], context: NodeBuilderContext): TypeNode[] { - const result = []; - for (let i = 0; i < types.length; ++i) { - const type = types[i]; - const typeNode = typeToTypeNodeHelper(type, context); - if (typeNode) { - result.push(typeNode); + function mapToTypeNodes(types: Type[], context: NodeBuilderContext): TypeNode[] { + if (some(types)) { + const result = []; + for (let i = 0; i < types.length; ++i) { + const type = types[i]; + const typeNode = typeToTypeNodeHelper(type, context); + if (typeNode) { + result.push(typeNode); + } } - } - return result; + return result; + } } function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, context: NodeBuilderContext): IndexSignatureDeclaration { @@ -2890,9 +2890,7 @@ namespace ts { } } - if (typeParameters && typeParameters.length > 0) { - typeParameterNodes = mapToTypeNodeArray(typeParameters, context); - } + typeParameterNodes = mapToTypeNodes(typeParameters, context); } const symbolName = getNameOfSymbol(symbol, context); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 826b636e71..7917480975 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2655,7 +2655,7 @@ namespace ts { if (isIdentifier(textSourceNode)) { return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? `"${escapeString(getTextOfNode(textSourceNode))}"` : - `"${escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode)))}"`; + `"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`; } else { return getLiteralTextOfNode(textSourceNode); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 18e71f94ee..1a5f1fbac5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3607,16 +3607,17 @@ namespace ts { } export function parenthesizeElementTypeMembers(members: TypeNode[]) { - // TODO: does this lose `originalNode` ptr? - return createNodeArray(members.map(parenthesizeElementTypeMember)); + return createNodeArray(sameMap(members, parenthesizeElementTypeMember)); } export function parenthesizeTypeParameters(typeParameters: TypeNode[]) { - if (typeParameters && typeParameters.length > 0) { - const nodeArray = createNodeArray(typeParameters); - const firstEntry = nodeArray[0]; - if (isFunctionOrConstructor(firstEntry) && firstEntry.typeParameters) { - nodeArray[0] = createParenthesizedType(firstEntry); + if (some(typeParameters)) { + const nodeArray = createNodeArray() as NodeArray; + for (let i = 0; i < typeParameters.length; ++i) { + const entry = typeParameters[i]; + nodeArray.push(i === 0 && isFunctionOrConstructorTypeNode(entry) && entry.typeParameters ? + createParenthesizedType(entry) : + entry); } return nodeArray; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4bc97c56c0..3ac3caa121 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -580,7 +580,7 @@ namespace ts { /*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. /*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name. isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes.Though not syntactically valid, used in emitting diagnostics. + /*@internal*/ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics. } // Transient identifier node (marked by id === -1) @@ -2599,10 +2599,10 @@ namespace ts { AllowEmptyUnionOrIntersection = 1 << 14, AllowEmptyTuple = 1 << 15, - ignoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, + IgnoreErrors = AllowThisInObjectLiteral | AllowQualifedNameInPlaceOfIdentifier | AllowAnonymousIdentifier | AllowEmptyUnionOrIntersection | AllowEmptyTuple, // State - inObjectTypeLiteral = 1 << 20, + InObjectTypeLiteral = 1 << 20, InTypeAlias = 1 << 23, // Writing type in type alias declaration } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9dac18eec8..c8e481bc2e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -328,9 +328,8 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(sourceFile, node); } - const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? - (text: string) => escapeString(text) : - (text: string) => escapeNonAsciiCharacters(escapeString(text)); + const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString; + // If we can't reach the original source text, use the canonical form if it's a number, // or a (possibly escaped) quoted form of the original text if it's string-like. switch (node.kind) { @@ -880,7 +879,7 @@ namespace ts { return false; } - export function isFunctionOrConstructor(node: Node): node is FunctionTypeNode | ConstructorTypeNode { + export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode { switch (node.kind) { case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: @@ -2468,7 +2467,8 @@ namespace ts { } const nonAsciiCharacters = /[^\u0000-\u007F]/g; - export function escapeNonAsciiCharacters(s: string): string { + export function escapeNonAsciiString(s: string): string { + s = escapeString(s); // Replace non-ASCII characters with '\uNNNN' escapes if any exist. // Otherwise just return the original string. return nonAsciiCharacters.test(s) ? diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index c62af0da79..f8fe92c184 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -988,8 +988,6 @@ namespace ts { result = reduceNode((node).initializer, cbNode, result); break; - case SyntaxKind.PropertySignature: - case SyntaxKind.MethodDeclaration: result = reduceNodes((node).decorators, cbNodes, result); result = reduceNodes((node).modifiers, cbNodes, result);