Skip to content

Commit 52aa4bc

Browse files
committed
Fancy truncation + higher hard limit
1 parent 5de3756 commit 52aa4bc

File tree

7 files changed

+173
-75
lines changed

7 files changed

+173
-75
lines changed

src/compiler/checker.ts

Lines changed: 100 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,9 +2993,6 @@ namespace ts {
29932993
}
29942994

29952995
function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string {
2996-
if (writer.maximumApproximateLength === undefined) {
2997-
writer.maximumApproximateLength = defaultMaximumTruncationLength;
2998-
}
29992996
const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation;
30002997
const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), writer);
30012998
if (typeNode === undefined) return Debug.fail("should always get typenode");
@@ -3005,7 +3002,7 @@ namespace ts {
30053002
printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer);
30063003
const result = writer.getText();
30073004

3008-
const maxLength = noTruncation ? undefined : writer.maximumApproximateLength;
3005+
const maxLength = noTruncation ? undefined : defaultMaximumTruncationLength * 2;
30093006
if (maxLength && result && result.length >= maxLength) {
30103007
return result.substr(0, maxLength - "...".length) + "...";
30113008
}
@@ -3051,6 +3048,11 @@ namespace ts {
30513048
return context.encounteredError ? undefined : resultingNode;
30523049
}
30533050

