插件
插件是向 Prettier 添加新语言或格式化规则的方法。Prettier 自己对所有语言的实现都是使用插件 API 来表达的。核心 prettier
包包含 JavaScript 和其他内置的以网络为中心的语言。对于其他语言,你需要安装一个插件。
¥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:
CLI,通过
--plugin
:¥The CLI, via
--plugin
:prettier --write main.foo --plugin=prettier-plugin-foo
提示:你可以多次设置
--plugin
选项。¥Tip: You can set
--plugin
options multiple times.API,通过
plugins
选项:¥The API, via the
plugins
options:await prettier.format("code", { parser: "foo", plugins: ["prettier-plugin-foo"], });
配置文件:
¥The Configuration File:
{ "plugins": ["prettier-plugin-foo"] }
提供给 plugins
的字符串最终会传递给 import()
表达式,因此你可以提供模块/包名称、路径或 import()
需要的任何其他内容。
¥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 插件是常规 JavaScript 模块,具有以下五个导出或具有以下属性的默认导出:
¥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 是一组语言定义,你的插件将贡献给 Prettier。它可以包括 prettier.getSupportInfo()
中指定的所有字段。
¥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()
.
它必须包括 name
和 parsers
。
¥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
解析器将代码作为字符串转换为 AST。
¥Parsers convert code as a string into an AST.
密钥必须与 languages
中的 parsers
数组中的名称相匹配。该值包含一个解析函数、一个 AST 格式名称和两个位置提取函数(locStart
和 locEnd
)。
¥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
astFormat: "dance-ast",
hasPragma,
locStart,
locEnd,
preprocess,
},
};
parse
函数的签名是:
¥The signature of the parse
function is:
function parse(text: string, options: object): Promise<AST> | AST;
位置提取函数(locStart
和 locEnd
)返回给定 AST 节点的起始和结束位置:
¥The location extraction functions (locStart
and locEnd
) return the starting and ending locations of a given AST node:
function locStart(node: object): number;
(可选的)如果文本包含 pragma 注释,则 pragma 检测函数 (hasPragma
) 应返回。
¥(Optional) The pragma detection function (hasPragma
) should return if the text contains the pragma comment.
function hasPragma(text: string): boolean;
(可选的)预处理函数可以在传入 parse
函数之前处理输入文本。
¥(Optional) The preprocess function can process the input text before passing into parse
function.
function preprocess(text: string, options: object): string;
printers
打印机将 AST 转换为 Prettier 中间表示,也称为 Doc。
¥Printers convert ASTs into a Prettier intermediate representation, also known as a Doc.
密钥必须与解析器生成的 astFormat
相匹配。该值包含一个具有 print
函数的对象。所有其他属性(embed
、preprocess
等)都是可选的。
¥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,
handleComments: {
ownLine,
endOfLine,
remaining,
},
},
};
打印过程
¥The printing process
Prettier 使用一种称为 Doc 的中间表示形式,然后 Prettier 将其转换为字符串(基于像 printWidth
这样的选项)。打印机的工作是获取 parsers[<parser name>].parse
生成的 AST 并返回一个 Doc。使用 构建器命令 构建 Doc:
¥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 { doc } from "prettier";
const { join, line, ifBreak, group } = doc.builders;
打印过程由以下步骤组成:
¥The printing process consists of the following steps:
AST 预处理(可选)。参见
preprocess
。¥AST preprocessing (optional). See
preprocess
.评论附件(可选)。参见 在打印机中处理注释。
¥Comment attachment (optional). See Handling comments in a printer.
处理嵌入式语言(可选)。如果定义了
embed
方法,则会为每个节点调用深度优先。虽然出于性能原因,递归本身是同步的,但embed
可能会返回异步函数,这些函数可以调用其他解析器和打印机来为 CSS-in-JS 等嵌入式语法编写文档。这些返回的函数会排队并在下一步之前顺序执行。¥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.递归打印。文档是根据 AST 递归构建的。从根节点开始:
¥Recursive printing. A doc is recursively constructed from the AST. Starting from the root node:
如果从步骤 3 开始,存在与当前节点关联的嵌入式语言文档,则使用该文档。
¥If, from the step 3, there is an embedded language doc associated with the current node, this doc is used.
否则,调用
print(path, options, print): Doc
方法。它通常通过使用print
回调打印子节点来为当前节点撰写文档。¥Otherwise, the
print(path, options, print): Doc
method is called. It composes a doc for the current node, often by printing child nodes using theprint
callback.
print
插件打印机的大部分工作将在其 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;
print
函数传递了以下参数:
¥The print
function is passed the following parameters:
path
:一个对象,可用于访问 AST 中的节点。它是一种类似堆栈的数据结构,用于维护递归的当前状态。之所以称为“路径”,是因为它表示从 AST 根到当前节点的路径。当前节点由path.node
返回。¥
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
:一个持久对象,它包含全局选项并且插件可以改变它来存储上下文数据。¥
options
: A persistent object, which contains global options and which a plugin may mutate to store contextual data.print
:用于打印子节点的回调。此函数包含核心打印逻辑,该逻辑由插件提供的步骤组成。特别是,它调用打印机的print
函数并将自身传递给它。因此,两个print
函数(一个来自核心函数和一个来自插件函数)在 AST 递归下降时互相调用。¥
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’sprint
function and passes itself to it. Thus, the twoprint
functions – the one from the core and the one from the plugin – call each other while descending down the AST recursively.
这是一个简化的示例,可以让你了解 print
的典型实现是什么样子的:
¥Here’s a simplified example to give an idea of what a typical implementation of print
looks like:
import { doc } from "prettier";
const { group, indent, join, line, softline } = 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}`);
}
查看 prettier-python 的打印机 以了解一些可能的示例。
¥Check out prettier-python's printer for some examples of what is possible.
embed
(可选)¥(optional) embed
打印机可以使用 embed
方法在一种语言中打印另一种语言。这方面的例子是在 Markdown 中打印 CSS-in-JS 或围栏代码块。签名是:
¥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;
embed
方法与 print
方法类似,它将 AST 节点映射到文档,但与 print
不同的是,它能够通过返回异步函数来执行异步工作。该函数的第一个参数 textToDoc
异步函数可用于使用不同的插件渲染文档。
¥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.
如果从 embed
返回的函数返回一个文档或解析为文档的 Promise,则该文档将用于打印,并且不会为此节点调用 print
方法。也可以,在极少数情况下,直接从 embed
同步返回文档可能会很方便,但在这种情况下 textToDoc
和 print
回调不可用。返回一个函数来获取它们。
¥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.
如果 embed
返回 undefined
,或者它返回的函数返回 undefined
或解析为 undefined
的 Promise,则将使用 print
方法正常打印该节点。如果返回的函数抛出错误或返回拒绝的 promise(例如,如果发生解析错误),也会发生同样的情况。如果你希望 Prettier 重新抛出这些错误,请将 PRETTIER_DEBUG
环境变量设置为非空值。
¥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.
例如,具有嵌入 JavaScript 的节点的插件可能具有以下 embed
方法:
¥For example, a plugin that has nodes with embedded JavaScript might have the following embed
method:
function embed(path, options) {
const node = path.node;
if (node.type === "javascript") {
return async (textToDoc) => {
return [
"<script>",
hardline,
await textToDoc(node.javaScriptCode, { parser: "babel" }),
hardline,
"</script>",
];
};
}
}
如果 --embedded-language-formatting
选项设置为 off
,则完全跳过嵌入步骤,不调用 embed
,并且使用 print
方法打印所有节点。
¥If the --embedded-language-formatting
option is set to off
, the embedding step is entirely skipped, embed
isn’t called, and all nodes are printed with the print
method.
preprocess
(可选)¥(optional) preprocess
preprocess
方法可以在将解析器传递给 print
方法之前处理来自解析器的 AST。
¥The preprocess
method can process the AST from the parser before passing it into the print
method.
function preprocess(ast: AST, options: Options): AST | Promise<AST>;
getVisitorKeys
(可选)¥(optional) getVisitorKeys
如果插件使用注释附件或嵌入语言,此属性可能会派上用场。这些特性遍历 AST,从根开始迭代每个节点的所有自己的可枚举属性。如果 AST 具有 cycles,则这样的遍历将以无限循环结束。此外,节点可能包含非节点对象(例如位置数据),对其进行迭代会浪费资源。为了解决这些问题,打印机可以定义一个函数来返回应该遍历的属性名称。
¥This property might come in handy if the plugin uses comment attachment or embedded languages. These features traverse the AST iterating through all the own enumerable properties of each node starting from the root. If the AST has cycles, such a traverse ends up in an infinite loop. Also, nodes might contain non-node objects (e.g., location data), iterating through which is a waste of resources. To solve these issues, the printer can define a function to return property names that should be traversed.
它的签名是:
¥Its signature is:
function getVisitorKeys(node, nonTraversableKeys: Set<string>): string[];
默认 getVisitorKeys
:
¥The default getVisitorKeys
:
function getVisitorKeys(node, nonTraversableKeys) {
return Object.keys(node).filter((key) => !nonTraversableKeys.has(key));
}
第二个参数 nonTraversableKeys
是一组常用键和 prettier 使用的内部键。
¥The second argument nonTraversableKeys
is a set of common keys and keys that prettier used internal.
如果你有访客密钥的完整列表
¥If you have full list of visitor keys
const visitorKeys = {
Program: ["body"],
Identifier: [],
// ...
};
function getVisitorKeys(node /* , nonTraversableKeys*/) {
// Return `[]` for unknown node to prevent Prettier fallback to use `Object.keys()`
return visitorKeys[node.type] ?? [];
}
如果你只需要排除一小组键
¥If you only need exclude a small set of keys
const ignoredKeys = new Set(["prev", "next", "range"]);
function getVisitorKeys(node, nonTraversableKeys) {
return Object.keys(node).filter(
(key) => !nonTraversableKeys.has(key) && !ignoredKeys.has(key),
);
}
insertPragma
(可选)¥(optional) insertPragma
当在 insertPragma
函数中使用 --insert-pragma
选项时,插件可以实现如何在结果代码中插入 pragma 注释。它的签名是:
¥A plugin can implement how a pragma comment is inserted in the resulting code when the --insert-pragma
option is used, in the insertPragma
function. Its signature is:
function insertPragma(text: string): string;
在打印机中处理注释
¥Handling comments in a printer
注释通常不是语言 AST 的一部分,并且对漂亮的打印机提出了挑战。Prettier 插件可以在其 print
函数中自行打印注释,也可以依赖 Prettier 的注释算法。
¥Comments are often not part of a language's AST and present a challenge for pretty printers. A Prettier plugin can either print comments itself in its print
function or rely on Prettier's comment algorithm.
默认情况下,如果 AST 具有顶层 comments
属性,Prettier 会假定 comments
存储注释节点数组。然后 Prettier 将使用提供的 parsers[<plugin>].locStart
/locEnd
函数来搜索每个注释 "belongs" 的 AST 节点。然后将注释附加到这些节点,在该过程中改变 AST,并从 AST 根中删除 comments
属性。*Comment
函数用于调整 Prettier 的算法。一旦注释附加到 AST,Prettier 将自动调用 printComment(path, options): Doc
函数并将返回的文档插入(希望如此)正确的位置。
¥By default, if the AST has a top-level comments
property, Prettier assumes that comments
stores an array of comment nodes. Prettier will then use the provided parsers[<plugin>].locStart
/locEnd
functions to search for the AST node that each comment "belongs" to. Comments are then attached to these nodes mutating the AST in the process, and the comments
property is deleted from the AST root. The *Comment
functions are used to adjust Prettier's algorithm. Once the comments are attached to the AST, Prettier will automatically call the printComment(path, options): Doc
function and insert the returned doc into the (hopefully) correct place.
getCommentChildNodes
(可选)¥(optional) getCommentChildNodes
默认情况下,Prettier 递归地搜索每个节点的所有对象属性(除了一些预定义的属性)。可以提供此功能来覆盖该行为。它有签名:
¥By default, Prettier searches all object properties (except for a few predefined ones) of each node recursively. This function can be provided to override that behavior. It has the signature:
function getCommentChildNodes(
// The node whose children should be returned.
node: AST,
// Current options
options: object,
): AST[] | undefined;
如果节点没有子节点或 undefined
返回默认行为,则返回 []
。
¥Return []
if the node has no children or undefined
to fall back on the default behavior.
printComment
(可选)¥(optional) printComment
每当需要打印注释节点时调用。它有签名:
¥Called whenever a comment node needs to be printed. It has the signature:
function printComment(
// Path to the current comment node
commentPath: AstPath,
// Current options
options: object,
): Doc;
canAttachComment
(可选)¥(optional) canAttachComment
function canAttachComment(node: AST): boolean;
此函数用于决定是否可以将注释附加到特定的 AST 节点。默认情况下,遍历所有 AST 属性以搜索可以附加注释的节点。此功能用于防止注释附加到特定节点。一个典型的实现看起来像
¥This function is used for deciding whether a comment can be attached to a particular AST node. By default, all AST properties are traversed searching for nodes that comments can be attached to. This function is used to prevent comments from being attached to a particular node. A typical implementation looks like
function canAttachComment(node) {
return node.type && node.type !== "comment";
}
isBlockComment
(可选)¥(optional) isBlockComment
function isBlockComment(node: AST): boolean;
返回 AST 节点是否为块注释。
¥Returns whether or not the AST node is a block comment.
handleComments
(可选)¥(optional) handleComments
handleComments
对象包含三个可选函数,每个函数都有签名
¥The handleComments
object contains three optional functions, each with signature
(
// The AST node corresponding to the comment
comment: AST,
// The full source code text
text: string,
// The global options object
options: object,
// The AST
ast: AST,
// Whether this comment is the last comment
isLastComment: boolean,
) => boolean;
这些函数用于覆盖 Prettier 的默认注释附件算法。ownLine
/endOfLine
/remaining
要么手动将注释附加到节点并返回 true
,要么返回 false
并让 Prettier 附加注释。
¥These functions are used to override Prettier's default comment attachment algorithm. ownLine
/endOfLine
/remaining
is expected to either manually attach a comment to a node and return true
, or return false
and let Prettier attach the comment.
基于注释节点周围的文本,Prettier 调度:
¥Based on the text surrounding a comment node, Prettier dispatches:
ownLine
如果注释前面只有空格,后面有一个换行符,¥
ownLine
if a comment has only whitespace preceding it and a newline afterwards,endOfLine
如果注释后面有一个换行符但前面有一些非空格,¥
endOfLine
if a comment has a newline afterwards but some non-whitespace preceding it,remaining
在所有其他情况下。¥
remaining
in all other cases.
在调度时,Prettier 将至少用 enclosingNode
、precedingNode
或 followingNode
之一注释每个 AST 注释节点(即,创建新属性)。这些可以用来帮助插件的决策过程(当然整个 AST 和原始文本也被传入以做出更复杂的决策)。
¥At the time of dispatching, Prettier will have annotated each AST comment node (i.e., created new properties) with at least one of enclosingNode
, precedingNode
, or followingNode
. These can be used to aid a plugin's decision process (of course the entire AST and original text is also passed in for making more complicated decisions).
手动附加注释
¥Manually attaching a comment
util.addTrailingComment
/addLeadingComment
/addDanglingComment
函数可用于手动将注释附加到 AST 节点。确保注释不跟随 "punctuation" 节点的示例 ownLine
函数(出于演示目的而编写)可能如下所示:
¥The util.addTrailingComment
/addLeadingComment
/addDanglingComment
functions can be used to manually attach a comment to an AST node. An example ownLine
function that ensures a comment does not follow a "punctuation" node (made up for demonstration purposes) might look like:
import { util } from "prettier";
function ownLine(comment, text, options, ast, isLastComment) {
const { precedingNode } = comment;
if (precedingNode && precedingNode.type === "punctuation") {
util.addTrailingComment(precedingNode, comment);
return true;
}
return false;
}
带有注释的节点应该有一个包含注释数组的 comments
属性。每个注释都应具有以下属性:leading
、trailing
、printed
。
¥Nodes with comments are expected to have a comments
property containing an array of comments. Each comment is expected to have the following properties: leading
, trailing
, printed
.
上面的示例使用 util.addTrailingComment
,它会自动将 comment.leading
/trailing
/printed
设置为适当的值,并将注释添加到 AST 节点的 comments
数组中。
¥The example above uses util.addTrailingComment
, which automatically sets comment.leading
/trailing
/printed
to appropriate values and adds the comment to the AST node's comments
array.
--debug-print-comments
CLI 标志可以帮助调试注释附件问题。它会打印一份详细的注释列表,其中包括关于每条注释如何分类(ownLine
/endOfLine
/remaining
、leading
/trailing
/dangling
)以及它附加到哪个节点的信息。对于 Prettier 的内置语言,这些信息也可以在 Playground 上找到(调试部分的 '显示注释' 复选框)。
¥The --debug-print-comments
CLI flag can help with debugging comment attachment issues. It prints a detailed list of comments, which includes information on how every comment was classified (ownLine
/endOfLine
/remaining
, leading
/trailing
/dangling
) and to which node it was attached. For Prettier’s built-in languages, this information is also available on the Playground (the 'show comments' checkbox in the Debug section).
options
options
是一个包含你的插件支持的自定义选项的对象。
¥options
is an object containing the custom options your plugin supports.
示例:
¥Example:
export default {
// ... plugin implementation
options: {
openingBraceNewLine: {
type: "boolean",
category: "Global",
default: true,
description: "Move open brace for code blocks onto new line.",
},
},
};
defaultOptions
如果你的插件对 Prettier 的一些核心选项需要不同的默认值,你可以在 defaultOptions
中指定它们:
¥If your plugin requires different default values for some of Prettier’s core options, you can specify them in defaultOptions
:
export default {
// ... plugin implementation
defaultOptions: {
tabWidth: 4,
},
};
工具函数
¥Utility functions
来自 Prettier 核心的 util
模块被认为是私有 API,并不意味着被插件使用。相反,util-shared
模块为插件提供了以下有限的实用函数集:
¥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:
type Quote = '"' | "'";
type SkipOptions = { backwards?: boolean };
function getMaxContinuousCount(text: string, searchString: string): number;
function getStringWidth(text: string): number;
function getAlignmentSize(
text: string,
tabWidth: number,
startIndex?: number,
): number;
function getIndentSize(value: string, tabWidth: number): number;
function skip(
characters: string | RegExp,
): (
text: string,
startIndex: number | false,
options?: SkipOptions,
) => number | false;
function skipWhitespace(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipSpaces(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipToLineEnd(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipEverythingButNewLine(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipInlineComment(
text: string,
startIndex: number | false,
): number | false;
function skipTrailingComment(
text: string,
startIndex: number | false,
): number | false;
function skipNewline(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function hasNewline(
text: string,
startIndex: number,
options?: SkipOptions,
): boolean;
function hasNewlineInRange(
text: string,
startIndex: number,
startIndex: number,
): boolean;
function hasSpaces(
text: string,
startIndex: number,
options?: SkipOptions,
): boolean;
function makeString(
rawText: string,
enclosingQuote: Quote,
unescapeUnnecessaryEscapes?: boolean,
): string;
function getNextNonSpaceNonCommentCharacter(
text: string,
startIndex: number,
): string;
function getNextNonSpaceNonCommentCharacterIndex(
text: string,
startIndex: number,
): number | false;
function isNextLineEmpty(text: string, startIndex: number): boolean;
function isPreviousLineEmpty(text: string, startIndex: number): boolean;
教程
¥Tutorials
如何为 Prettier 编写插件:教你如何为 TOML 编写一个非常基本的 Prettier 插件。
¥How to write a plugin for Prettier: Teaches you how to write a very basic Prettier plugin for TOML.
测试插件
¥Testing Plugins
由于可以使用相对路径解析插件,因此在处理一个插件时,你可以执行以下操作:
¥Since plugins can be resolved using relative paths, when working on one you can do:
import * as prettier from "prettier";
const code = "(add 1 2)";
await prettier.format(code, {
parser: "lisp",
plugins: ["."],
});
这将解析一个相对于当前工作目录的插件。
¥This will resolve a plugin relative to the current working directory.