@@ -50,11 +50,12 @@ export type FormatEmbeddedCodeParam = {
5050} ;
5151
5252/**
53- * Format xxx-in-js code snippets
53+ * Format xxx-in-js code snippets into formatted string.
54+ *
55+ * This will be gradually replaced by `formatEmbeddedDoc` which returns `Doc`.
56+ * For now, html|css|md-in-js are using this.
5457 *
5558 * @returns Formatted code snippet
56- * TODO: In the future, this should return `Doc` instead of string,
57- * otherwise, we cannot calculate `printWidth` correctly.
5859 */
5960export async function formatEmbeddedCode ( {
6061 code,
@@ -75,64 +76,55 @@ export async function formatEmbeddedCode({
7576// ---
7677
7778export type FormatEmbeddedDocParam = {
78- code : string ;
79+ texts : string [ ] ;
7980 options : Options ;
8081} ;
8182
8283/**
83- * Format xxx-in-js code snippets via Doc IR path .
84+ * Format xxx-in-js code snippets into Prettier ` Doc` JSON strings .
8485 *
85- * Uses `prettier.__debug.printToDoc()` to get the unresolved Doc,
86- * then serializes it to JSON for the Rust side to parse.
86+ * This makes `oxc_formatter` correctly handle `printWidth` even for embedded code.
87+ * - For gql-in-js, `texts` contains multiple parts split by `${}` in a template literal
88+ * - For others, `texts` always contains a single string with `${}` parts replaced by placeholders
89+ * However, this function does not need to be aware of that,
90+ * as it simply formats each text part independently and returns an array of formatted parts.
8791 *
88- * @returns Doc JSON string
92+ * @returns Doc JSON strings (one per input text)
8993 */
9094export async function formatEmbeddedDoc ( {
91- code ,
95+ texts ,
9296 options,
93- } : FormatEmbeddedDocParam ) : Promise < string > {
97+ } : FormatEmbeddedDocParam ) : Promise < string [ ] > {
9498 const prettier = await loadPrettier ( ) ;
9599
96- // Enable Tailwind CSS plugin for embedded code if needed
100+ // Enable Tailwind CSS plugin for embedded code (e.g., html`...` in JS) if needed
97101 await setupTailwindPlugin ( options ) ;
98102
99- // Get unresolved Doc from Prettier
100- const doc = await prettier . __debug . printToDoc ( code , options ) ;
101-
102- // Replace Symbol group IDs with numeric counters before JSON serialization
103- const symbolToNumber = new Map < symbol , number > ( ) ;
104- let nextId = 1 ;
105-
106- const { utils } = await import ( "prettier/doc" ) ;
107- utils . traverseDoc ( doc , ( docNode : any ) => {
108- // Replace group id (Symbol → number)
109- if ( docNode . type === "group" && typeof docNode . id === "symbol" ) {
110- if ( ! symbolToNumber . has ( docNode . id ) ) {
111- symbolToNumber . set ( docNode . id , nextId ++ ) ;
112- }
113- docNode . id = symbolToNumber . get ( docNode . id ) ;
114- }
115- // Replace if-break groupId
116- if ( docNode . type === "if-break" && typeof docNode . groupId === "symbol" ) {
117- if ( ! symbolToNumber . has ( docNode . groupId ) ) {
118- symbolToNumber . set ( docNode . groupId , nextId ++ ) ;
119- }
120- docNode . groupId = symbolToNumber . get ( docNode . groupId ) ;
121- }
122- // Replace indent-if-break groupId
123- if ( docNode . type === "indent-if-break" && typeof docNode . groupId === "symbol" ) {
124- if ( ! symbolToNumber . has ( docNode . groupId ) ) {
125- symbolToNumber . set ( docNode . groupId , nextId ++ ) ;
126- }
127- docNode . groupId = symbolToNumber . get ( docNode . groupId ) ;
128- }
129- } ) ;
130-
131- // Serialize with -Infinity replacer
132- return JSON . stringify ( doc , ( _key , value ) => {
133- if ( value === - Infinity ) return "__NEGATIVE_INFINITY__" ;
134- return value ;
135- } ) ;
103+ // NOTE: This will throw if:
104+ // - Specified parser is not available
105+ // - Or, code has syntax errors
106+ // In such cases, Rust side will fallback to original code
107+ return Promise . all (
108+ texts . map ( async ( text ) => {
109+ // @ts -expect-error: Use internal API, but it's necessary and only way to get `Doc`
110+ const doc = await prettier . __debug . printToDoc ( text , options ) ;
111+
112+ // Serialize Doc to JSON, handling special values in a single pass:
113+ // - Symbol group IDs (used by `group`, `if-break`, `indent-if-break`) → numeric counters
114+ // - -Infinity (used by `dedentToRoot` via `align`) → marker string
115+ const symbolToNumber = new Map < symbol , number > ( ) ;
116+ let nextId = 1 ;
117+
118+ return JSON . stringify ( doc , ( _key , value ) => {
119+ if ( typeof value === "symbol" ) {
120+ if ( ! symbolToNumber . has ( value ) ) symbolToNumber . set ( value , nextId ++ ) ;
121+ return symbolToNumber . get ( value ) ;
122+ }
123+ if ( value === - Infinity ) return "__NEGATIVE_INFINITY__" ;
124+ return value ;
125+ } ) ;
126+ } ) ,
127+ ) ;
136128}
137129
138130// ---
0 commit comments