Repository navigation
Preserve single-line emit hints for nodes returned by the API - #65062
Open
Harsh Vardhan Chauhan (1-DARK) wants to merge 2 commits into
Open
Harsh Vardhan Chauhan (1-DARK) wants to merge 2 commits into
Harsh Vardhan Chauhan (1-DARK) wants to merge 2 commits into
Conversation
Nodes built by the node builder (e.g. via typeToTypeNode) mark tuple and type literal nodes as single-line using emit flags kept in an emit context. The API encoder never sent those, so printNode on the client side printed such nodes across several lines, unlike typeToString and the 6.0 API. Carry EFSingleLine and EFNoAsciiEscaping across the API in two reserved NodeFlags bits when encoding the results of typeToTypeNode and signatureToSignatureDeclaration, and restore them as emit flags in printNode.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new tests lack non-ASCII round-trip coverage for EFNoAsciiEscaping, so regressions in transporting or restoring that hint would go undetected.
1 open issue
1 file not reviewed
tsc/internal/api/enum_values_generated.go: Generated file
What changed in this PR
Preserves node-builder printer hints across the TypeScript API boundary, addressing #64991 so checker-generated tuples and type literals retain their single-line formatting.
Changes:
- Transports single-line and no-ASCII-escaping hints through node flags.
- Returns emit contexts from checker builders and restores hints before printing.
- Adds Go round-trip coverage and sync/async API formatting tests.
| File | Description |
|---|---|
tsc/internal/checker/printer.go |
Adds builder methods that return emit contexts. |
tsc/internal/ast/nodeflags.go |
Defines transport flags for printer hints. |
tsc/internal/api/session.go |
Encodes builder hints and restores them for printing. |
tsc/internal/api/printnode_emitflags_test.go |
Tests single-line hints through encoding and decoding. |
tsc/internal/api/enum_values_generated.go |
Registers the new generated enum values. |
tsc/internal/api/encoder/encoder.go |
Serializes emit hints without mutating nodes. |
packages/typescript/test/sync/api.test.ts |
Tests single-line formatting through the sync API. |
packages/typescript/test/async/api.test.ts |
Tests single-line formatting through the async API. |
packages/typescript/enums/nodeFlags.js |
Adds runtime enum values for transported hints. |
packages/typescript/enums/nodeFlags.d.ts |
Adds corresponding enum declarations. |
Review effort: Balanced
Comment on lines
+468
to
+469
| if emitFlags&printer.EFNoAsciiEscaping != 0 { | ||
| flags |= ast.NodeFlagsEmitNoAsciiEscaping |
Contributor
Author
There was a problem hiding this comment.
Good catch, thanks. Added TestPrintNodeRestoresNoAsciiEscaping: a synthesized "é" literal round-trips verbatim with EFNoAsciiEscaping and as "\u00E9" without it. I also confirmed it fails if the encoder stops setting NodeFlagsEmitNoAsciiEscaping.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #64991
Problem
With
typescript/sync/async,checker.typeToTypeNode(...)results printed viaapi.printer.printNode(...)come out across several lines:whereas
checker.typeToStringand the 6.0 API give[Date, number]/{ a: string; }.Cause
The node builder marks tuple types, type literals (and a few other nodes: mapped types, empty type literals, string literals in type position, pseudo-type-builder results) with
EFSingleLine/EFNoAsciiEscaping. Those flags live in the node builder'sEmitContext, not on the node. The API encoder only serialized the node, andprintNodedecoded it into a fresh printer with no emit flags, so the default multi-line layout was used.Fix
Carry the two printer hints across the API boundary:
ast/nodeflags.go: addNodeFlagsEmitSingleLine(bit 29) andNodeFlagsEmitNoAsciiEscaping(bit 30). They are transport-only and never set by the parser/binder.api/encoder: newEncodeNodeWithEmitContext; when given an emit context it sets those bits in each node's flags (without mutating the nodes).checker/printer.go:TypeToTypeNodeWithEmitContextandSignatureToSignatureDeclarationWithEmitContextreturn the builder's emit context alongside the node.api/session.go:typeToTypeNodeandsignatureToSignatureDeclarationencode with that context;printNodeconverts the bits back into emit flags before printing.enums/nodeFlags.*andenum_values_generated.go.No client-facing API changes. Because the hint travels in
node.flags, it survives the client re-encoding the node forprintNode.FlagsMultilineObjectLiteralsis respected (the builder doesn't set the flag in that case, so nothing is sent), and hand-written multi-line type literals are unaffected.Alternatives considered
PrintNodeOptionsflag (e.g.singleLine): works, but would flatten every type literal/tuple in the tree, including user-written ones, and requires callers to opt in to what 6.0 did by default.Tests
TestPrintNodeRestoresEmitFlags(encode with emit context → decode → print; with and without the hint).typeToTypeNoderesults for{ tuple: [Date, number]; obj: { a: string } }and asserting they equaltypeToString.npx hereby test: 168642 tests passed.hereby lintandhereby check:formatare clean. Sync/async API tests: 727/727.Notes
node.flagsfor builder-produced nodes seen from JS now includes bit 29/30 when set.