From cd3afe4f0c261f65404c230f22ab555a761cb1b4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 23 Jan 2023 19:31:30 -0800 Subject: [PATCH 1/9] Reuse Printers in symbolToStringWorker --- src/compiler/checker.ts | 9 ++++++++- src/compiler/core.ts | 30 ++++++++++++++++++++++++++++++ src/compiler/emitter.ts | 3 ++- src/compiler/types.ts | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f77641faf5cc..020c509a96526 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -871,6 +871,7 @@ import { pathIsRelative, PatternAmbientModule, PlusToken, + pooled, PostfixUnaryExpression, PrefixUnaryExpression, PrivateIdentifier, @@ -2173,6 +2174,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { [".json", ".json"], ]; + const symbolToStringWorkerSourceFilePrinter = pooled(() => createPrinter({ removeComments: true, neverAsciiEscape: true }), (printer) => printer.reset()); + const symbolToStringWorkerNonSourceFilePrinter = pooled(() => createPrinter({ removeComments: true }), (printer) => printer.reset()); + initializeTypeChecker(); return checker; @@ -6123,9 +6127,12 @@ 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, disposePrinter] = enclosingDeclaration?.kind === SyntaxKind.SourceFile + ? symbolToStringWorkerSourceFilePrinter() + : symbolToStringWorkerNonSourceFilePrinter(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); + disposePrinter(); return writer; } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 2dc7f533c766a..b308c8e2c3ffa 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2917,3 +2917,33 @@ export function isNodeLikeSystem(): boolean { && !process.browser && typeof module === "object"; } + +/** @internal */ +export function pooled(fn: () => T, reset: (value: T) => void): () => [value: T, dispose: () => void] { + // TODO(jakebailey): this is supposed to be something like Go's sync.Pool, + // but I don't know of a way to "eventually" return the pool's contents to GC. + // For now, this just holds onto the objects even when they may not have been + // in use for a long time. + const pool: T[] = []; + + return () => { + let value: T; + if (pool.length > 1) { + const end = pool.length - 1; + value = pool[end]; + pool.length = end; + } + else { + value = fn(); + } + + const dispose = () => { + if (pool.length < 8) { + reset(value); + pool.push(value); + } + }; + + return [value, dispose]; + }; +} diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 170ad79e7d587..1266772ba801d 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1428,7 +1428,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeList, writeFile, writeBundle, - bundleFileInfo + bundleFileInfo, + reset, }; function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a43afe978ea4..758fa517c0b40 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9165,6 +9165,7 @@ export interface Printer { /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; /** @deprecated @internal */ bundleFileInfo?: BundleFileInfo; + /** @internal */ reset(): void; } /** @deprecated @internal */ From db730c9c6ec5e245eba809411694dee9b2dc0f5d Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 23 Jan 2023 20:11:08 -0800 Subject: [PATCH 2/9] Simplify greatly --- src/compiler/checker.ts | 8 +++----- src/compiler/core.ts | 30 ------------------------------ 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 020c509a96526..c69ac537836b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -871,7 +871,6 @@ import { pathIsRelative, PatternAmbientModule, PlusToken, - pooled, PostfixUnaryExpression, PrefixUnaryExpression, PrivateIdentifier, @@ -2174,8 +2173,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { [".json", ".json"], ]; - const symbolToStringWorkerSourceFilePrinter = pooled(() => createPrinter({ removeComments: true, neverAsciiEscape: true }), (printer) => printer.reset()); - const symbolToStringWorkerNonSourceFilePrinter = pooled(() => createPrinter({ removeComments: true }), (printer) => printer.reset()); + const symbolToStringWorkerSourceFilePrinter = memoize(() => createPrinter({ removeComments: true, neverAsciiEscape: true })); + const symbolToStringWorkerNonSourceFilePrinter = memoize(() => createPrinter({ removeComments: true })); initializeTypeChecker(); @@ -6127,12 +6126,11 @@ 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, disposePrinter] = enclosingDeclaration?.kind === SyntaxKind.SourceFile + const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? symbolToStringWorkerSourceFilePrinter() : symbolToStringWorkerNonSourceFilePrinter(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); - disposePrinter(); return writer; } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index b308c8e2c3ffa..2dc7f533c766a 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2917,33 +2917,3 @@ export function isNodeLikeSystem(): boolean { && !process.browser && typeof module === "object"; } - -/** @internal */ -export function pooled(fn: () => T, reset: (value: T) => void): () => [value: T, dispose: () => void] { - // TODO(jakebailey): this is supposed to be something like Go's sync.Pool, - // but I don't know of a way to "eventually" return the pool's contents to GC. - // For now, this just holds onto the objects even when they may not have been - // in use for a long time. - const pool: T[] = []; - - return () => { - let value: T; - if (pool.length > 1) { - const end = pool.length - 1; - value = pool[end]; - pool.length = end; - } - else { - value = fn(); - } - - const dispose = () => { - if (pool.length < 8) { - reset(value); - pool.push(value); - } - }; - - return [value, dispose]; - }; -} From 93039027d3268c844fa8cd18b7566576ff035de0 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 23 Jan 2023 20:11:44 -0800 Subject: [PATCH 3/9] Remove reset in API --- src/compiler/emitter.ts | 1 - src/compiler/types.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 1266772ba801d..5ed6de9b5dbc2 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1429,7 +1429,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeFile, writeBundle, bundleFileInfo, - reset, }; function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 758fa517c0b40..0a43afe978ea4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9165,7 +9165,6 @@ export interface Printer { /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; /** @deprecated @internal */ bundleFileInfo?: BundleFileInfo; - /** @internal */ reset(): void; } /** @deprecated @internal */ From 8610e66631d59a38677b8d940010c7815f8e3c56 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 23 Jan 2023 20:13:14 -0800 Subject: [PATCH 4/9] Minimize diff --- src/compiler/emitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5ed6de9b5dbc2..170ad79e7d587 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1428,7 +1428,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeList, writeFile, writeBundle, - bundleFileInfo, + bundleFileInfo }; function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { From 6d99c8f7c99b0231092c1a849bee30d556db4d18 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 23 Jan 2023 20:36:59 -0800 Subject: [PATCH 5/9] Reuse a lot more printers --- src/compiler/checker.ts | 19 +++++++++---------- src/compiler/emitter.ts | 12 ++++++++++++ src/services/callHierarchy.ts | 4 ++-- src/services/inlayHints.ts | 6 ++---- src/services/signatureHelp.ts | 8 ++++---- src/services/utilities.ts | 4 ++-- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c69ac537836b6..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, @@ -2173,9 +2176,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { [".json", ".json"], ]; - const symbolToStringWorkerSourceFilePrinter = memoize(() => createPrinter({ removeComments: true, neverAsciiEscape: true })); - const symbolToStringWorkerNonSourceFilePrinter = memoize(() => createPrinter({ removeComments: true })); - initializeTypeChecker(); return checker; @@ -6127,8 +6127,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile - ? symbolToStringWorkerSourceFilePrinter() - : symbolToStringWorkerNonSourceFilePrinter(); + ? createPrinterWithRemoveCommentsNeverAsciiEscape() + : createPrinterWithRemoveComments(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer; @@ -6147,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; @@ -6160,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(); @@ -9641,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/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); }); } From 4102e953faf39bcf98ee0d59427db5349412787b Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:40:11 -0800 Subject: [PATCH 6/9] Reuse new createPrinter functions in symbolDisplay --- src/services/symbolDisplay.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) 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() { From 28dfb919a032fdea9ac9b0d41711369b1628d4bc Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 24 Jan 2023 13:04:17 -0800 Subject: [PATCH 7/9] Use a cache with a key on subset of options --- src/compiler/checker.ts | 16 +++++++--------- src/compiler/emitter.ts | 24 ++++++++++++++++++------ src/services/callHierarchy.ts | 4 ++-- src/services/completions.ts | 3 ++- src/services/inlayHints.ts | 4 ++-- src/services/signatureHelp.ts | 8 ++++---- src/services/symbolDisplay.ts | 4 ++-- src/services/utilities.ts | 4 ++-- 8 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 985893023a30b..32cf2fa054ef1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -111,10 +111,7 @@ import { createGetCanonicalFileName, createGetSymbolWalker, createModeAwareCacheKey, - createPrinterWithDefaults, - createPrinterWithRemoveComments, - createPrinterWithRemoveCommentsNeverAsciiEscape, - createPrinterWithRemoveCommentsOmitTrailingSemicolon, + createOrReusePrinter, createPropertyNameNodeForIdentifierOrLiteral, createSymbolTable, createTextWriter, @@ -6127,8 +6124,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile - ? createPrinterWithRemoveCommentsNeverAsciiEscape() - : createPrinterWithRemoveComments(); + ? createOrReusePrinter({ removeComments: true, neverAsciiEscape: true }) + : createOrReusePrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer; @@ -6147,7 +6144,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 = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 return writer; @@ -6160,7 +6157,8 @@ 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 printer = type !== unresolvedType ? createPrinterWithRemoveComments() : createPrinterWithDefaults(); + const options = { removeComments: type !== unresolvedType }; + const printer = createOrReusePrinter(options); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); @@ -9640,7 +9638,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 = createPrinterWithRemoveComments(); + const printer = createOrReusePrinter({ removeComments: true }); 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 e81f2b090a8ae..289383c99c954 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1343,17 +1343,29 @@ const enum PipelinePhase { Emit, } -/** @internal */ -export const createPrinterWithDefaults = memoize(() => createPrinter({})); +const printerCache = new Map(); +// If updating this, make sure the cache key is updated too. /** @internal */ -export const createPrinterWithRemoveComments = memoize(() => createPrinter({ removeComments: true })); +export type ReusablePrinterOptions = Pick; /** @internal */ -export const createPrinterWithRemoveCommentsNeverAsciiEscape = memoize(() => createPrinter({ removeComments: true, neverAsciiEscape: true })); +export function createOrReusePrinter(o: ReusablePrinterOptions = {}) { + const key = `${keyBool(o.removeComments)}|${keyBool(o.neverAsciiEscape)}|${keyBool(o.omitTrailingSemicolon)}|${keyNum(o.module)}|${keyNum(o.target)}|${keyNum(o.newLine)}`; + let printer = printerCache.get(key); + if (!printer) { + printerCache.set(key, printer = createPrinter(o)); + } + return printer; -/** @internal */ -export const createPrinterWithRemoveCommentsOmitTrailingSemicolon = memoize(() => createPrinter({ removeComments: true, omitTrailingSemicolon: true })); + function keyBool(value: boolean | undefined) { + return value === undefined ? "u" : value ? 1 : 0; + } + + function keyNum(value: number | undefined) { + return value === undefined ? "u" : `${value}`; + } +} export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { const { diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index a2d32e6da717f..fafa979780fbf 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -14,7 +14,7 @@ import { ClassLikeDeclaration, ClassStaticBlockDeclaration, compareStringsCaseSensitive, - createPrinterWithRemoveCommentsOmitTrailingSemicolon, + createOrReusePrinter, 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 = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); } return { text, pos: declName.getStart(), end: declName.getEnd() }; diff --git a/src/services/completions.ts b/src/services/completions.ts index 4193e651a037f..b538e0566ef62 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -34,6 +34,7 @@ import { ConstructorDeclaration, ContextFlags, createModuleSpecifierResolutionHost, + createOrReusePrinter, createPackageJsonImportFilter, createPrinter, createSortedArray, @@ -1747,7 +1748,7 @@ function getEntryForObjectLiteralMethodCompletion( insertText = printer.printSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile); } - const signaturePrinter = createPrinter({ + const signaturePrinter = createOrReusePrinter({ removeComments: true, module: options.module, target: options.target, diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index 49b113e927554..5f8d9ab7810af 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -2,7 +2,7 @@ import { __String, ArrowFunction, CallExpression, - createPrinterWithRemoveComments, + createOrReusePrinter, Debug, EmitHint, EnumMember, @@ -382,7 +382,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function printTypeInSingleLine(type: Type) { const flags = NodeBuilderFlags.IgnoreErrors | TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope; - const printer = createPrinterWithRemoveComments(); + const printer = createOrReusePrinter({ removeComments: true }); return usingSingleLineStringWriter(writer => { const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags); diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index c8923140c4935..745756503ce21 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -7,7 +7,7 @@ import { CheckFlags, contains, countWhere, - createPrinterWithRemoveComments, + createOrReusePrinter, 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 = createPrinterWithRemoveComments(); + const printer = createOrReusePrinter({ removeComments: true }); 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 = createPrinterWithRemoveComments(); + const printer = createOrReusePrinter({ removeComments: true }); 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 = createPrinterWithRemoveComments(); + const printer = createOrReusePrinter({ removeComments: true }); 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 be2e83a48bb2f..a0a9059379d62 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -5,7 +5,7 @@ import { CallExpression, CheckFlags, contains, - createPrinterWithRemoveComments, + createOrReusePrinter, Debug, displayPart, EmitHint, @@ -728,7 +728,7 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ return { displayParts, documentation, symbolKind, tags: tags.length === 0 ? undefined : tags }; function getPrinter() { - return createPrinterWithRemoveComments(); + return createOrReusePrinter({ removeComments: true }); } function prefixNextMeaning() { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 9935d419b2c4b..1a53d38f9dfea 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -30,7 +30,7 @@ import { ConditionalExpression, contains, ContextFlags, - createPrinterWithRemoveCommentsOmitTrailingSemicolon, + createOrReusePrinter, 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 = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); printer.writeNode(EmitHint.Unspecified, node, file, writer); }); } From 2f48ec3b575505fbd9634ed99e9fa28482ea2233 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 24 Jan 2023 13:04:32 -0800 Subject: [PATCH 8/9] messing around with printhelpers --- src/compiler/emitter.ts | 97 +++++++++++++++++++++---------------- src/compiler/types.ts | 8 +-- src/services/completions.ts | 11 ++--- src/services/textChanges.ts | 6 +-- 4 files changed, 67 insertions(+), 55 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 289383c99c954..d9317f267b27c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1347,11 +1347,11 @@ const printerCache = new Map(); // If updating this, make sure the cache key is updated too. /** @internal */ -export type ReusablePrinterOptions = Pick; +export type ReusablePrinterOptions = Pick; /** @internal */ export function createOrReusePrinter(o: ReusablePrinterOptions = {}) { - const key = `${keyBool(o.removeComments)}|${keyBool(o.neverAsciiEscape)}|${keyBool(o.omitTrailingSemicolon)}|${keyNum(o.module)}|${keyNum(o.target)}|${keyNum(o.newLine)}`; + const key = `${keyBool(o.removeComments)}|${keyBool(o.neverAsciiEscape)}|${keyBool(o.omitTrailingSemicolon)}|${keyNum(o.module)}|${keyNum(o.target)}|${keyNum(o.newLine)}|${keyBool(o.preserveSourceNewlines)}|${keyBool(o.terminateUnterminatedLiterals)}`; let printer = printerCache.get(key); if (!printer) { printerCache.set(key, printer = createPrinter(o)); @@ -1368,18 +1368,19 @@ export function createOrReusePrinter(o: ReusablePrinterOptions = {}) { } export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { - const { - hasGlobalName, - onEmitNode = noEmitNotification, - isEmitNotificationEnabled, - substituteNode = noEmitSubstitution, - onBeforeEmitNode, - onAfterEmitNode, - onBeforeEmitNodeArray, - onAfterEmitNodeArray, - onBeforeEmitToken, - onAfterEmitToken - } = handlers; + let theHandlers!: PrintHandlers & Required>; + + function setHandlers(newHandlers?: PrintHandlers) { + if (newHandlers) { + theHandlers = { + onEmitNode: noEmitNotification, + substituteNode: noEmitSubstitution, + ...newHandlers, + }; + } + } + + setHandlers(handlers); const extendedDiagnostics = !!printerOptions.extendedDiagnostics; const newLine = getNewLineCharacter(printerOptions); @@ -1499,18 +1500,23 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri /** * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`. */ - function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter): void; - function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter): void; - function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter, handlers?: PrintHandlers): void; + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter, handlers?: PrintHandlers): void; + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter, handlers?: PrintHandlers) { const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, /*_sourceMapGenerator*/ undefined); print(hint, node, sourceFile); reset(); writer = previousWriter; + theHandlers = previousHandlers; } - function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter, handlers?: PrintHandlers) { const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, /*_sourceMapGenerator*/ undefined); if (sourceFile) { setSourceFile(sourceFile); @@ -1518,6 +1524,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitList(/*parentNode*/ undefined, nodes, format); reset(); writer = previousWriter; + theHandlers = previousHandlers; } function getTextPosWithWriteLine() { @@ -1566,9 +1573,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return false; } - function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers) { isOwnFileEmit = false; const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, sourceMapGenerator); emitShebangIfNeeded(bundle); emitPrologueDirectivesIfNeeded(bundle); @@ -1623,6 +1632,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri reset(); writer = previousWriter; + theHandlers = previousHandlers; } function writeUnparsedSource(unparsed: UnparsedSource, output: EmitTextWriter) { @@ -1633,15 +1643,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writer = previousWriter; } - function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers) { isOwnFileEmit = true; const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, sourceMapGenerator); emitShebangIfNeeded(sourceFile); emitPrologueDirectivesIfNeeded(sourceFile); print(EmitHint.SourceFile, sourceFile, sourceFile); reset(); writer = previousWriter; + theHandlers = previousHandlers; } function beginPrint() { @@ -1765,12 +1778,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) { switch (phase) { case PipelinePhase.Notification: - if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { + if (theHandlers.onEmitNode !== noEmitNotification && (!theHandlers.isEmitNotificationEnabled || theHandlers.isEmitNotificationEnabled(node))) { return pipelineEmitWithNotification; } // falls through case PipelinePhase.Substitution: - if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node) || node) !== node) { + if (theHandlers.substituteNode !== noEmitSubstitution && (lastSubstitution = theHandlers.substituteNode(emitHint, node) || node) !== node) { if (currentParenthesizerRule) { lastSubstitution = currentParenthesizerRule(lastSubstitution); } @@ -1800,11 +1813,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function pipelineEmitWithNotification(hint: EmitHint, node: Node) { const pipelinePhase = getNextPipelinePhase(PipelinePhase.Notification, hint, node); - onEmitNode(hint, node, pipelinePhase); + theHandlers.onEmitNode(hint, node, pipelinePhase); } function pipelineEmitWithHint(hint: EmitHint, node: Node): void { - onBeforeEmitNode?.(node); + theHandlers.onBeforeEmitNode?.(node); if (preserveSourceNewlines) { const savedPreserveSourceNewlines = preserveSourceNewlines; beforeEmitNode(node); @@ -1814,7 +1827,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri else { pipelineEmitWithHintWorker(hint, node); } - onAfterEmitNode?.(node); + theHandlers.onAfterEmitNode?.(node); // clear the parenthesizer rule as we ascend currentParenthesizerRule = undefined; } @@ -2185,8 +2198,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } if (isExpression(node)) { hint = EmitHint.Expression; - if (substituteNode !== noEmitSubstitution) { - const substitute = substituteNode(hint, node) || node; + if (theHandlers.substituteNode !== noEmitSubstitution) { + const substitute = theHandlers.substituteNode(hint, node) || node; if (substitute !== node) { node = substitute; if (currentParenthesizerRule) { @@ -3227,7 +3240,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri state.declarationListContainerEndStack[state.stackIndex] = declarationListContainerEnd; const emitComments = state.shouldEmitCommentsStack[state.stackIndex] = shouldEmitComments(node); const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps(node); - onBeforeEmitNode?.(node); + theHandlers.onBeforeEmitNode?.(node); if (emitComments) emitCommentsBeforeNode(node); if (emitSourceMaps) emitSourceMapsBeforeNode(node); beforeEmitNode(node); @@ -3279,7 +3292,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri afterEmitNode(savedPreserveSourceNewlines); if (shouldEmitSourceMaps) emitSourceMapsAfterNode(node); if (shouldEmitComments) emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); - onAfterEmitNode?.(node); + theHandlers.onAfterEmitNode?.(node); state.stackIndex--; } } @@ -3780,7 +3793,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitBlockFunctionBody(body: Block) { - onBeforeEmitNode?.(body); + theHandlers.onBeforeEmitNode?.(body); writeSpace(); writePunctuation("{"); increaseIndent(); @@ -3793,7 +3806,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri decreaseIndent(); writeToken(SyntaxKind.CloseBraceToken, body.statements.end, writePunctuation, body); - onAfterEmitNode?.(body); + theHandlers.onAfterEmitNode?.(body); } function emitBlockFunctionBodyOnSingleLine(body: Block) { @@ -4761,7 +4774,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return node.pos; } - onBeforeEmitNodeArray?.(modifiers); + theHandlers.onBeforeEmitNodeArray?.(modifiers); // partition modifiers into contiguous chunks of `Modifier` or `Decorator` let lastMode: "modifiers" | "decorators" | undefined; @@ -4803,7 +4816,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri pos++; } - onAfterEmitNodeArray?.(modifiers); + theHandlers.onAfterEmitNodeArray?.(modifiers); if (lastModifier && !positionIsSynthesized(lastModifier.end)) { return lastModifier.end; @@ -4978,8 +4991,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const isEmpty = children === undefined || start >= children.length || count === 0; if (isEmpty && format & ListFormat.OptionalIfEmpty) { - onBeforeEmitNodeArray?.(children); - onAfterEmitNodeArray?.(children); + theHandlers.onBeforeEmitNodeArray?.(children); + theHandlers.onAfterEmitNodeArray?.(children); return; } @@ -4990,7 +5003,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - onBeforeEmitNodeArray?.(children); + theHandlers.onBeforeEmitNodeArray?.(children); if (isEmpty) { // Write a line terminator if the parent node was multi-line @@ -5005,7 +5018,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitNodeListItems(emit, parentNode, children, format, parenthesizerRule, start, count, children.hasTrailingComma, children); } - onAfterEmitNodeArray?.(children); + theHandlers.onAfterEmitNodeArray?.(children); if (format & ListFormat.BracketsMask) { if (isEmpty && children) { @@ -5231,12 +5244,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function writeTokenNode(node: Node, writer: (s: string) => void) { - if (onBeforeEmitToken) { - onBeforeEmitToken(node); + if (theHandlers.onBeforeEmitToken) { + theHandlers.onBeforeEmitToken(node); } writer(tokenToString(node.kind)!); - if (onAfterEmitToken) { - onAfterEmitToken(node); + if (theHandlers.onAfterEmitToken) { + theHandlers.onAfterEmitToken(node); } } @@ -5778,7 +5791,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * when `isfileLevelUniqueName` is passed as a callback to `makeUniqueName`. */ function isFileLevelUniqueName(name: string, _isPrivate: boolean) { - return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, hasGlobalName) : true; + return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, theHandlers.hasGlobalName) : true; } /** diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a43afe978ea4..702969fc1183e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9160,10 +9160,10 @@ export interface Printer { * Prints a bundle of source files as-is, without any emit transformations. */ printBundle(bundle: Bundle): string; - /** @internal */ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; - /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; + /** @internal */ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter, handlers?: PrintHandlers): void; + /** @internal */ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter, handlers?: PrintHandlers): void; + /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers): void; + /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers): void; /** @deprecated @internal */ bundleFileInfo?: BundleFileInfo; } diff --git a/src/services/completions.ts b/src/services/completions.ts index b538e0566ef62..1c312a57dcd7f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -36,7 +36,6 @@ import { createModuleSpecifierResolutionHost, createOrReusePrinter, createPackageJsonImportFilter, - createPrinter, createSortedArray, createTextRangeFromSpan, createTextSpanFromBounds, @@ -292,7 +291,6 @@ import { positionBelongsToNode, positionIsASICandidate, positionsAreOnSameLine, - PrinterOptions, probablyUsesSemicolons, Program, programContainsModules, @@ -308,6 +306,7 @@ import { rangeContainsPosition, rangeContainsPositionExclusive, rangeIsOnSingleLine, + ReusablePrinterOptions, ScriptElementKind, ScriptElementKindModifier, ScriptTarget, @@ -1851,11 +1850,11 @@ function createObjectLiteralMethod( } function createSnippetPrinter( - printerOptions: PrinterOptions, + printerOptions: ReusablePrinterOptions, ) { let escapes: TextChange[] | undefined; const baseWriter = textChanges.createWriter(getNewLineCharacter(printerOptions)); - const printer = createPrinter(printerOptions, baseWriter); + const printer = createOrReusePrinter(printerOptions); const writer: EmitTextWriter = { ...baseWriter, write: s => escapingWrite(s, () => baseWriter.write(s)), @@ -1909,7 +1908,7 @@ function createSnippetPrinter( ): string { escapes = undefined; writer.clear(); - printer.writeList(format, list, sourceFile, writer); + printer.writeList(format, list, sourceFile, writer, baseWriter); return writer.getText(); } @@ -1956,7 +1955,7 @@ function createSnippetPrinter( function printUnescapedNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { escapes = undefined; writer.clear(); - printer.writeNode(hint, node, sourceFile, writer); + printer.writeNode(hint, node, sourceFile, writer, baseWriter); return writer.getText(); } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 50621f641601d..d4fea865d443d 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -11,7 +11,7 @@ import { ConstructorDeclaration, contains, createNodeFactory, - createPrinter, + createOrReusePrinter, createRange, createSourceFile, createTextChange, @@ -1301,12 +1301,12 @@ namespace changesToText { export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } { const writer = createWriter(newLineCharacter); const newLine = getNewLineKind(newLineCharacter); - createPrinter({ + createOrReusePrinter({ newLine, neverAsciiEscape: true, preserveSourceNewlines: true, terminateUnterminatedLiterals: true - }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); + }).writeNode(EmitHint.Unspecified, node, sourceFile, writer, writer); return { text: writer.getText(), node: assignPositionsToNode(node) }; } } From b1ed654a3870995e4e570e6b7ec03e5a74906a0a Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:54:52 -0800 Subject: [PATCH 9/9] Restore previous formatting --- src/compiler/checker.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 32cf2fa054ef1..1aea0c180e432 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6123,9 +6123,7 @@ 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 - ? createOrReusePrinter({ removeComments: true, neverAsciiEscape: true }) - : createOrReusePrinter({ removeComments: true }); + const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createOrReusePrinter({ removeComments: true, neverAsciiEscape: true }) : createOrReusePrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer;