or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-formatting.mddocument-builders.mdfile-analysis.mdindex.mdplugin-development.mdutilities.md

plugin-development.mddocs/

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

```