0
# Plugin Development Guide
1
2
Complete interfaces and types for developing Prettier plugins, including parsers, printers, and language support definitions.
3
4
## Plugin Interface
5
6
### Plugin Definition
7
```typescript { .api }
8
interface Plugin<T = any> {
9
languages?: SupportLanguage[] | undefined;
10
parsers?: { [parserName: string]: Parser<T> } | undefined;
11
printers?: { [astFormat: string]: Printer<T> } | undefined;
12
options?: SupportOptions | undefined;
13
defaultOptions?: Partial<RequiredOptions> | undefined;
14
}
15
```
16
17
The main plugin interface that defines a complete Prettier plugin with language support, parsing, printing, and configuration capabilities.
18
19
**Properties:**
20
- `languages` (SupportLanguage[], optional): Supported languages and file extensions
21
- `parsers` (object, optional): Parser implementations keyed by parser name
22
- `printers` (object, optional): Printer implementations keyed by AST format
23
- `options` (SupportOptions, optional): Custom formatting options
24
- `defaultOptions` (Partial<RequiredOptions>, optional): Default option values
25
26
## Parser Interface
27
28
### Parser Implementation
29
```typescript { .api }
30
interface Parser<T = any> {
31
parse: (text: string, options: ParserOptions<T>) => T | Promise<T>;
32
astFormat: string;
33
hasPragma?: ((text: string) => boolean) | undefined;
34
hasIgnorePragma?: ((text: string) => boolean) | undefined;
35
locStart: (node: T) => number;
36
locEnd: (node: T) => number;
37
preprocess?: ((text: string, options: ParserOptions<T>) => string) | undefined;
38
}
39
```
40
41
Defines how to parse source code into an Abstract Syntax Tree (AST).
42
43
**Required Properties:**
44
- `parse` (function): Main parsing function that converts text to AST
45
- `astFormat` (string): Identifier for the AST format produced
46
- `locStart` (function): Returns start position of a node in original text
47
- `locEnd` (function): Returns end position of a node in original text
48
49
**Optional Properties:**
50
- `hasPragma` (function): Detects if source contains a formatting pragma
51
- `hasIgnorePragma` (function): Detects if source should be ignored
52
- `preprocess` (function): Transform source before parsing
53
54
### Parser Options
55
```typescript { .api }
56
interface ParserOptions<T = any> extends RequiredOptions {
57
locStart: (node: T) => number;
58
locEnd: (node: T) => number;
59
originalText: string;
60
}
61
```
62
63
Options passed to parser functions, extending base formatting options with location utilities.
64
65
## Printer Interface
66
67
### Printer Implementation
68
```typescript { .api }
69
interface Printer<T = any> {
70
print(
71
path: AstPath<T>,
72
options: ParserOptions<T>,
73
print: (path: AstPath<T>) => Doc,
74
args?: unknown,
75
): Doc;
76
embed?: ((
77
path: AstPath,
78
options: Options,
79
) => ((
80
textToDoc: (text: string, options: Options) => Promise<Doc>,
81
print: (selector?: string | number | Array<string | number> | AstPath) => Doc,
82
path: AstPath,
83
options: Options,
84
) => Promise<Doc | undefined> | Doc | undefined) | Doc | null) | undefined;
85
preprocess?: ((ast: T, options: ParserOptions<T>) => T | Promise<T>) | undefined;
86
insertPragma?: (text: string) => string;
87
massageAstNode?: ((original: any, cloned: any, parent: any) => any) | undefined;
88
hasPrettierIgnore?: ((path: AstPath<T>) => boolean) | undefined;
89
canAttachComment?: ((node: T) => boolean) | undefined;
90
isBlockComment?: ((node: T) => boolean) | undefined;
91
willPrintOwnComments?: ((path: AstPath<T>) => boolean) | undefined;
92
printComment?: ((commentPath: AstPath<T>, options: ParserOptions<T>) => Doc) | undefined;
93
getCommentChildNodes?: ((node: T, options: ParserOptions<T>) => T[] | undefined) | undefined;
94
}
95
```
96
97
Defines how to format AST nodes into formatted output documents.
98
99
**Required Methods:**
100
- `print` (function): Main printing function that converts AST nodes to Doc objects
101
102
**Optional Methods:**
103
- `embed` (function): Handle embedded languages (like CSS in HTML)
104
- `preprocess` (function): Transform AST before printing
105
- `insertPragma` (function): Add formatting pragma to output
106
- `massageAstNode` (function): Modify AST nodes during printing
107
- `hasPrettierIgnore` (function): Check if node should be ignored
108
- `canAttachComment` (function): Determine if comments can attach to node
109
- `isBlockComment` (function): Identify block vs line comments
110
- `printComment` (function): Custom comment formatting
111
- `getCommentChildNodes` (function): Override default comment traversal
112
113
### Comment Handling
114
```typescript { .api }
115
interface CommentHandlers<T = any> {
116
ownLine?: ((
117
commentNode: any,
118
text: string,
119
options: ParserOptions<T>,
120
ast: T,
121
isLastComment: boolean,
122
) => boolean) | undefined;
123
endOfLine?: ((
124
commentNode: any,
125
text: string,
126
options: ParserOptions<T>,
127
ast: T,
128
isLastComment: boolean,
129
) => boolean) | undefined;
130
remaining?: ((
131
commentNode: any,
132
text: string,
133
options: ParserOptions<T>,
134
ast: T,
135
isLastComment: boolean,
136
) => boolean) | undefined;
137
}
138
```
139
140
Advanced comment handling for complex comment attachment scenarios.
141
142
## Language Support
143
144
### Language Definition
145
```typescript { .api }
146
interface SupportLanguage {
147
name: string;
148
parsers: BuiltInParserName[] | string[];
149
group?: string | undefined;
150
tmScope?: string | undefined;
151
aceMode?: string | undefined;
152
codemirrorMode?: string | undefined;
153
codemirrorMimeType?: string | undefined;
154
aliases?: string[] | undefined;
155
extensions?: string[] | undefined;
156
filenames?: string[] | undefined;
157
linguistLanguageId?: number | undefined;
158
vscodeLanguageIds?: string[] | undefined;
159
interpreters?: string[] | undefined;
160
isSupported?: ((options: { filepath: string }) => boolean) | undefined;
161
}
162
```
163
164
Defines language support metadata for file recognition and editor integration.
165
166
**Required Properties:**
167
- `name` (string): Display name of the language
168
- `parsers` (string[]): Parser names that can handle this language
169
170
**Optional Properties:**
171
- `group` (string): Language category grouping
172
- `extensions` (string[]): File extensions (e.g., ['.js', '.jsx'])
173
- `filenames` (string[]): Specific filenames (e.g., ['Dockerfile'])
174
- `aliases` (string[]): Alternative language names
175
- `interpreters` (string[]): Shebang interpreters (e.g., ['node'])
176
- `isSupported` (function): Custom support detection
177
178
## Option Definition
179
180
### Custom Options
181
```typescript { .api }
182
interface SupportOptions extends Record<string, SupportOption> {}
183
184
type SupportOption =
185
| IntSupportOption
186
| StringSupportOption
187
| BooleanSupportOption
188
| ChoiceSupportOption
189
| PathSupportOption;
190
191
interface BooleanSupportOption extends BaseSupportOption<"boolean"> {
192
default?: boolean | undefined;
193
description: string;
194
oppositeDescription?: string | undefined;
195
}
196
197
interface ChoiceSupportOption<Value = any> extends BaseSupportOption<"choice"> {
198
default?: Value | Array<{ value: Value }> | undefined;
199
description: string;
200
choices: Array<{
201
value: Value;
202
description: string;
203
}>;
204
}
205
```
206
207
Define custom formatting options for plugins with proper CLI integration and validation.
208
209
## Usage Examples
210
211
### Basic Plugin Structure
212
```javascript { .api }
213
// Example plugin for a custom language
214
export default {
215
languages: [
216
{
217
name: "MyLanguage",
218
parsers: ["mylang-parser"],
219
extensions: [".mylang"],
220
vscodeLanguageIds: ["mylang"]
221
}
222
],
223
parsers: {
224
"mylang-parser": {
225
parse: (text, options) => {
226
// Parse text into AST
227
return parseMyLanguage(text);
228
},
229
astFormat: "mylang-ast",
230
locStart: (node) => node.start,
231
locEnd: (node) => node.end,
232
}
233
},
234
printers: {
235
"mylang-ast": {
236
print: (path, options, print) => {
237
const node = path.getValue();
238
// Convert AST node to Doc
239
return formatMyLanguageNode(node, print);
240
}
241
}
242
},
243
options: {
244
myOption: {
245
type: "boolean",
246
category: "MyLanguage",
247
default: false,
248
description: "Enable my custom formatting option"
249
}
250
}
251
};
252
```
253
254
### Advanced Parser with Preprocessing
255
```javascript { .api }
256
const advancedParser = {
257
parse: async (text, options) => {
258
// Handle async parsing
259
const ast = await parseAsync(text);
260
return processAst(ast, options);
261
},
262
astFormat: "custom-ast",
263
locStart: (node) => node.loc?.start?.offset ?? 0,
264
locEnd: (node) => node.loc?.end?.offset ?? text.length,
265
hasPragma: (text) => /@format/.test(text),
266
preprocess: (text, options) => {
267
// Transform source before parsing
268
return text.replace(/oldSyntax/g, 'newSyntax');
269
}
270
};
271
```
272
273
### Custom Printer with Embedded Language Support
274
```javascript { .api }
275
const customPrinter = {
276
print: (path, options, print) => {
277
const node = path.getValue();
278
279
switch (node.type) {
280
case "Block":
281
return [
282
"{",
283
doc.builders.indent([
284
doc.builders.hardline,
285
path.map(print, "body")
286
]),
287
doc.builders.hardline,
288
"}"
289
];
290
default:
291
return node.value;
292
}
293
},
294
embed: (path, options) => {
295
const node = path.getValue();
296
297
if (node.type === "EmbeddedCode" && node.lang === "javascript") {
298
return async (textToDoc, print, path, options) => {
299
// Format embedded JavaScript
300
const formatted = await textToDoc(
301
node.code,
302
{ ...options, parser: "babel" }
303
);
304
return formatted;
305
};
306
}
307
return null;
308
}
309
};
310
```