Plugins
Plugins are ways of adding new languages or formatting rules to Prettier. Prettier’s own implementations of all languages are expressed using the plugin API. The core prettier package contains JavaScript and other web-focused languages built in. For additional languages you’ll need to install a plugin.
Using Plugins
You can load plugins with:
-
The CLI, via
--plugin:prettier --write main.foo --plugin=prettier-plugin-footipYou can set
--pluginoptions multiple times. -
The API, via the
pluginsoptions:import * as prettierPluginFoo from "prettier-plugin-foo";await prettier.format("code", {parser: "foo",plugins: [prettierPluginFoo],}); -
The Configuration File:
prettier.config.mjsimport * as prettierPluginFoo from "prettier-plugin-foo";/*** @see https://prettier.io/docs/configuration* @type {import("prettier").Config}*/const config = {plugins: [prettierPluginFoo],};export default config;
Strings provided to plugins are ultimately passed to import() expression, so you can provide a module/package name, a path, or anything else import() takes.
Official Plugins
@prettier/plugin-php@prettier/plugin-pugby @Shinigami92@prettier/plugin-ruby@prettier/plugin-xml
Community Plugins
@htnabe/prettier-plugin-go-templateby @htnabe@htnabe/prettier-plugin-hugo-postby @htnabe@poliklot/prettier-plugin-handlebarsby @Poliklotprettier-plugin-apexby @dangmaiprettier-plugin-astroby @withastro contributorsprettier-plugin-bigcommerce-stencilby @phoenix128prettier-plugin-elmby @giCentreprettier-plugin-erbby @adamzapasnikprettier-plugin-gherkinby @mapadoprettier-plugin-glslby @NaridaLprettier-plugin-javaby @JHipsterprettier-plugin-jinja-templateby @davidodenwaldprettier-plugin-jteby @sgruendelprettier-plugin-kotlinby @Angry-Potatoprettier-plugin-markdown-compact-tablesby @cudomentprettier-plugin-markdown-htmlby @poradaprettier-plugin-markoby @marko-jsprettier-plugin-motokoby @dfinityprettier-plugin-mustacheby @Poliklotprettier-plugin-nginxby @jxddkprettier-plugin-nunjucksby @Poliklotprettier-plugin-prismaby @umidbekkprettier-plugin-propertiesby @eemeliprettier-plugin-powershellby @Nick2bad4uprettier-plugin-rustby @jinxdashprettier-plugin-shby @JounQinprettier-plugin-sqlby @JounQinprettier-plugin-sql-cstby @neneprettier-plugin-solidityby @mattiaerreprettier-plugin-svelteby @sveltejsprettier-plugin-tomlby @JounQin and @so1veprettier-plugin-xqueryby @DrRataplanprettier-plugin-yamlby @porada
Developing Plugins
Prettier plugins are regular JavaScript modules with the following five exports or default export with the following properties:
languagesparsersprintersoptionsdefaultOptions
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().
It must include name and parsers.
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.
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).
export const parsers = {
"dance-parse": {
parse,
// The name of the AST that the parser produces.
astFormat: "dance-ast",
hasPragma,
hasIgnorePragma,
locStart,
locEnd,
preprocess,
},
};
The signature of the parse function is:
function parse(text: string, options: object): Promise<AST> | AST;
The location extraction functions (locStart and locEnd) return the starting and ending locations of a given AST node:
function locStart(node: object): number;
(Optional) The pragma detection function (hasPragma) should return if the text contains the pragma comment.
function hasPragma(text: string): boolean;
(Optional) The "ignore pragma" detection function (hasIgnorePragma) should return if the text contains a pragma indicating the text should not be formatted.
function hasIgnorePragma(text: string): boolean;
(Optional) The preprocess function can process the input text before passing into parse function.
function preprocess(text: string, options: object): string | Promise<string>;
Support for async preprocess first added in v3.7.0
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. All other properties (embed, preprocess, etc.) are optional.
export const printers = {
"dance-ast": {
print,
embed,
preprocess,
getVisitorKeys,
insertPragma,
canAttachComment,
isBlockComment,
printComment,
getCommentChildNodes,
hasPrettierIgnore,
printPrettierIgnored,
handleComments: {
ownLine,
endOfLine,
remaining,
},
},
};
The printing process
Prettier uses an intermediate representation, called a Doc, which Prettier then turns into a string (based on options like printWidth). A printer's job is to take the AST generated by parsers[<parser name>].parse and return a Doc. A Doc is constructed using builder commands:
import * as prettier from "prettier";
const { join, line, ifBreak, group } = prettier.doc.builders;
The printing process consists of the following steps:
- AST preprocessing (optional). See
preprocess. - Comment attachment (optional). See Handling comments in a printer.
- Processing embedded languages (optional). The
embedmethod, if defined, is called for each node, depth-first. While, for performance reasons, the recursion itself is synchronous,embedmay return asynchronous functions that can call other parsers and printers to compose docs for embedded syntaxes like CSS-in-JS. These returned functions are queued up and sequentially executed before the next step. - Recursive printing. A doc is recursively constructed from the AST. Starting from the root node:
- If, from the step 3, there is an embedded language doc associated with the current node, this doc is used.
- Otherwise, the
print(path, options, print): Docmethod is called. It composes a doc for the current node, often by printing child nodes using theprintcallback.
print
Most of the work of a plugin's printer will take place in its print function, whose signature is:
function print(
// Path to the AST node to print
path: AstPath,
options: object,
// Recursively print a child node
print: (selector?: string | number | Array<string | number> | AstPath) => Doc,
): Doc;
The print function is passed the following parameters:
path: An object, which can be used to access nodes in the AST. It’s a stack-like data structure that maintains the current state of the recursion. It is called “path” because it represents the path to the current node from the root of the AST. The current node is returned bypath.node.options: A persistent object, which contains global options and which a plugin may mutate to store contextual data.print: A callback for printing sub-nodes. This function contains the core printing logic that consists of steps whose implementation is provided by plugins. In particular, it calls the printer’sprintfunction and passes itself to it. Thus, the twoprintfunctions – the one from the core and the one from the plugin – call each other while descending down the AST recursively.
Here’s a simplified example to give an idea of what a typical implementation of print looks like:
import * as prettier from "prettier";
const { group, indent, join, line, softline } = prettier.doc.builders;
function print(path, options, print) {
const node = path.node;
switch (node.type) {
case "list":
return group([
"(",
indent([softline, join(line, path.map(print, "elements"))]),
softline,
")",
]);
case "pair":
return group([
"(",
indent([softline, print("left"), line, ". ", print("right")]),
softline,
")",
]);
case "symbol":
return node.name;
}
throw new Error(`Unknown node type: ${node.type}`);
}
Check out prettier-python's printer for some examples of what is possible.
(optional) embed
A printer can have the embed method to print one language inside another. Examples of this are printing CSS-in-JS or fenced code blocks in Markdown. The signature is:
function embed(
// Path to the current AST node
path: AstPath,
// Current options
options: Options,
):
| ((
// Parses and prints the passed text using a different parser.
// You should set `options.parser` to specify which parser to use.
textToDoc: (text: string, options: Options) => Promise<Doc>,
// Prints the current node or its descendant node with the current printer
print: (
selector?: string | number | Array<string | number> | AstPath,
) => Doc,
// The following two arguments are passed for convenience.
// They're the same `path` and `options` that are passed to `embed`.
path: AstPath,
options: Options,
) => Promise<Doc | undefined> | Doc | undefined)
| Doc
| undefined;
The embed method is similar to the print method in that it maps AST nodes to docs, but unlike print, it has power to do async work by returning an async function. That function's first parameter, the textToDoc async function, can be used to render a doc using a different plugin.
If a function returned from embed returns a doc or a promise that resolves to a doc, that doc will be used in printing, and the print method won’t be called for this node. It's also possible and, in rare situations, might be convenient to return a doc synchronously directly from embed, however textToDoc and the print callback aren’t available at that case. Return a function to get them.
If embed returns undefined, or if a function it returned returns undefined or a promise that resolves to undefined, the node will be printed normally with the print method. Same will happen if a returned function throws an error or returns a promise that rejects (e.g., if a parsing error has happened). Set the PRETTIER_DEBUG environment variable to a non-empty value if you want Prettier to rethrow these errors.
For example, a plugin that has nodes with embedded JavaScript might have the following embed method:
function embed(path, options) {