@@ -119,74 +119,72 @@ function flatten(doc: Doc): Doc {
119119// ---------------------------------------
120120
121121/**
122- * The `SubString` represents a reduced version of the `Doc` structure,
123- * representing a single way to format an AST into a human-readable string.
122+ * A linked list for string segments.
124123 */
125- type SubString = SubLine | SubText | null ;
126-
127- type SubLine = {
128- type : "subLine" ;
129- indent : number ;
130- subString : SubString ;
131- } ;
132- type SubText = {
133- type : "subText" ;
134- text : string ;
135- subString : SubString ;
136- } ;
124+ interface LinkedString {
125+ subString : string ;
126+ next : LinkedString | null ;
127+ }
137128
138129/**
139- * `PrettifyFitState` represents the current state of the formatting process,
140- * including the remaining `Doc` to process and the current indentation level.
130+ * Memoized helper to build indentation strings.
141131 */
142- type PrettifyFitState = {
143- indentLevel : number ;
144- doc : Doc ;
145- next : PrettifyFitState | null ;
146- } ;
132+ const memoizedIndentation : Record < number , string > = { } ;
133+ function getIndentation ( indentLevel : number ) : string {
134+ if ( ! ( indentLevel in memoizedIndentation ) ) {
135+ memoizedIndentation [ indentLevel ] = "\n" + "\t" . repeat ( indentLevel ) ;
136+ }
137+ return memoizedIndentation [ indentLevel ] ;
138+ }
147139
148140/**
149141 * Converts a `Doc` structure into a string representation that fits within
150142 * the specified width.
151143 */
152144function print ( doc : Doc , width : number ) : string {
153- return stringify ( selectBestSubString ( width , doc ) ) ;
145+ return stringify ( selectBestLinkedString ( width , doc ) ) ;
154146}
155147
156148/**
157- * Recursively converts a `SubString ` object into a human-readable string.
149+ * Recursively converts a `LinkedString ` object into a human-readable string.
158150 * This is the final step of the prettifier process.
159151 */
160- function stringify ( x : SubString ) : string {
161- if ( x && "type" in x ) {
162- if ( x . type === "subLine" ) {
163- return "\n" + "\t" . repeat ( x . indent ) + stringify ( x . subString ) ;
164- }
165- if ( x . type === "subText" ) {
166- return x . text + stringify ( x . subString ) ;
167- }
152+ function stringify ( linkedString : LinkedString | null ) : string {
153+ let result = "" ;
154+ while ( linkedString ) {
155+ result += linkedString . subString ;
156+ linkedString = linkedString . next ;
168157 }
169- return "" ;
158+ return result ;
170159}
171160
172161/**
173- * Selects the best `SubString ` representation of a `Doc` that fits within
162+ * Selects the best `LinkedString ` representation of a `Doc` that fits within
174163 * the given width.
175164 */
176- function selectBestSubString ( width : number , doc : Doc ) : SubString {
177- const head : PrettifyFitState = {
165+ function selectBestLinkedString ( width : number , doc : Doc ) : LinkedString | null {
166+ const head : RestToFitNode = {
178167 indentLevel : 0 ,
179168 doc,
180169 next : null ,
181170 } ;
182- return _selectBestSubString ( width , 0 , head ) ;
171+ return _selectBestLinkedString ( width , 0 , head ) ;
183172}
184173
185- function _selectBestSubString (
174+ /**
175+ * A specialized linked list node for tracking the remaining `Doc` to fit.
176+ */
177+ interface RestToFitNode {
178+ indentLevel : number ;
179+ doc : Doc ;
180+ next : RestToFitNode | null ;
181+ }
182+
183+ function _selectBestLinkedString (
186184 width : number ,
187185 currentIndentLevel : number ,
188- head : PrettifyFitState | null
189- ) : SubString {
186+ head : RestToFitNode | null
187+ ) : LinkedString | null {
190188 if ( head === null ) {
191189 return null ;
192190 }
@@ -195,58 +193,56 @@ function _selectBestSubString(
195193
196194 if ( typeof doc === "string" ) {
197195 return {
198- type : "subText" ,
199- text : doc ,
200- subString : _selectBestSubString ( width , currentIndentLevel + doc . length , next ) ,
196+ subString : doc ,
197+ next : _selectBestLinkedString ( width , currentIndentLevel + doc . length , next ) ,
201198 } ;
202199 }
203200 if ( doc . type === "concat" ) {
204201 let newHead = next ;
205202 for ( let i = doc . docs . length - 1 ; i >= 0 ; i -- ) {
206203 newHead = { indentLevel, doc : doc . docs [ i ] , next : newHead } ;
207204 }
208- return _selectBestSubString ( width , currentIndentLevel , newHead ) ;
205+ return _selectBestLinkedString ( width , currentIndentLevel , newHead ) ;
209206 }
210207 if ( doc . type === "nest" ) {
211- return _selectBestSubString ( width , currentIndentLevel , {
208+ return _selectBestLinkedString ( width , currentIndentLevel , {
212209 indentLevel : indentLevel + doc . indentLevel ,
213210 doc : doc . doc ,
214211 next,
215212 } ) ;
216213 }
217214 if ( doc . type === "insertLine" ) {
218215 return {
219- type : "subLine" ,
220- indent : indentLevel ,
221- subString : _selectBestSubString ( width , indentLevel , next ) ,
216+ subString : getIndentation ( indentLevel ) ,
217+ next : _selectBestLinkedString ( width , indentLevel , next ) ,
222218 } ;
223219 }
224220 if ( doc . type === "chooseBetween" ) {
225221 const head1 = { indentLevel, doc : doc . doc1 , next } ;
226- const possibleSubString = _selectBestSubString ( width , currentIndentLevel , head1 ) ;
227- if ( fits ( width - currentIndentLevel , possibleSubString ) ) {
228- return possibleSubString ;
222+ const possibleLinkedString = _selectBestLinkedString ( width , currentIndentLevel , head1 ) ;
223+ if ( fits ( width - currentIndentLevel , possibleLinkedString ) ) {
224+ return possibleLinkedString ;
229225 }
230226
231227 const head2 = { indentLevel, doc : doc . doc2 , next } ;
232- return _selectBestSubString ( width , currentIndentLevel , head2 ) ;
228+ return _selectBestLinkedString ( width , currentIndentLevel , head2 ) ;
233229 }
234230 return null ;
235231}
236232
237233/**
238- * Checks whether a given `SubString ` fits within the specified width.
234+ * Checks whether a given `LinkedString ` fits within the specified width.
239235 */
240- function fits ( width : number , x : SubString ) : boolean {
241- if ( width < 0 ) return false ;
242- if ( x === null ) {
243- return true ;
244- } else if ( x . type === "subLine" ) {
245- return true ;
246- } else if ( x . type === "subText" ) {
247- return fits ( width - x . text . length , x . subString ) ;
236+ function fits ( width : number , linkedString : LinkedString | null ) : boolean {
237+ while ( linkedString ) {
238+ if ( linkedString . subString [ 0 ] === "\n" ) {
239+ return true ;
240+ }
241+ width -= linkedString . subString . length ;
242+ if ( width < 0 ) return false ;
243+ linkedString = linkedString . next ;
248244 }
249- return false ;
245+ return true ;
250246}
251247
252248// ---------------------------------------
0 commit comments