prettier/docs/plugins.md

211 lines
6.0 KiB
Markdown
Raw Normal View History

---
id: plugins
title: Plugins (Beta)
---
## IN BETA
> The plugin API is in a **beta** state as of Prettier 1.10 and the API may change in the next release!
Plugins are ways of adding new languages to Prettier. Prettier's own implementations of all languages are expressed using the plugin API. The core `prettier` package contains JavaScript and other web-focussed languages built in. For additional languages you'll need to install a plugin.
## Using Plugins
2018-01-05 18:48:47 +03:00
Plugins are automatically loaded if you have them installed in your `package.json`. Prettier plugin package names must start with `@prettier/plugin-` or `prettier-plugin-` to be registered.
2018-01-05 18:48:47 +03:00
If the plugin is unable to be found automatically, you can load them with:
2018-01-05 18:48:47 +03:00
* The [CLI](./cli.md), via the `--plugin` flag:
2018-01-05 18:48:47 +03:00
```bash
prettier --write main.foo --plugin=./foo-plugin
```
2018-01-05 18:48:47 +03:00
> Tip: You can pass multiple `--plugin` flags.
2018-01-05 18:48:47 +03:00
* Or the [API](./api.md), via the `plugins` field:
2018-01-05 18:48:47 +03:00
```js
prettier.format("code", {
parser: "foo",
plugins: ["./foo-plugin"]
});
```
## Official Plugins
2018-01-05 18:48:47 +03:00
* [`@prettier/plugin-python`](https://github.com/prettier/prettier-python)
* [`@prettier/plugin-php`](https://github.com/prettier/prettier-php)
* [`@prettier/plugin-swift`](https://github.com/prettier/prettier-swift)
## Community Plugins
2018-02-21 16:36:59 +03:00
* [`prettier-plugin-java`](https://github.com/thorbenvh8/prettier-java)
* [`iamsolankiamit/prettier-ruby`](https://github.com/iamsolankiamit/prettier-ruby)
* [`benjie/prettier-plugin-pg`](https://github.com/benjie/prettier-plugin-pg)
## Developing Plugins
Prettier plugins are regular JavaScript modules with five exports:
* `languages`
* `parsers`
* `printers`
* `options`
* `defaultOptions`
### `languages`
Languages is an array of language definitions that your plugin will contribute to Prettier. It can include all of the fields specified in [`prettier.getSupportInfo()`](./api.md#prettiergetsupportinfo-version).
It **must** include `name` and `parsers`.
```js
export const languages = [
{
// The language name
name: "InterpretedDanceScript",
// Parsers that can parse this language.
// This can be built-in parsers, or parsers you have contributed via this plugin.
parsers: ["dance-parse"]
}
];
```
### `parsers`
Parsers convert code as a string into an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree).
The key must match the name in the `parsers` array from `languages`. The value contains a parse function, an AST format name, and two location extraction functions (`locStart` and `locEnd`).
```js
export const parsers = {
"dance-parse": {
parse,
// The name of the AST that
astFormat: "dance-ast",
locStart,
locEnd
}
};
```
The signature of the `parse` function is:
```ts
function parse(text: string, parsers: object, options: object): AST;
```
The location extraction functions (`locStart` and `locEnd`) return the beginning and the end location of a given AST node:
```ts
function locStart(node: object): number;
```
### `printers`
Printers convert ASTs into a Prettier intermediate representation, also known as a Doc.
The key must match the `astFormat` that the parser produces. The value contains an object with a `print` function and (optionally) an `embed` function.
```js
export const printers = {
"dance-ast": {
print,
embed
}
};
```
Printing is a recursive process of coverting an AST node (represented by a path to that node) into a doc. The doc is constructed using the [builder commands](https://github.com/prettier/prettier/blob/master/commands.md):
```js
const { concat, join, line, ifBreak, group } = require("prettier").doc.builders;
```
The signature of the `print` function is:
```ts
function print(
// Path to the AST node to print
path: FastPath,
options: object,
// Recursively print a child node
print: (path: FastPath) => Doc
): Doc;
```
Check out [prettier-python's printer](https://github.com/prettier/prettier-python/blob/034ba8a9551f3fa22cead41b323be0b28d06d13b/src/printer.js#L174) as an example.
Embedding refers to printing one language inside another. Examples of this are CSS-in-JS and Markdown code blocks. Plugins can switch to alternate languages using the `embed` function. Its signature is:
```ts
function embed(
// Path to the current AST node
path: FastPath,
// Print a node with the current printer
print: (path: FastPath) => Doc,
// Parse and print some text using a different parser.
// You should set `options.parser` to specify which parser to use.
textToDoc: (text: string, options: object) => Doc,
// Current options
options: object
): Doc | null;
```
If you don't want to switch to a different parser, simply return `null` or `undefined`.
### `options`
`options` is an object containing the custom options your plugin supports.
Example:
```js
options: {
openingBraceNewLine: {
type: "boolean",
category: "Global",
default: true,
description: "Move open brace for code blocks onto new line."
}
}
```
### `defaultOptions`
If your plugin requires different default values for some of prettier's core options, you can specify them in `defaultOptions`:
```
defaultOptions: {
tabWidth: 4
}
```
### Utility functions
A `util` module from prettier core is considered a private API and is not meant to be consumed by plugins. Instead, the `util-shared` module provides the following limited set of utility functions for plugins:
```ts
makeString(rawContent: string, enclosingQuote: string, unescapeUnnecessarEscapes: boolean): string;
getNextNonSpaceNonCommentCharacterIndex(text: string, node: object, options: object): number;
isNextLineEmptyAfterIndex(text: string, index: number): boolean;
isNextLineEmpty(text: string, node: object, options: object): boolean;
mapDoc(doc: object, callback: function): void;
```
## Testing Plugins
Since plugins can be resolved using relative paths, when working on one you can do:
```js
const prettier = require("prettier");
const code = "(add 1 2)";
prettier.format(code, {
parser: "lisp",
plugins: ["."]
});
```
This will resolve a plugin relative to the current working direcrory.