diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f77641faf5cc..985893023a30b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -111,7 +111,10 @@ import { createGetCanonicalFileName, createGetSymbolWalker, createModeAwareCacheKey, - createPrinter, + createPrinterWithDefaults, + createPrinterWithRemoveComments, + createPrinterWithRemoveCommentsNeverAsciiEscape, + createPrinterWithRemoveCommentsOmitTrailingSemicolon, createPropertyNameNodeForIdentifierOrLiteral, createSymbolTable, createTextWriter, @@ -6123,7 +6126,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function symbolToStringWorker(writer: EmitTextWriter) { const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 - const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createPrinter({ removeComments: true, neverAsciiEscape: true }) : createPrinter({ removeComments: true }); + const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile + ? createPrinterWithRemoveCommentsNeverAsciiEscape() + : createPrinterWithRemoveComments(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer; @@ -6142,7 +6147,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; } const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 return writer; @@ -6155,8 +6160,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeNode === undefined) return Debug.fail("should always get typenode"); // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. // Otherwise, we always strip comments out. - const options = { removeComments: type !== unresolvedType }; - const printer = createPrinter(options); + const printer = type !== unresolvedType ? createPrinterWithRemoveComments() : createPrinterWithDefaults(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); @@ -9636,7 +9640,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 ); - const printer = createPrinter({ removeComments: true }); + const printer = createPrinterWithRemoveComments(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, predicate, /*sourceFile*/ sourceFile, writer); return writer; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 170ad79e7d587..e81f2b090a8ae 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1343,6 +1343,18 @@ const enum PipelinePhase { Emit, } +/** @internal */ +export const createPrinterWithDefaults = memoize(() => createPrinter({})); + +/** @internal */ +export const createPrinterWithRemoveComments = memoize(() => createPrinter({ removeComments: true })); + +/** @internal */ +export const createPrinterWithRemoveCommentsNeverAsciiEscape = memoize(() => createPrinter({ removeComments: true, neverAsciiEscape: true })); + +/** @internal */ +export const createPrinterWithRemoveCommentsOmitTrailingSemicolon = memoize(() => createPrinter({ removeComments: true, omitTrailingSemicolon: true })); + export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { const { hasGlobalName, diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index fc4280802ee6d..a2d32e6da717f 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -14,7 +14,7 @@ import { ClassLikeDeclaration, ClassStaticBlockDeclaration, compareStringsCaseSensitive, - createPrinter, + createPrinterWithRemoveCommentsOmitTrailingSemicolon, createTextRangeFromNode, createTextSpanFromBounds, createTextSpanFromRange, @@ -245,7 +245,7 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati } if (text === undefined) { // get the text from printing the node on a single line without comments... - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); } return { text, pos: declName.getStart(), end: declName.getEnd() }; diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index 5544aaa920c02..49b113e927554 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -2,7 +2,7 @@ import { __String, ArrowFunction, CallExpression, - createPrinter, + createPrinterWithRemoveComments, Debug, EmitHint, EnumMember, @@ -53,7 +53,6 @@ import { NodeBuilderFlags, ParameterDeclaration, PrefixUnaryExpression, - PrinterOptions, PropertyDeclaration, Signature, skipParentheses, @@ -383,8 +382,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function printTypeInSingleLine(type: Type) { const flags = NodeBuilderFlags.IgnoreErrors | TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope; - const options: PrinterOptions = { removeComments: true }; - const printer = createPrinter(options); + const printer = createPrinterWithRemoveComments(); return usingSingleLineStringWriter(writer => { const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags); diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index f662021481c4c..c8923140c4935 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -7,7 +7,7 @@ import { CheckFlags, contains, countWhere, - createPrinter, + createPrinterWithRemoveComments, createTextSpan, createTextSpanFromBounds, createTextSpanFromNode, @@ -659,7 +659,7 @@ function createTypeHelpItems( function getTypeHelpItem(symbol: Symbol, typeParameters: readonly TypeParameter[], checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem { const typeSymbolDisplay = symbolToDisplayParts(checker, symbol); - const printer = createPrinter({ removeComments: true }); + const printer = createPrinterWithRemoveComments(); const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); const documentation = symbol.getDocumentationComment(checker); @@ -699,7 +699,7 @@ interface SignatureHelpItemInfo { readonly isVariadic: boolean; readonly paramet function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { const typeParameters = (candidateSignature.target || candidateSignature).typeParameters; - const printer = createPrinter({ removeComments: true }); + const printer = createPrinterWithRemoveComments(); const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : []; @@ -713,7 +713,7 @@ function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeC } function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { - const printer = createPrinter({ removeComments: true }); + const printer = createPrinterWithRemoveComments(); const typeParameterParts = mapToDisplayParts(writer => { if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { const args = factory.createNodeArray(candidateSignature.typeParameters.map(p => checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)); diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index bda7ba595090c..be2e83a48bb2f 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -5,7 +5,7 @@ import { CallExpression, CheckFlags, contains, - createPrinter, + createPrinterWithRemoveComments, Debug, displayPart, EmitHint, @@ -75,7 +75,6 @@ import { NodeBuilderFlags, ObjectFlags, operatorPart, - Printer, PropertyAccessExpression, PropertyDeclaration, punctuationPart, @@ -259,7 +258,6 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ let hasAddedSymbolInfo = false; const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) || isThisInTypeQuery(location); let type: Type | undefined; - let printer: Printer; let documentationFromAlias: SymbolDisplayPart[] | undefined; let tagsFromAlias: JSDocTagInfo[] | undefined; let hasMultipleSignatures = false; @@ -730,10 +728,7 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ return { displayParts, documentation, symbolKind, tags: tags.length === 0 ? undefined : tags }; function getPrinter() { - if (!printer) { - printer = createPrinter({ removeComments: true }); - } - return printer; + return createPrinterWithRemoveComments(); } function prefixNextMeaning() { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e3de3b3014744..9935d419b2c4b 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -30,7 +30,7 @@ import { ConditionalExpression, contains, ContextFlags, - createPrinter, + createPrinterWithRemoveCommentsOmitTrailingSemicolon, createRange, createScanner, createTextSpan, @@ -2984,7 +2984,7 @@ export function signatureToDisplayParts(typechecker: TypeChecker, signature: Sig export function nodeToDisplayParts(node: Node, enclosingDeclaration: Node): SymbolDisplayPart[] { const file = enclosingDeclaration.getSourceFile(); return mapToDisplayParts(writer => { - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); printer.writeNode(EmitHint.Unspecified, node, file, writer); }); }