diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3a19ca63b3f9b..93c2e6a10e145 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2993,7 +2993,8 @@ namespace ts { } function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string { - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors, writer); + const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation; + const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), writer); if (typeNode === undefined) return Debug.fail("should always get typenode"); const options = { removeComments: true }; const printer = createPrinter(options); @@ -3001,7 +3002,7 @@ namespace ts { printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); - const maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; + const maxLength = noTruncation ? undefined : defaultMaximumTruncationLength * 2; if (maxLength && result && result.length >= maxLength) { return result.substr(0, maxLength - "...".length) + "..."; } @@ -3040,12 +3041,18 @@ namespace ts { tracker: tracker && tracker.trackSymbol ? tracker : { trackSymbol: noop }, encounteredError: false, visitedSymbols: undefined, - inferTypeParameters: undefined + inferTypeParameters: undefined, + approximateLength: 0 }; const resultingNode = cb(context); return context.encounteredError ? undefined : resultingNode; } + function checkTruncationLength(context: NodeBuilderContext): boolean { + if (context.truncating) return context.truncating; + return context.truncating = !(context.flags & NodeBuilderFlags.NoTruncation) && context.approximateLength > defaultMaximumTruncationLength; + } + function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { if (cancellationToken && cancellationToken.throwIfCancellationRequested) { cancellationToken.throwIfCancellationRequested(); @@ -3059,66 +3066,83 @@ namespace ts { } if (type.flags & TypeFlags.Any) { + context.approximateLength += 3; return createKeywordTypeNode(SyntaxKind.AnyKeyword); } if (type.flags & TypeFlags.Unknown) { return createKeywordTypeNode(SyntaxKind.UnknownKeyword); } if (type.flags & TypeFlags.String) { + context.approximateLength += 6; return createKeywordTypeNode(SyntaxKind.StringKeyword); } if (type.flags & TypeFlags.Number) { + context.approximateLength += 6; return createKeywordTypeNode(SyntaxKind.NumberKeyword); } if (type.flags & TypeFlags.Boolean) { + context.approximateLength += 7; return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } if (type.flags & TypeFlags.EnumLiteral && !(type.flags & TypeFlags.Union)) { const parentSymbol = getParentOfSymbol(type.symbol)!; const parentName = symbolToName(parentSymbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); const enumLiteralName = getDeclaredTypeOfSymbol(parentSymbol) === type ? parentName : createQualifiedName(parentName, symbolName(type.symbol)); + context.approximateLength += symbolName(type.symbol).length; return createTypeReferenceNode(enumLiteralName, /*typeArguments*/ undefined); } if (type.flags & TypeFlags.EnumLike) { const name = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false); + context.approximateLength += symbolName(type.symbol).length; return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (type.flags & (TypeFlags.StringLiteral)) { + if (type.flags & TypeFlags.StringLiteral) { + context.approximateLength += ((type).value.length + 2); return createLiteralTypeNode(setEmitFlags(createLiteral((type).value), EmitFlags.NoAsciiEscaping)); } - if (type.flags & (TypeFlags.NumberLiteral)) { + if (type.flags & TypeFlags.NumberLiteral) { + context.approximateLength += (("" + (type).value).length); return createLiteralTypeNode((createLiteral((type).value))); } if (type.flags & TypeFlags.BooleanLiteral) { + context.approximateLength += (type).intrinsicName.length; return (type).intrinsicName === "true" ? createTrue() : createFalse(); } if (type.flags & TypeFlags.UniqueESSymbol) { if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration!)) { + context.approximateLength += 6; return symbolToTypeNode(type.symbol, context, SymbolFlags.Value); } if (context.tracker.reportInaccessibleUniqueSymbolError) { context.tracker.reportInaccessibleUniqueSymbolError(); } } + context.approximateLength += 13; return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createKeywordTypeNode(SyntaxKind.SymbolKeyword)); } if (type.flags & TypeFlags.Void) { + context.approximateLength += 4; return createKeywordTypeNode(SyntaxKind.VoidKeyword); } if (type.flags & TypeFlags.Undefined) { + context.approximateLength += 9; return createKeywordTypeNode(SyntaxKind.UndefinedKeyword); } if (type.flags & TypeFlags.Null) { + context.approximateLength += 4; return createKeywordTypeNode(SyntaxKind.NullKeyword); } if (type.flags & TypeFlags.Never) { + context.approximateLength += 5; return createKeywordTypeNode(SyntaxKind.NeverKeyword); } if (type.flags & TypeFlags.ESSymbol) { + context.approximateLength += 6; return createKeywordTypeNode(SyntaxKind.SymbolKeyword); } if (type.flags & TypeFlags.NonPrimitive) { + context.approximateLength += 6; return createKeywordTypeNode(SyntaxKind.ObjectKeyword); } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { @@ -3130,6 +3154,7 @@ namespace ts { context.tracker.reportInaccessibleThisError(); } } + context.approximateLength += 4; return createThis(); } @@ -3141,6 +3166,7 @@ namespace ts { } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { + context.approximateLength += (symbolName(type.symbol).length + 6); return createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, /*constraintNode*/ undefined)); } if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && @@ -3149,7 +3175,9 @@ namespace ts { isTypeParameterDeclaration(type.symbol.declarations[0]) && typeParameterShadowsNameInScope(type, context) && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)) { - return createTypeReferenceNode(getGeneratedNameForNode((type.symbol.declarations[0] as TypeParameterDeclaration).name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes), /*typeArguments*/ undefined); + const name = (type.symbol.declarations[0] as TypeParameterDeclaration).name; + context.approximateLength += idText(name).length; + return createTypeReferenceNode(getGeneratedNameForNode(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes), /*typeArguments*/ undefined); } // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return type.symbol @@ -3163,7 +3191,7 @@ namespace ts { } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { const types = type.flags & TypeFlags.Union ? formatUnionTypes((type).types) : (type).types; - const typeNodes = mapToTypeNodes(types, context); + const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true); if (typeNodes && typeNodes.length > 0) { const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes); return unionOrIntersectionTypeNode; @@ -3182,12 +3210,14 @@ namespace ts { } if (type.flags & TypeFlags.Index) { const indexedType = (type).type; + context.approximateLength += 6; const indexTypeNode = typeToTypeNodeHelper(indexedType, context); return createTypeOperatorNode(indexTypeNode); } if (type.flags & TypeFlags.IndexedAccess) { const objectTypeNode = typeToTypeNodeHelper((type).objectType, context); const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); + context.approximateLength += 2; return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } if (type.flags & TypeFlags.Conditional) { @@ -3198,6 +3228,7 @@ namespace ts { context.inferTypeParameters = saveInferTypeParameters; const trueTypeNode = typeToTypeNodeHelper(getTrueTypeFromConditionalType(type), context); const falseTypeNode = typeToTypeNodeHelper(getFalseTypeFromConditionalType(type), context); + context.approximateLength += 15; return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); } if (type.flags & TypeFlags.Substitution) { @@ -3222,6 +3253,7 @@ namespace ts { const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context); const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode); + context.approximateLength += 10; return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); } @@ -3250,6 +3282,7 @@ namespace ts { return symbolToTypeNode(typeAlias, context, SymbolFlags.Type); } else { + context.approximateLength += 3; return createKeywordTypeNode(SyntaxKind.AnyKeyword); } } @@ -3294,6 +3327,7 @@ namespace ts { const resolved = resolveStructuredTypeMembers(type); if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { + context.approximateLength += 2; return setEmitFlags(createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); } @@ -3316,6 +3350,7 @@ namespace ts { const members = createTypeNodesFromResolvedType(resolved); context.flags = savedFlags; const typeLiteralNode = createTypeLiteralNode(members); + context.approximateLength += 2; return setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); } @@ -3437,6 +3472,9 @@ namespace ts { } function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined { + if (checkTruncationLength(context)) { + return [createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)]; + } const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context)); @@ -3459,7 +3497,9 @@ namespace ts { return typeElements; } + let i = 0; for (const propertySymbol of properties) { + i++; if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) { if (propertySymbol.flags & SymbolFlags.Prototype) { continue; @@ -3468,65 +3508,102 @@ namespace ts { context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName)); } } - const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ? - anyType : getTypeOfSymbol(propertySymbol); - const saveEnclosingDeclaration = context.enclosingDeclaration; - context.enclosingDeclaration = undefined; - if (getCheckFlags(propertySymbol) & CheckFlags.Late) { - const decl = first(propertySymbol.declarations); - if (context.tracker.trackSymbol && hasLateBindableName(decl)) { - // get symbol of the first identifier of the entityName - const firstIdentifier = getFirstIdentifier(decl.name.expression); - const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); - if (name) { - context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value); - } - } + if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) { + typeElements.push(createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); + addPropertyToElementList(properties[properties.length - 1], context, typeElements); + break; } - const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true); - context.enclosingDeclaration = saveEnclosingDeclaration; - const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; - if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { - const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); - for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context); - methodDeclaration.name = propertyName; - methodDeclaration.questionToken = optionalToken; - if (propertySymbol.valueDeclaration) { - // Copy comments to node for declaration emit - setCommentRange(methodDeclaration, propertySymbol.valueDeclaration); - } - typeElements.push(methodDeclaration); - } + addPropertyToElementList(propertySymbol, context, typeElements); + + } + return typeElements.length ? typeElements : undefined; + } + } + + function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { + const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ? + anyType : getTypeOfSymbol(propertySymbol); + const saveEnclosingDeclaration = context.enclosingDeclaration; + context.enclosingDeclaration = undefined; + if (getCheckFlags(propertySymbol) & CheckFlags.Late) { + const decl = first(propertySymbol.declarations); + if (context.tracker.trackSymbol && hasLateBindableName(decl)) { + // get symbol of the first identifier of the entityName + const firstIdentifier = getFirstIdentifier(decl.name.expression); + const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + if (name) { + context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value); } - else { - const savedFlags = context.flags; - context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0; - const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); - context.flags = savedFlags; - - const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined; - const propertySignature = createPropertySignature( - modifiers, - propertyName, - optionalToken, - propertyTypeNode, - /*initializer*/ undefined); - if (propertySymbol.valueDeclaration) { - // Copy comments to node for declaration emit - setCommentRange(propertySignature, propertySymbol.valueDeclaration); - } - typeElements.push(propertySignature); + } + } + const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true); + context.approximateLength += (symbolName(propertySymbol).length + 1); + context.enclosingDeclaration = saveEnclosingDeclaration; + const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; + if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { + const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); + for (const signature of signatures) { + const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context); + methodDeclaration.name = propertyName; + methodDeclaration.questionToken = optionalToken; + if (propertySymbol.valueDeclaration) { + // Copy comments to node for declaration emit + setCommentRange(methodDeclaration, propertySymbol.valueDeclaration); } + typeElements.push(methodDeclaration); } - return typeElements.length ? typeElements : undefined; + } + else { + const savedFlags = context.flags; + context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0; + const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); + context.flags = savedFlags; + + const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined; + if (modifiers) { + context.approximateLength += 9; + } + const propertySignature = createPropertySignature( + modifiers, + propertyName, + optionalToken, + propertyTypeNode, + /*initializer*/ undefined); + if (propertySymbol.valueDeclaration) { + // Copy comments to node for declaration emit + setCommentRange(propertySignature, propertySymbol.valueDeclaration); + } + typeElements.push(propertySignature); } } - function mapToTypeNodes(types: ReadonlyArray | undefined, context: NodeBuilderContext): TypeNode[] | undefined { + function mapToTypeNodes(types: ReadonlyArray | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined { if (some(types)) { + if (checkTruncationLength(context)) { + if (!isBareList) { + return [createTypeReferenceNode("...", /*typeArguments*/ undefined)]; + } + else if (types.length > 2) { + return [ + typeToTypeNodeHelper(types[0], context), + createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined), + typeToTypeNodeHelper(types[types.length - 1], context) + ]; + } + } const result = []; + let i = 0; for (const type of types) { + i++; + if (checkTruncationLength(context) && (i + 2 < types.length - 1)) { + result.push(createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined)); + const typeNode = typeToTypeNodeHelper(types[types.length - 1], context); + if (typeNode) { + result.push(typeNode); + } + break; + } + context.approximateLength += 2; // Account for whitespace + separator const typeNode = typeToTypeNodeHelper(type, context); if (typeNode) { result.push(typeNode); @@ -3553,6 +3630,7 @@ namespace ts { if (!indexInfo.type && !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType)) { context.encounteredError = true; } + context.approximateLength += (name.length + 4); return createIndexSignature( /*decorators*/ undefined, indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined, @@ -3597,6 +3675,7 @@ namespace ts { else if (!returnTypeNode) { returnTypeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword); } + context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode, typeArguments); } @@ -3658,6 +3737,7 @@ namespace ts { questionToken, parameterTypeNode, /*initializer*/ undefined); + context.approximateLength += symbolName(parameterSymbol).length + 3; return parameterNode; function cloneBindingName(node: BindingName): BindingName { @@ -3812,7 +3892,9 @@ namespace ts { // module is root, must use `ImportTypeNode` const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined; const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context); - const lit = createLiteralTypeNode(createLiteral(getSpecifierForModuleSymbol(chain[0], context))); + const specifier = getSpecifierForModuleSymbol(chain[0], context); + const lit = createLiteralTypeNode(createLiteral(specifier)); + context.approximateLength += specifier.length + 10; // specifier + import("") if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; @@ -3849,6 +3931,7 @@ namespace ts { context.flags |= NodeBuilderFlags.InInitialEntityName; } const symbolName = getNameOfSymbolAsWritten(symbol, context); + context.approximateLength += symbolName.length + 1; if (index === 0) { context.flags ^= NodeBuilderFlags.InInitialEntityName; } @@ -4033,6 +4116,8 @@ namespace ts { encounteredError: boolean; visitedSymbols: Map | undefined; inferTypeParameters: TypeParameter[] | undefined; + approximateLength: number; + truncating?: boolean; } function isDefaultBindingContext(location: Node) { diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 055fc3d2e0f5c..dcfc50dd007de 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -11,11 +11,12 @@ namespace ts { const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals | - TypeFormatFlags.WriteClassExpressionAsTypeLiteral | + NodeBuilderFlags.WriteClassExpressionAsTypeLiteral | NodeBuilderFlags.UseTypeOfFunction | NodeBuilderFlags.UseStructuralFallback | NodeBuilderFlags.AllowEmptyTuple | - NodeBuilderFlags.GenerateNamesForShadowedTypeParams; + NodeBuilderFlags.GenerateNamesForShadowedTypeParams | + NodeBuilderFlags.NoTruncation; /** * Transforms a ts file into a .d.ts file diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c5fa7d155d519..9cedb7d659e30 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -21,6 +21,8 @@ namespace ts { export const externalHelpersModuleNameText = "tslib"; + export const defaultMaximumTruncationLength = 160; + export function getDeclarationOfKind(symbol: Symbol, kind: T["kind"]): T | undefined { const declarations = symbol.declarations; if (declarations) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index b87ec2610d856..deccf19b8eae1 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1435,14 +1435,25 @@ namespace ts { const displayPartWriter = getDisplayPartWriter(); function getDisplayPartWriter(): DisplayPartsSymbolWriter { + const absoluteMaximumLength = defaultMaximumTruncationLength * 10; // A hard cutoff to avoid overloading the messaging channel in worst-case scenarios let displayParts: SymbolDisplayPart[]; let lineStart: boolean; let indent: number; + let length: number; resetWriter(); const unknownWrite = (text: string) => writeKind(text, SymbolDisplayPartKind.text); return { - displayParts: () => displayParts, + displayParts: () => { + const finalText = displayParts.length && displayParts[displayParts.length - 1].text; + if (length > absoluteMaximumLength && finalText && finalText !== "...") { + if (!isWhiteSpaceLike(finalText.charCodeAt(finalText.length - 1))) { + displayParts.push(displayPart(" ", SymbolDisplayPartKind.space)); + } + displayParts.push(displayPart("...", SymbolDisplayPartKind.punctuation)); + } + return displayParts; + }, writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword), writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator), writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation), @@ -1472,9 +1483,11 @@ namespace ts { }; function writeIndent() { + if (length > absoluteMaximumLength) return; if (lineStart) { const indentString = getIndentString(indent); if (indentString) { + length += indentString.length; displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space)); } lineStart = false; @@ -1482,16 +1495,22 @@ namespace ts { } function writeKind(text: string, kind: SymbolDisplayPartKind) { + if (length > absoluteMaximumLength) return; writeIndent(); + length += text.length; displayParts.push(displayPart(text, kind)); } function writeSymbol(text: string, symbol: Symbol) { + if (length > absoluteMaximumLength) return; writeIndent(); + length += text.length; displayParts.push(symbolPart(text, symbol)); } function writeLine() { + if (length > absoluteMaximumLength) return; + length += 1; displayParts.push(lineBreakPart()); lineStart = true; } @@ -1500,6 +1519,7 @@ namespace ts { displayParts = []; lineStart = true; indent = 0; + length = 0; } } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 82b7e0c3ef833..50459ff4389aa 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6031,6 +6031,7 @@ declare namespace ts { const emptyMap: ReadonlyMap; const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap; const externalHelpersModuleNameText = "tslib"; + const defaultMaximumTruncationLength = 160; function getDeclarationOfKind(symbol: Symbol, kind: T["kind"]): T | undefined; /** Create a new escaped identifier map. */ function createUnderscoreEscapedMap(): UnderscoreEscapedMap; diff --git a/tests/baselines/reference/errorWithTruncatedType.errors.txt b/tests/baselines/reference/errorWithTruncatedType.errors.txt index 33714b8626280..2f6e095a042ae 100644 --- a/tests/baselines/reference/errorWithTruncatedType.errors.txt +++ b/tests/baselines/reference/errorWithTruncatedType.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propert...' is not assignable to type 'string'. +tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; }' is not assignable to type 'string'. ==== tests/cases/compiler/errorWithTruncatedType.ts (1 errors) ==== @@ -13,5 +13,5 @@ tests/cases/compiler/errorWithTruncatedType.ts(10,5): error TS2322: Type '{ prop // String representation of type of 'x' should be truncated in error message var s: string = x; ~ -!!! error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propert...' is not assignable to type 'string'. +!!! error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; }' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoCanBeTruncated.ts b/tests/cases/fourslash/quickInfoCanBeTruncated.ts new file mode 100644 index 0000000000000..9c8965641d9d4 --- /dev/null +++ b/tests/cases/fourslash/quickInfoCanBeTruncated.ts @@ -0,0 +1,580 @@ +/// + +// @noLib: true +//// interface Foo { +//// _0: 0; +//// _1: 1; +//// _2: 2; +//// _3: 3; +//// _4: 4; +//// _5: 5; +//// _6: 6; +//// _7: 7; +//// _8: 8; +//// _9: 9; +//// _10: 10; +//// _11: 11; +//// _12: 12; +//// _13: 13; +//// _14: 14; +//// _15: 15; +//// _16: 16; +//// _17: 17; +//// _18: 18; +//// _19: 19; +//// _20: 20; +//// _21: 21; +//// _22: 22; +//// _23: 23; +//// _24: 24; +//// _25: 25; +//// _26: 26; +//// _27: 27; +//// _28: 28; +//// _29: 29; +//// _30: 30; +//// _31: 31; +//// _32: 32; +//// _33: 33; +//// _34: 34; +//// _35: 35; +//// _36: 36; +//// _37: 37; +//// _38: 38; +//// _39: 39; +//// _40: 40; +//// _41: 41; +//// _42: 42; +//// _43: 43; +//// _44: 44; +//// _45: 45; +//// _46: 46; +//// _47: 47; +//// _48: 48; +//// _49: 49; +//// _50: 50; +//// _51: 51; +//// _52: 52; +//// _53: 53; +//// _54: 54; +//// _55: 55; +//// _56: 56; +//// _57: 57; +//// _58: 58; +//// _59: 59; +//// _60: 60; +//// _61: 61; +//// _62: 62; +//// _63: 63; +//// _64: 64; +//// _65: 65; +//// _66: 66; +//// _67: 67; +//// _68: 68; +//// _69: 69; +//// _70: 70; +//// _71: 71; +//// _72: 72; +//// _73: 73; +//// _74: 74; +//// _75: 75; +//// _76: 76; +//// _77: 77; +//// _78: 78; +//// _79: 79; +//// _80: 80; +//// _81: 81; +//// _82: 82; +//// _83: 83; +//// _84: 84; +//// _85: 85; +//// _86: 86; +//// _87: 87; +//// _88: 88; +//// _89: 89; +//// _90: 90; +//// _91: 91; +//// _92: 92; +//// _93: 93; +//// _94: 94; +//// _95: 95; +//// _96: 96; +//// _97: 97; +//// _98: 98; +//// _99: 99; +//// _100: 100; +//// _101: 101; +//// _102: 102; +//// _103: 103; +//// _104: 104; +//// _105: 105; +//// _106: 106; +//// _107: 107; +//// _108: 108; +//// _109: 109; +//// _110: 110; +//// _111: 111; +//// _112: 112; +//// _113: 113; +//// _114: 114; +//// _115: 115; +//// _116: 116; +//// _117: 117; +//// _118: 118; +//// _119: 119; +//// _120: 120; +//// _121: 121; +//// _122: 122; +//// _123: 123; +//// _124: 124; +//// _125: 125; +//// _126: 126; +//// _127: 127; +//// _128: 128; +//// _129: 129; +//// _130: 130; +//// _131: 131; +//// _132: 132; +//// _133: 133; +//// _134: 134; +//// _135: 135; +//// _136: 136; +//// _137: 137; +//// _138: 138; +//// _139: 139; +//// _140: 140; +//// _141: 141; +//// _142: 142; +//// _143: 143; +//// _144: 144; +//// _145: 145; +//// _146: 146; +//// _147: 147; +//// _148: 148; +//// _149: 149; +//// _150: 150; +//// _151: 151; +//// _152: 152; +//// _153: 153; +//// _154: 154; +//// _155: 155; +//// _156: 156; +//// _157: 157; +//// _158: 158; +//// _159: 159; +//// _160: 160; +//// _161: 161; +//// _162: 162; +//// _163: 163; +//// _164: 164; +//// _165: 165; +//// _166: 166; +//// _167: 167; +//// _168: 168; +//// _169: 169; +//// _170: 170; +//// _171: 171; +//// _172: 172; +//// _173: 173; +//// _174: 174; +//// _175: 175; +//// _176: 176; +//// _177: 177; +//// _178: 178; +//// _179: 179; +//// _180: 180; +//// _181: 181; +//// _182: 182; +//// _183: 183; +//// _184: 184; +//// _185: 185; +//// _186: 186; +//// _187: 187; +//// _188: 188; +//// _189: 189; +//// _190: 190; +//// _191: 191; +//// _192: 192; +//// _193: 193; +//// _194: 194; +//// _195: 195; +//// _196: 196; +//// _197: 197; +//// _198: 198; +//// _199: 199; +//// _200: 200; +//// _201: 201; +//// _202: 202; +//// _203: 203; +//// _204: 204; +//// _205: 205; +//// _206: 206; +//// _207: 207; +//// _208: 208; +//// _209: 209; +//// _210: 210; +//// _211: 211; +//// _212: 212; +//// _213: 213; +//// _214: 214; +//// _215: 215; +//// _216: 216; +//// _217: 217; +//// _218: 218; +//// _219: 219; +//// _220: 220; +//// _221: 221; +//// _222: 222; +//// _223: 223; +//// _224: 224; +//// _225: 225; +//// _226: 226; +//// _227: 227; +//// _228: 228; +//// _229: 229; +//// _230: 230; +//// _231: 231; +//// _232: 232; +//// _233: 233; +//// _234: 234; +//// _235: 235; +//// _236: 236; +//// _237: 237; +//// _238: 238; +//// _239: 239; +//// _240: 240; +//// _241: 241; +//// _242: 242; +//// _243: 243; +//// _244: 244; +//// _245: 245; +//// _246: 246; +//// _247: 247; +//// _248: 248; +//// _249: 249; +//// _250: 250; +//// _251: 251; +//// _252: 252; +//// _253: 253; +//// _254: 254; +//// _255: 255; +//// _256: 256; +//// _257: 257; +//// _258: 258; +//// _259: 259; +//// _260: 260; +//// _261: 261; +//// _262: 262; +//// _263: 263; +//// _264: 264; +//// _265: 265; +//// _266: 266; +//// _267: 267; +//// _268: 268; +//// _269: 269; +//// _270: 270; +//// _271: 271; +//// _272: 272; +//// _273: 273; +//// _274: 274; +//// _275: 275; +//// _276: 276; +//// _277: 277; +//// _278: 278; +//// _279: 279; +//// _280: 280; +//// _281: 281; +//// _282: 282; +//// _283: 283; +//// _284: 284; +//// _285: 285; +//// _286: 286; +//// _287: 287; +//// _288: 288; +//// _289: 289; +//// _290: 290; +//// _291: 291; +//// _292: 292; +//// _293: 293; +//// _294: 294; +//// _295: 295; +//// _296: 296; +//// _297: 297; +//// _298: 298; +//// _299: 299; +//// _300: 300; +//// _301: 301; +//// _302: 302; +//// _303: 303; +//// _304: 304; +//// _305: 305; +//// _306: 306; +//// _307: 307; +//// _308: 308; +//// _309: 309; +//// _310: 310; +//// _311: 311; +//// _312: 312; +//// _313: 313; +//// _314: 314; +//// _315: 315; +//// _316: 316; +//// _317: 317; +//// _318: 318; +//// _319: 319; +//// _320: 320; +//// _321: 321; +//// _322: 322; +//// _323: 323; +//// _324: 324; +//// _325: 325; +//// _326: 326; +//// _327: 327; +//// _328: 328; +//// _329: 329; +//// _330: 330; +//// _331: 331; +//// _332: 332; +//// _333: 333; +//// _334: 334; +//// _335: 335; +//// _336: 336; +//// _337: 337; +//// _338: 338; +//// _339: 339; +//// _340: 340; +//// _341: 341; +//// _342: 342; +//// _343: 343; +//// _344: 344; +//// _345: 345; +//// _346: 346; +//// _347: 347; +//// _348: 348; +//// _349: 349; +//// _350: 350; +//// _351: 351; +//// _352: 352; +//// _353: 353; +//// _354: 354; +//// _355: 355; +//// _356: 356; +//// _357: 357; +//// _358: 358; +//// _359: 359; +//// _360: 360; +//// _361: 361; +//// _362: 362; +//// _363: 363; +//// _364: 364; +//// _365: 365; +//// _366: 366; +//// _367: 367; +//// _368: 368; +//// _369: 369; +//// _370: 370; +//// _371: 371; +//// _372: 372; +//// _373: 373; +//// _374: 374; +//// _375: 375; +//// _376: 376; +//// _377: 377; +//// _378: 378; +//// _379: 379; +//// _380: 380; +//// _381: 381; +//// _382: 382; +//// _383: 383; +//// _384: 384; +//// _385: 385; +//// _386: 386; +//// _387: 387; +//// _388: 388; +//// _389: 389; +//// _390: 390; +//// _391: 391; +//// _392: 392; +//// _393: 393; +//// _394: 394; +//// _395: 395; +//// _396: 396; +//// _397: 397; +//// _398: 398; +//// _399: 399; +//// _400: 400; +//// _401: 401; +//// _402: 402; +//// _403: 403; +//// _404: 404; +//// _405: 405; +//// _406: 406; +//// _407: 407; +//// _408: 408; +//// _409: 409; +//// _410: 410; +//// _411: 411; +//// _412: 412; +//// _413: 413; +//// _414: 414; +//// _415: 415; +//// _416: 416; +//// _417: 417; +//// _418: 418; +//// _419: 419; +//// _420: 420; +//// _421: 421; +//// _422: 422; +//// _423: 423; +//// _424: 424; +//// _425: 425; +//// _426: 426; +//// _427: 427; +//// _428: 428; +//// _429: 429; +//// _430: 430; +//// _431: 431; +//// _432: 432; +//// _433: 433; +//// _434: 434; +//// _435: 435; +//// _436: 436; +//// _437: 437; +//// _438: 438; +//// _439: 439; +//// _440: 440; +//// _441: 441; +//// _442: 442; +//// _443: 443; +//// _444: 444; +//// _445: 445; +//// _446: 446; +//// _447: 447; +//// _448: 448; +//// _449: 449; +//// _450: 450; +//// _451: 451; +//// _452: 452; +//// _453: 453; +//// _454: 454; +//// _455: 455; +//// _456: 456; +//// _457: 457; +//// _458: 458; +//// _459: 459; +//// _460: 460; +//// _461: 461; +//// _462: 462; +//// _463: 463; +//// _464: 464; +//// _465: 465; +//// _466: 466; +//// _467: 467; +//// _468: 468; +//// _469: 469; +//// _470: 470; +//// _471: 471; +//// _472: 472; +//// _473: 473; +//// _474: 474; +//// _475: 475; +//// _476: 476; +//// _477: 477; +//// _478: 478; +//// _479: 479; +//// _480: 480; +//// _481: 481; +//// _482: 482; +//// _483: 483; +//// _484: 484; +//// _485: 485; +//// _486: 486; +//// _487: 487; +//// _488: 488; +//// _489: 489; +//// _490: 490; +//// _491: 491; +//// _492: 492; +//// _493: 493; +//// _494: 494; +//// _495: 495; +//// _496: 496; +//// _497: 497; +//// _498: 498; +//// _499: 499; +//// } +//// type A/*1*/ = keyof Foo; +//// type Exclude = T extends U ? never : T; +//// type Less/*2*/ = Exclude; +//// function f(s: T, x: Exclude, y: string) {} +//// f("_499", /*3*/); +//// type Decomposed/*4*/ = {[K in A]: Foo[K]} +//// type LongTuple/*5*/ = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17.18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70]; +//// type DeeplyMapped/*6*/ = {[K in keyof Foo]: {[K2 in keyof Foo]: [K, K2, Foo[K], Foo[K2]]}} + +goTo.marker("1"); +verify.quickInfoIs(`type A = "_0" | "_1" | "_2" | "_3" | "_4" | "_5" | "_6" | "_7" | "_8" | "_9" | "_10" | "_11" | "_12" | "_13" | "_14" | "_15" | "_16" | "_17" | "_18" | "_19" | "_20" | "_21" | "_22" | "_23" | "_24" | ... 474 more ... | "_499"`); +goTo.marker("2"); +verify.quickInfoIs(`type Less = "_1" | "_2" | "_3" | "_4" | "_5" | "_6" | "_7" | "_8" | "_9" | "_10" | "_11" | "_12" | "_13" | "_14" | "_15" | "_16" | "_17" | "_18" | "_19" | "_20" | "_21" | "_22" | "_23" | "_24" | "_25" | ... 473 more ... | "_499"`); +goTo.marker("3"); +verify.signatureHelp({ + marker: "3", + text: `f(s: T, x: Exclude<"_0", T> | Exclude<"_1", T> | Exclude<"_2", T> | Exclude<"_3", T> | Exclude<"_4", T> | Exclude<"_5", T> | Exclude<"_6", T> | Exclude<"_7", T> | Exclude<...> | ... 490 more ... | Exclude<...>, y: string): void` +}); +goTo.marker("4"); +verify.quickInfoIs(`type Decomposed = { + _0: 0; + _1: 1; + _2: 2; + _3: 3; + _4: 4; + _5: 5; + _6: 6; + _7: 7; + _8: 8; + _9: 9; + _10: 10; + _11: 11; + _12: 12; + _13: 13; + _14: 14; + _15: 15; + _16: 16; + _17: 17; + _18: 18; + _19: 19; + _20: 20; + _21: 21; + _22: 22; + _23: 23; + _24: 24; + _25: 25; + _26: 26; + _27: 27; + _28: 28; + _29: 29; + _30: 30; + ... 468 more ...; + _499: 499; +}`); +goTo.marker("5"); +verify.quickInfoIs(`type LongTuple = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17.18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ... 27 more ..., 70]`); +goTo.marker("6"); +verify.quickInfoIs(`type DeeplyMapped = { + _0: { + _0: ["_0", "_0", 0, 0]; + _1: ["_0", "_1", 0, 1]; + _2: ["_0", "_2", 0, 2]; + _3: ["_0", "_3", 0, 3]; + _4: ["_0", "_4", 0, 4]; + _5: ["_0", "_5", 0, 5]; + _6: ["_0", "_6", 0, 6]; + _7: ["_0", "_7", 0, 7]; + ... 491 more ...; + _499: [...]; + }; + ... 498 more ...; + _499: { + ...; + }; +}`);