Skip to main content

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-foo
    tip

    You can set --plugin options multiple times.

  • The API, via the plugins options:

    import * as prettierPluginFoo from "prettier-plugin-foo";

    await prettier.format("code", {
    parser: "foo",
    plugins: [prettierPluginFoo],
    });
  • The Configuration File:

    prettier.config.mjs
    import * 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

Community Plugins

Developing Plugins

Prettier plugins are regular JavaScript modules with the following five exports or default export with the following properties:

  • 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().

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:

  1. AST preprocessing (optional). See preprocess.
  2. Comment attachment (optional). See Handling comments in a printer.
  3. Processing embedded languages (optional). The embed method, if defined, is called for each node, depth-first. While, for performance reasons, the recursion itself is synchronous, embed may 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.
  4. 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): Doc method is called. It composes a doc for the current node, often by printing child nodes using the print callback.

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 by path.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’s print function and passes itself to it. Thus, the two print functions – 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