3051+
function checkTruncationLength(context: NodeBuilderContext): boolean {
3052+
if (context.truncating) return context.truncating;
3053+
return context.truncating = !(context.flags & NodeBuilderFlags.NoTruncation) && context.approximateLength > defaultMaximumTruncationLength;
3054+
}
3055+
30543056
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
30553057
if (cancellationToken && cancellationToken.throwIfCancellationRequested) {
30563058
cancellationToken.throwIfCancellationRequested();
@@ -3063,7 +3065,7 @@ namespace ts {
30633065
return undefined!; // TODO: GH#18217
30643066
}
30653067

3066-
if (type.flags & TypeFlags.Any || (!(context.flags & NodeBuilderFlags.NoTruncation) && context.approximateLength > (context.tracker.maximumApproximateLength || 2000))) {
3068+
if (type.flags & TypeFlags.Any) {
30673069
context.approximateLength += 3;
30683070
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
30693071
}
@@ -3189,10 +3191,9 @@ namespace ts {
31893191
}
31903192
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
31913193
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
3192-
const typeNodes = mapToTypeNodes(types, context);
3194+
const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true);
31933195
if (typeNodes && typeNodes.length > 0) {
31943196
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
3195-
context.approximateLength += (3 * (types.length - 1));
31963197
return unionOrIntersectionTypeNode;
31973198
}
31983199
else {
@@ -3471,6 +3472,9 @@ namespace ts {
34713472
}
34723473

34733474
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined {
3475+
if (checkTruncationLength(context)) {
3476+
return [createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)];
3477+
}
34743478
const typeElements: TypeElement[] = [];
34753479
for (const signature of resolvedType.callSignatures) {
34763480
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context));
@@ -3493,7 +3497,9 @@ namespace ts {
34933497
return typeElements;
34943498
}
34953499

3500+
let i = 0;
34963501
for (const propertySymbol of properties) {
3502+
i++;
34973503
if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) {
34983504
if (propertySymbol.flags & SymbolFlags.Prototype) {
34993505
continue;
@@ -3502,69 +3508,102 @@ namespace ts {
35023508
context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
35033509
}
35043510
}
3505-
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ?
3506-
anyType : getTypeOfSymbol(propertySymbol);
3507-
const saveEnclosingDeclaration = context.enclosingDeclaration;
3508-
context.enclosingDeclaration = undefined;
3509-
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
3510-
const decl = first(propertySymbol.declarations);
3511-
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
3512-
// get symbol of the first identifier of the entityName
3513-
const firstIdentifier = getFirstIdentifier(decl.name.expression);
3514-
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
3515-
if (name) {
3516-
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
3517-
}
3518-
}
3511+
if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
3512+
typeElements.push(createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
3513+
addPropertyToElementList(properties[properties.length - 1], context, typeElements);
3514+
break;
35193515
}
3520-
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
3521-
context.approximateLength += (symbolName(propertySymbol).length + 1);
3522-
context.enclosingDeclaration = saveEnclosingDeclaration;
3523-
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
3524-
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
3525-
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
3526-
for (const signature of signatures) {
3527-
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
3528-
methodDeclaration.name = propertyName;
3529-
methodDeclaration.questionToken = optionalToken;
3530-
if (propertySymbol.valueDeclaration) {
3531-
// Copy comments to node for declaration emit
3532-
setCommentRange(methodDeclaration, propertySymbol.valueDeclaration);
3533-
}
3534-
typeElements.push(methodDeclaration);
3535-
}
3516+
addPropertyToElementList(propertySymbol, context, typeElements);
3517+
3518+
}
3519+
return typeElements.length ? typeElements : undefined;
3520+
}
3521+
}
3522+
3523+
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
3524+
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ?
3525+
anyType : getTypeOfSymbol(propertySymbol);
3526+
const saveEnclosingDeclaration = context.enclosingDeclaration;
3527+
context.enclosingDeclaration = undefined;
3528+
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
3529+
const decl = first(propertySymbol.declarations);
3530+
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
3531+
// get symbol of the first identifier of the entityName
3532+
const firstIdentifier = getFirstIdentifier(decl.name.expression);
3533+
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
3534+
if (name) {
3535+
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
35363536
}
3537-
else {
3538-
const savedFlags = context.flags;
3539-
context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0;
3540-
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
3541-
context.flags = savedFlags;
3542-
3543-
const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
3544-
if (modifiers) {
3545-
context.approximateLength += 9;
3546-
}
3547-
const propertySignature = createPropertySignature(
3548-
modifiers,
3549-
propertyName,
3550-
optionalToken,
3551-
propertyTypeNode,
3552-
/*initializer*/ undefined);
3553-
if (propertySymbol.valueDeclaration) {
3554-
// Copy comments to node for declaration emit
3555-
setCommentRange(propertySignature, propertySymbol.valueDeclaration);
3556-
}
3557-
typeElements.push(propertySignature);
3537+
}
3538+
}
3539+
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
3540+
context.approximateLength += (symbolName(propertySymbol).length + 1);
3541+
context.enclosingDeclaration = saveEnclosingDeclaration;
3542+
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
3543+
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
3544+
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
3545+
for (const signature of signatures) {
3546+
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
3547+
methodDeclaration.name = propertyName;
3548+
methodDeclaration.questionToken = optionalToken;
3549+
if (propertySymbol.valueDeclaration) {
3550+
// Copy comments to node for declaration emit
3551+
setCommentRange(methodDeclaration, propertySymbol.valueDeclaration);
35583552
}
3553+
typeElements.push(methodDeclaration);
35593554
}
3560-
return typeElements.length ? typeElements : undefined;
3555+
}
3556+
else {
3557+
const savedFlags = context.flags;
3558+
context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0;
3559+
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
3560+
context.flags = savedFlags;
3561+
3562+
const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
3563+
if (modifiers) {
3564+
context.approximateLength += 9;
3565+
}
3566+
const propertySignature = createPropertySignature(
3567+
modifiers,
3568+
propertyName,
3569+
optionalToken,
3570+
propertyTypeNode,
3571+
/*initializer*/ undefined);
3572+
if (propertySymbol.valueDeclaration) {
3573+
// Copy comments to node for declaration emit
3574+
setCommentRange(propertySignature, propertySymbol.valueDeclaration);
3575+
}
3576+
typeElements.push(propertySignature);
35613577
}
35623578
}
35633579

