0
# Document Builder API
1
2
The Document Builder API provides low-level primitives for creating custom formatters and Prettier plugins. It offers a composable system for building formatted output through document objects that represent formatting decisions.
3
4
## Core Concepts
5
6
The Document Builder API uses an intermediate representation called "Doc" objects that describe how code should be formatted. These documents are then printed to strings with line breaking, indentation, and spacing applied.
7
8
### Importing Document Builders
9
```javascript { .api }
10
import { doc } from 'prettier';
11
12
// Access builder functions
13
const { builders, printer, utils } = doc;
14
15
// Or import specific builders
16
import { doc } from 'prettier';
17
const { group, line, indent, join } = doc.builders;
18
```
19
20
## Document Builder Functions
21
22
### Basic Building Blocks
23
24
### join
25
```javascript { .api }
26
function join(separator: Doc, docs: Doc[]): Doc
27
```
28
29
Join an array of documents with a separator document between each element.
30
31
**Parameters:**
32
- `separator` (Doc): Document to insert between elements
33
- `docs` (Doc[]): Array of documents to join
34
35
**Example:**
36
```javascript { .api }
37
const params = ['a', 'b', 'c'];
38
const joined = doc.builders.join(
39
[',', doc.builders.line],
40
params
41
);
42
// Result: 'a,\nb,\nc' (when broken) or 'a, b, c' (when flat)
43
```
44
45
### Line Breaking Documents
46
47
### line
48
```javascript { .api }
49
const line: Doc
50
```
51
52
A line break that becomes a space when the parent group fits on one line.
53
54
**Example:**
55
```javascript { .api }
56
const statement = doc.builders.group([
57
'if (',
58
'condition',
59
')',
60
doc.builders.line,
61
'doSomething();'
62
]);
63
// Result: 'if (condition) doSomething();' or 'if (condition)\ndoSomething();'
64
```
65
66
### softline
67
```javascript { .api }
68
const softline: Doc
69
```
70
71
A line break that becomes nothing (empty string) when the parent group fits on one line.
72
73
**Example:**
74
```javascript { .api }
75
const array = doc.builders.group([
76
'[',
77
doc.builders.softline,
78
doc.builders.join([',', doc.builders.line], elements),
79
doc.builders.softline,
80
']'
81
]);
82
// Result: '[a, b, c]' or '[\n a,\n b,\n c\n]'
83
```
84
85
### hardline
86
```javascript { .api }
87
const hardline: Doc
88
```
89
90
An unconditional line break that always creates a new line.
91
92
**Example:**
93
```javascript { .api }
94
const statements = [
95
'const a = 1;',
96
'const b = 2;'
97
];
98
const program = doc.builders.join(doc.builders.hardline, statements);
99
// Result: 'const a = 1;\nconst b = 2;'
100
```
101
102
### literalline
103
```javascript { .api }
104
const literalline: Doc
105
```
106
107
A line break that preserves literal newlines without triggering parent group breaking.
108
109
### hardlineWithoutBreakParent
110
```javascript { .api }
111
const hardlineWithoutBreakParent: Doc
112
```
113
114
An unconditional line break that doesn't trigger parent group breaking.
115
116
### literallineWithoutBreakParent
117
```javascript { .api }
118
const literallineWithoutBreakParent: Doc
119
```
120
121
A literal line break that doesn't trigger parent group breaking.
122
123
### Grouping and Layout
124
125
### group
126
```javascript { .api }
127
function group(doc: Doc, options?: { shouldBreak?: boolean, id?: symbol }): Doc
128
```
129
130
Group documents that should be formatted consistently - either all on one line or all broken across multiple lines.
131
132
**Parameters:**
133
- `doc` (Doc): Document to group
134
- `options` (optional): Grouping options
135
- `shouldBreak` (boolean): Force group to break
136
- `id` (symbol): Unique identifier for the group
137
138
**Example:**
139
```javascript { .api }
140
const functionCall = doc.builders.group([
141
'functionName(',
142
doc.builders.indent([
143
doc.builders.softline,
144
doc.builders.join([',', doc.builders.line], args)
145
]),
146
doc.builders.softline,
147
')'
148
]);
149
// Result: 'functionName(a, b, c)' or 'functionName(\n a,\n b,\n c\n)'
150
```
151
152
### conditionalGroup
153
```javascript { .api }
154
function conditionalGroup(docs: Doc[], options?: { shouldBreak?: boolean }): Doc
155
```
156
157
Try multiple document variants in order, using the first one that fits.
158
159
**Example:**
160
```javascript { .api }
161
const alternatives = doc.builders.conditionalGroup([
162
// Try inline first
163
['(', doc.builders.join(', ', args), ')'],
164
// Fall back to multi-line
165
[
166
'(',
167
doc.builders.indent([doc.builders.line, doc.builders.join([',', doc.builders.line], args)]),
168
doc.builders.line,
169
')'
170
]
171
]);
172
```
173
174
### fill
175
```javascript { .api }
176
function fill(docs: Doc[]): Doc
177
```
178
179
Fill available line space optimally by trying to fit as many documents as possible on each line.
180
181
**Example:**
182
```javascript { .api }
183
const words = ['This', 'is', 'a', 'long', 'sentence', 'that', 'should', 'wrap'];
184
const paragraph = doc.builders.fill(
185
doc.builders.join(doc.builders.line, words)
186
);
187
// Result: Wraps words to fit available width
188
```
189
190
### Indentation and Alignment
191
192
### indent
193
```javascript { .api }
194
function indent(doc: Doc): Doc
195
```
196
197
Increase indentation level for the contained document.
198
199
**Example:**
200
```javascript { .api }
201
const block = [
202
'{',
203
doc.builders.indent([
204
doc.builders.hardline,
205
'statement1;',
206
doc.builders.hardline,
207
'statement2;'
208
]),
209
doc.builders.hardline,
210
'}'
211
];
212
// Result: '{\n statement1;\n statement2;\n}'
213
```
214
215
### indentIfBreak
216
```javascript { .api }
217
function indentIfBreak(doc: Doc, options?: { groupId?: symbol }): Doc
218
```
219
220
Conditionally indent the document only if the parent group breaks.
221
222
**Parameters:**
223
- `doc` (Doc): Document to conditionally indent
224
- `options` (object, optional): Options including group ID for specific targeting
225
226
**Example:**
227
```javascript { .api }
228
const conditional = doc.builders.group([
229
'if (',
230
doc.builders.indentIfBreak([
231
doc.builders.line,
232
'longCondition'
233
]),
234
doc.builders.line,
235
')'
236
]);
237
// Indents only when the group breaks
238
```
239
240
### align
241
```javascript { .api }
242
function align(n: number | string, doc: Doc): Doc
243
```
244
245
Align document to a specific column offset.
246
247
**Parameters:**
248
- `n` (number | string): Spaces to align (number) or alignment string
249
- `doc` (Doc): Document to align
250
251
**Example:**
252
```javascript { .api }
253
const aligned = doc.builders.align(4, [
254
'let x = longVariableName +',
255
doc.builders.line,
256
'anotherLongVariableName;'
257
]);
258
// Result: Aligns continuation line to column 4
259
```
260
261
### addAlignmentToDoc
262
```javascript { .api }
263
function addAlignmentToDoc(doc: Doc, size: number, tabWidth: number): Doc
264
```
265
266
Add additional alignment space to an existing document.
267
268
**Parameters:**
269
- `doc` (Doc): Document to add alignment to
270
- `size` (number): Number of spaces to add for alignment
271
- `tabWidth` (number): Tab width for calculating proper alignment
272
273
**Example:**
274
```javascript { .api }
275
const withAlignment = doc.builders.addAlignmentToDoc(
276
existingDoc,
277
4,
278
2
279
);
280
// Adds 4 spaces of alignment considering tab width
281
```
282
283
### dedent
284
```javascript { .api }
285
function dedent(doc: Doc): Doc
286
```
287
288
Decrease indentation level for the contained document.
289
290
### dedentToRoot
291
```javascript { .api }
292
function dedentToRoot(doc: Doc): Doc
293
```
294
295
Remove all indentation, aligning to the root level.
296
297
### markAsRoot
298
```javascript { .api }
299
function markAsRoot(doc: Doc): Doc
300
```
301
302
Mark document as root for indentation calculations.
303
304
### Conditional Formatting
305
306
### ifBreak
307
```javascript { .api }
308
function ifBreak(breakContents: Doc, flatContents?: Doc, options?: { groupId?: symbol }): Doc
309
```
310
311
Conditionally include content based on whether the parent group breaks.
312
313
**Parameters:**
314
- `breakContents` (Doc): Content when parent group breaks
315
- `flatContents` (Doc, optional): Content when parent group is flat
316
- `options` (optional): Options including group ID to check
317
318
**Example:**
319
```javascript { .api }
320
const arrayElements = doc.builders.group([
321
'[',
322
doc.builders.indent([
323
doc.builders.softline,
324
doc.builders.join([
325
',',
326
doc.builders.ifBreak(doc.builders.hardline, doc.builders.line)
327
], elements)
328
]),
329
doc.builders.softline,
330
']'
331
]);
332
```
333
334
### Line Manipulation
335
336
### lineSuffix
337
```javascript { .api }
338
function lineSuffix(doc: Doc): Doc
339
```
340
341
Content that should appear at the end of the current line.
342
343
**Example:**
344
```javascript { .api }
345
const statement = [
346
'const x = value;',
347
doc.builders.lineSuffix(' // comment')
348
];
349
// Result: 'const x = value; // comment'
350
```
351
352
### lineSuffixBoundary
353
```javascript { .api }
354
const lineSuffixBoundary: Doc
355
```
356
357
Boundary marker for line suffix content placement.
358
359
### Special Documents
360
361
### cursor
362
```javascript { .api }
363
const cursor: Doc
364
```
365
366
Placeholder for cursor position in editor integrations.
367
368
### breakParent
369
```javascript { .api }
370
const breakParent: Doc
371
```
372
373
Force the parent group to break across multiple lines.
374
375
**Example:**
376
```javascript { .api }
377
const forceBreak = doc.builders.group([
378
'items: [',
379
doc.builders.indent([
380
doc.builders.line,
381
'item1,',
382
doc.builders.breakParent, // Forces parent group to break
383
doc.builders.line,
384
'item2'
385
]),
386
doc.builders.line,
387
']'
388
]);
389
```
390
391
### trim
392
```javascript { .api }
393
const trim: Doc
394
```
395
396
Remove trailing whitespace from the current line.
397
398
### label
399
```javascript { .api }
400
function label(label: string, doc: Doc): Doc
401
```
402
403
Label document for debugging and development purposes.
404
405
## Document Printer
406
407
### printDocToString
408
```javascript { .api }
409
function printDocToString(doc: Doc, options: PrintOptions): PrintResult
410
```
411
412
Convert a document to a formatted string with the specified print options.
413
414
**Types:**
415
```javascript { .api }
416
interface PrintOptions {
417
printWidth?: number; // Maximum line width (default: 80)
418
tabWidth?: number; // Tab width (default: 2)
419
useTabs?: boolean; // Use tabs for indentation (default: false)
420
endOfLine?: 'auto' | 'lf' | 'crlf' | 'cr'; // Line ending style
421
}
422
423
interface PrintResult {
424
formatted: string; // Formatted output
425
cursorOffset: number; // Cursor position (if cursor doc was used)
426
}
427
```
428
429
**Example:**
430
```javascript { .api }
431
const document = doc.builders.group([
432
'function(',
433
doc.builders.indent([
434
doc.builders.softline,
435
doc.builders.join([',', doc.builders.line], parameters)
436
]),
437
doc.builders.softline,
438
')'
439
]);
440
441
const result = doc.printer.printDocToString(document, {
442
printWidth: 80,
443
tabWidth: 2,
444
useTabs: false
445
});
446
447
console.log(result.formatted);
448
```
449
450
## Document Utilities
451
452
### traverseDoc
453
```javascript { .api }
454
function traverseDoc(
455
doc: Doc,
456
onEnter?: (doc: Doc) => void | boolean | Doc,
457
onExit?: (doc: Doc) => void,
458
shouldTraverseConditionalGroup?: boolean
459
): void
460
```
461
462
Traverse document tree with enter/exit callbacks.
463
464
### findInDoc
465
```javascript { .api }
466
function findInDoc(doc: Doc, fn: (doc: Doc) => boolean, defaultValue?: any): any
467
```
468
469
Find element in document tree matching predicate function.
470
471
### mapDoc
472
```javascript { .api }
473
function mapDoc(doc: Doc, fn: (doc: Doc) => Doc): Doc
474
```
475
476
Transform document tree by applying function to each node.
477
478
### willBreak
479
```javascript { .api }
480
function willBreak(doc: Doc): boolean
481
```
482
483
Check if document will cause parent group to break.
484
485
### canBreak
486
```javascript { .api }
487
function canBreak(doc: Doc): boolean
488
```
489
490
Check if document can break across lines.
491
492
### removeLines
493
```javascript { .api }
494
function removeLines(doc: Doc): Doc
495
```
496
497
Remove all line breaks from document.
498
499
### stripTrailingHardline
500
```javascript { .api }
501
function stripTrailingHardline(doc: Doc): Doc
502
```
503
504
Remove trailing hard line breaks from document.
505
506
### replaceEndOfLine
507
```javascript { .api }
508
function replaceEndOfLine(doc: Doc, replacement?: Doc): Doc
509
```
510
511
Replace end-of-line characters in document.
512
513
## Usage Patterns
514
515
### Building Complex Layouts
516
```javascript { .api }
517
function formatObjectExpression(properties) {
518
return doc.builders.group([
519
'{',
520
properties.length > 0 ? [
521
doc.builders.indent([
522
doc.builders.line,
523
doc.builders.join([',', doc.builders.line], properties.map(formatProperty))
524
]),
525
doc.builders.line
526
] : '',
527
'}'
528
]);
529
}
530
531
function formatProperty(prop) {
532
return doc.builders.group([
533
prop.key,
534
': ',
535
prop.value
536
]);
537
}
538
```
539
540
### Plugin Development
541
```javascript { .api }
542
// Example plugin printer function
543
function print(path, options, print) {
544
const node = path.node;
545
546
switch (node.type) {
547
case 'CustomNode':
548
return doc.builders.group([
549
'custom(',
550
doc.builders.indent([
551
doc.builders.softline,
552
doc.builders.join([',', doc.builders.line],
553
node.args.map((_, index) => path.call(print, 'args', index))
554
)
555
]),
556
doc.builders.softline,
557
')'
558
]);
559
560
default:
561
return '';
562
}
563
}
564
```
565
566
### Conditional Formatting
567
```javascript { .api }
568
function formatArray(elements, options) {
569
const shouldBreakElements = elements.length > 3 ||
570
elements.some(el => willBreak(el));
571
572
return doc.builders.group([
573
'[',
574
elements.length > 0 ? [
575
doc.builders.indent([
576
shouldBreakElements ? doc.builders.hardline : doc.builders.softline,
577
doc.builders.join([
578
',',
579
shouldBreakElements ? doc.builders.hardline : doc.builders.line
580
], elements)
581
]),
582
shouldBreakElements ? doc.builders.hardline : doc.builders.softline
583
] : '',
584
']'
585
], { shouldBreak: shouldBreakElements });
586
}
587
```
588
589
## Deprecated Functions
590
591
### concat (Deprecated)
592
```javascript { .api }
593
function concat(parts: Doc[]): Doc[]
594
```
595
596
**⚠️ Deprecated**: This function will be removed in v4. Use array syntax directly instead.
597
598
Legacy function that simply returns the parts array. Modern code should use arrays directly.
599
600
**Example:**
601
```javascript { .api }
602
// Deprecated usage
603
const doc = doc.builders.concat([part1, part2, part3]);
604
605
// Modern equivalent
606
const doc = [part1, part2, part3];
607
```