3564-
function mapToTypeNodes(types: ReadonlyArray<Type> | undefined, context: NodeBuilderContext): TypeNode[] | undefined {
3580+
function mapToTypeNodes(types: ReadonlyArray<Type> | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined {
35653581
if (some(types)) {
3582+
if (checkTruncationLength(context)) {
3583+
if (!isBareList) {
3584+
return [createTypeReferenceNode("...", /*typeArguments*/ undefined)];
3585+
}
3586+
else if (types.length > 2) {
3587+
return [
3588+
typeToTypeNodeHelper(types[0], context),
3589+
createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined),
3590+
typeToTypeNodeHelper(types[types.length - 1], context)
3591+
];
3592+
}
3593+
}
35663594
const result = [];
3595+
let i = 0;
35673596
for (const type of types) {
3597+
i++;
3598+
if (checkTruncationLength(context) && (i + 2 < types.length - 1)) {
3599+
result.push(createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined));
3600+
const typeNode = typeToTypeNodeHelper(types[types.length - 1], context);
3601+
if (typeNode) {
3602+
result.push(typeNode);
3603+
}
3604+
break;
3605+
}
3606+
context.approximateLength += 2; // Account for whitespace + separator
35683607
const typeNode = typeToTypeNodeHelper(type, context);
35693608
if (typeNode) {
35703609
result.push(typeNode);
@@ -4078,6 +4117,7 @@ namespace ts {
40784117
visitedSymbols: Map<true> | undefined;
40794118
inferTypeParameters: TypeParameter[] | undefined;
40804119
approximateLength: number;
4120+
truncating?: boolean;
40814121
}
40824122

40834123
function isDefaultBindingContext(location: Node) {

src/compiler/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5324,7 +5324,6 @@ namespace ts {
53245324
reportInaccessibleUniqueSymbolError?(): void;
53255325
moduleResolverHost?: ModuleSpecifierResolutionHost;
53265326
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
5327-
maximumApproximateLength?: number;
53285327
}
53295328

53305329
export interface TextSpan {

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace ts {
2121

2222
export const externalHelpersModuleNameText = "tslib";
2323

24-
export const defaultMaximumTruncationLength = 240;
24+
export const defaultMaximumTruncationLength = 160;
2525

2626
export function getDeclarationOfKind<T extends Declaration>(symbol: Symbol, kind: T["kind"]): T | undefined {
2727
const declarations = symbol.declarations;

src/services/utilities.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,7 @@ namespace ts {
14351435

14361436
const displayPartWriter = getDisplayPartWriter();
14371437
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
1438-
const maximumApproximateLength = defaultMaximumTruncationLength;
1438+
const absoluteMaximumLength = defaultMaximumTruncationLength * 10; // A hard cutoff to avoid overloading the messaging channel in worst-case scenarios
14391439
let displayParts: SymbolDisplayPart[];
14401440
let lineStart: boolean;
14411441
let indent: number;
@@ -1446,7 +1446,7 @@ namespace ts {
14461446
return {
14471447
displayParts: () => {
14481448
const finalText = displayParts.length && displayParts[displayParts.length - 1].text;
1449-
if (length > maximumApproximateLength && finalText && finalText !== "...") {
1449+
if (length > absoluteMaximumLength && finalText && finalText !== "...") {
14501450
if (!isWhiteSpaceLike(finalText.charCodeAt(finalText.length - 1))) {
14511451
displayParts.push(displayPart(" ", SymbolDisplayPartKind.space));
14521452
}
@@ -1480,11 +1480,10 @@ namespace ts {
14801480
reportInaccessibleThisError: noop,
14811481
reportInaccessibleUniqueSymbolError: noop,
14821482
reportPrivateInBaseOfClassExpression: noop,
1483-
maximumApproximateLength, // Limit output to about 2000 characters
14841483
};
14851484

14861485
function writeIndent() {
1487-
if (length > maximumApproximateLength) return;
1486+
if (length > absoluteMaximumLength) return;
14881487
if (lineStart) {
14891488
const indentString = getIndentString(indent);
14901489
if (indentString) {
@@ -1496,21 +1495,21 @@ namespace ts {
14961495
}
14971496

14981497
function writeKind(text: string, kind: SymbolDisplayPartKind) {
1499-
if (length > maximumApproximateLength) return;
1498+
if (length > absoluteMaximumLength) return;
15001499
writeIndent();
15011500
length += text.length;
15021501
displayParts.push(displayPart(text, kind));
15031502
}
15041503

15051504
function writeSymbol(text: string, symbol: Symbol) {
1506-
if (length > maximumApproximateLength) return;
1505+
if (length > absoluteMaximumLength) return;
15071506
writeIndent();
15081507
length += text.length;
15091508
displayParts.push(symbolPart(text, symbol));
15101509
}
15111510

15121511
function writeLine() {
1513-
if (length > maximumApproximateLength) return;
1512+
if (length > absoluteMaximumLength) return;
15141513
length += 1;
15151514
displayParts.push(lineBreakPart());
15161515
lineStart = true;

0 commit comments

Comments
 (0)