Prettier 编程式 API 详解:从 format 到插件化的完整实践指南
Prettier 编程式 API 详解从 format 到插件化的完整实践指南【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettierPrettier 除了命令行之外还暴露了一套完整的编程式 API供编辑器插件、CI 工具、自定义格式引擎直接调用。本文基于仓库文档 docs/api.md 展开完整覆盖format、check、formatWithCursor、resolveConfig等全部公开接口的用法与返回约定并结合 src/index.js、src/main/core.js、src/config/resolve-config.js 等源码实现解释每个 API 底层的执行路径帮助你在自研工具链中正确、高效地集成 Prettier。一、引入方式与 API 的整体形态文档开头给出的标准引入方式import * as prettier from prettier;所有公开 API 均为异步函数返回Promise。这是 Prettier v3 的重要约定如果必须使用同步版本文档推荐借助第三方包装层如prettier/sync包来桥接而不是在核心 API 中提供同步入口。从 package.json 的exports字段可以确认模块解析关系{ exports: { .: { types: ./src/index.d.ts, require: ./src/index.cjs, default: ./src/index.js }, ./standalone: ./src/standalone.js, ./plugins/*: ./src/plugins/*.js, ./*: ./* }, engines: { node: 22 } }import prettier对应 src/index.jsESM或 src/index.cjsCJS完整功能入口prettier/standalone对应 src/standalone.js面向浏览器/独立运行的裁剪版prettier/plugins/*对应 src/plugins/ 下按语言切分出的内置插件供外部以插件形式显式加载当前开发版本为3.10.0-dev运行时要求 Node.js22。standalone 入口的 API 子集对比 src/standalone.js 的导出列表export { debugApis as __debug, check, format, formatWithCursor, getSupportInfo, }; export * as doc from ./document/public.js; export { default as version } from ./main/version.evaluate.js; export * as util from ./utilities/public.js;可以看到 standalone 版只导出check、format、formatWithCursor、getSupportInfo外加doc、util、version并不包含resolveConfig、getFileInfo等依赖文件系统搜索的 API——这与其面向浏览器、无法自由搜索配置目录的定位一致。如果你的运行环境是 Node.js则应使用主入口获取完整 API。二、prettier.format(source, options)format是最核心的接口用于把一段文本格式化为 Prettier 风格。使用约定options.parser必须按照目标语言显式设置可用解析器列表见 docs/options.md或者改用options.filepath让 Prettier 根据文件扩展名推断解析器其余 options 均可传入以覆盖默认值。文档示例await prettier.format(foo ( );, { semi: false, parser: babel }); // - foo()\n源码实现src/index.js 中format并不是独立实现而是formatWithCursor的薄封装——内部强制把cursorOffset置为-1表示不追踪光标取出结果中的formatted字段返回const formatWithCursor withPlugins(core.formatWithCursor); async function format(text, options) { const { formatted } await formatWithCursor(text, { ...options, cursorOffset: -1, }); return formatted; }值得注意的是withPlugins包装器src/index.js它会在调用真正格式化逻辑之前把options.plugins中的字符串/URL 路径通过loadBuiltinPlugins()和loadPlugins()加载为插件对象并注入选项。也就是说plugins选项接受插件对象、文件路径或 URLAPI 层会自动完成加载。三、prettier.check(source, options)check用于判断文件是否已经是 Prettier 格式化后的产物返回Promiseboolean。它与 CLI 的--check/--list-different参数语义一致非常适合在 CI 中做格式校验格式化失败即阻断流水线。从源码看src/index.js它的实现极其简洁——直接执行一次format并与原文全等比较async function check(text, options) { return (await format(text, options)) text; }这意味着check与format对配置的解读完全一致若options中缺少parser同样需要依赖filepath推断。四、prettier.formatWithCursor(source, options)编辑器集成的关键formatWithCursor在格式化代码的同时把未格式化代码中的光标位置映射到格式化后的对应位置。这是编辑器集成的刚需格式化后光标不能跳走。使用它时必须通过cursorOffset选项指明光标所在的字符偏移await prettier.formatWithCursor( 1, { cursorOffset: 2, parser: babel }); // - { formatted: 1;\n, cursorOffset: 1 }光标迁移算法底层实现在 src/main/core.js 的formatWithCursor中注释里完整描述了三步策略格式化前基于 AST 找出包含光标的最小区域叶子节点、两节点之间的空隙、或文档首尾格式化中记录该区域被写到了新文本的什么位置格式化后把光标当作一个特殊字符Symbol(cursor)插入旧区域文本对新旧区域做仅含插入/删除的 diffsrc/main/core.js 使用diff库的diffArrays从 diff 结果中反推出光标在新文本中的偏移const oldCursorNodeCharArray oldCursorRegionText.split(); oldCursorNodeCharArray.splice(cursorOffsetRelativeToOldCursorRegionStart, 0, CURSOR); const cursorNodeDiff diffArrays(oldCursorNodeCharArray, newCursorNodeCharArray); let cursorOffset newCursorRegionStart; for (const entry of cursorNodeDiff) { if (entry.removed) { if (entry.value.includes(CURSOR)) break; } else { cursorOffset entry.count; } }此外还有几个值得了解的行为细节见 src/main/core.jsBOM 处理输入若以 BOM 开头会先剥离、格式化后再补回光标偏移相应调整换行归一endOfLine: auto时按内容猜测换行符CRLF输入会先归一为LF参与计算输出时再转回Range 格式化设置了rangeStart/rangeEnd时走formatRange分支src/main/core.js只格式化片段并恢复原始缩进光标在范围外时保持不动PragmasrequirePragma、insertPragma、checkIgnorePragma均在此层统一裁决不满足条件时原样返回输入。五、prettier.resolveConfig(fileUrlOrPath, options)resolveConfig为某个源文件解析 Prettier 配置从文件所在目录开始向上搜索配置文件也可以直接把配置文件路径作为options.config传入以跳过搜索。返回 Promise找到配置时resolve 为一个选项对象未找到时resolve 为null配置文件解析出错时Promise 被 reject。文档给出的典型用法读取文件 → 解析配置 → 格式化const text await fs.readFile(filePath, utf8); const options await prettier.resolveConfig(filePath); const formatted await prettier.format(text, { ...options, filepath: filePath, });参数与底层行为options.useCache默认true缓存目录结构以加速重复查询设为false时完全绕过缓存见 src/config/resolve-config.js 中options { useCache: true, ...options }。options.editorconfig设为true且项目存在.editorconfig时Prettier 会解析它并转换为对应配置但优先级低于.prettierrc等 Prettier 配置文件。目前支持的 EditorConfig 属性end_of_lineindent_styleindent_size/tab_widthmax_line_length实现上resolveConfig会并行加载 Prettier 配置与 EditorConfigsrc/config/resolve-config.js 中的Promise.all([loadPrettierConfig(...), loadEditorconfig(...)])再合并const merged { ...editorConfigured, // EditorConfig 垫底 ...mergeOverrides(result, filePath), // .prettierrc含 overrides覆盖 };其中mergeOverridessrc/config/resolve-config.js会用micromatch匹配overrides[].files/excludeFiles基于配置文件所在目录的相对路径命中则用override.options覆盖基础选项。另外配置里声明的plugins若为相对路径以.开头会被解析为相对于配置文件目录的绝对路径。六、prettier.resolveConfigFile([fileUrlOrPath])resolveConfigFile只回答一个问题最终会使用哪个配置文件。返回 Promise找到时 resolve 为配置文件的路径字符串未找到时 resolve 为null解析出错时 reject。搜索起点是process.cwd()若提供了fileUrlOrPath参数则从该文件所在目录开始。对应实现见 src/config/resolve-config.js——它始终用shouldCache: false调用searchPrettierConfig即本 API 自身不参与缓存复用。const configFile await prettier.resolveConfigFile(filePath); // you got the path of the configuration file它与resolveConfig是配套关系resolveConfigFile给出路径resolveConfig给出解析后的选项。七、prettier.clearConfigCache()当 Prettier 反复读取配置文件与插件时会为性能缓存文件系统结构resolveConfig系列默认启用缓存。clearConfigCache用于主动清空该缓存——典型场景是编辑器集成方已知文件系统在两次格式化之间发生了变化新增了.prettierrc、改动忽略规则等。从主入口的实现看src/index.js它实际清空的不仅是配置缓存async function clearCache() { clearConfigCache(); // 清 .prettierrc / .editorconfig 的缓存 clearPluginCache(); // 同时清插件加载缓存 }八、prettier.getFileInfo(fileUrlOrPath, options)getFileInfo面向编辑器扩展在真正格式化之前先判断某个文件要不要格式化、用哪个解析器。它返回一个 Promiseresolve 为{ ignored: boolean; inferredParser: string | null; }约束与选项第一个参数必须是string或URL否则 Promise 被 reject见 src/common/get-file-info.js 的TypeError抛出options.ignorePathstring | URL | (string | URL)[]指定.prettierignore之类的忽略文件options.withNodeModulesboolean是否把node_modules也视为可忽略对象二者共同影响ignored的取值若文件被忽略inferredParser恒为nulloptions.plugins(string | URL | Plugin)[]提供插件路径有助于为 Prettier 核心不直接支持的文件类型推断出inferredParseroptions.resolveConfigboolean默认true设为false时跳过配置文件搜索适合只关心是否被忽略的低成本调用。从源码看src/common/get-file-info.js推断解析器的优先级是显式options.parser→ 配置文件中声明的parser→ 根据插件的语言描述与文件扩展名推断inferParser。另外源码注释特别提到本 API 的plugins期望是路径数组与format等接口的插件加载方式有意区分涉及 VS Code 扩展的兼容历史。九、prettier.getSupportInfo()getSupportInfo()返回一个 Promiseresolve 为描述 Prettier 当前支持范围的SupportInfo对象{ languages: Array{ name: string; parsers: string[]; group?: string; tmScope?: string; aceMode?: string; codemirrorMode?: string; codemirrorMimeType?: string; aliases?: string[]; extensions?: string[]; filenames?: string[]; linguistLanguageId?: number; vscodeLanguageIds?: string[]; isSupported?(options: { filepath: string }): boolean; }; options: SupportOption[]; }options部分的结构定义见 src/index.d.ts 的SupportInfo。它的典型用途是给编辑器补全 Prettier 选项、为语言动态推荐parser。实现位于 src/main/support.js从所有插件聚合languages合并插件options与核心选项定义并可通过showDeprecated参数决定是否保留已废弃的选项与选项值。一个来自文档的注意点Prettier 无法保证filepath在磁盘上真实存在若通过 API如prettier.format()使用连路径是否有效都无法保证——因此依赖isSupported(options: { filepath })这类回调时调用方需自行兜底。十、Custom Parser API已移除与插件迁移文档明确标记Custom Parser API 已在 v3.0.0 中移除被 Plugin API 取代。在插件出现之前parser选项可以直接传一个函数// ❌ Custom parser API (removed) import { format } from prettier; format(lodash ( ), { parser(text, { babel }) { const ast babel(text); ast.program.body[0].expression.callee.name _; return ast; }, }); // - _();\n等价迁移到 Plugin API 后需要定义一个含parsers的插件对象并在选项里通过plugins显式传入// ✔️ Plugin API import { format } from prettier; import * as prettierPluginBabel from prettier/plugins/babel; const myCustomPlugin { parsers: { my-custom-parser: { async parse(text) { const ast await prettierPluginBabel.parsers.babel.parse(text); ast.program.body[0].expression.callee.name _; return ast; }, astFormat: estree, }, }, }; await format(lodash ( ), { parser: my-custom-parser, plugins: [myCustomPlugin], }); // - _();\n迁移要点解析器变成具名函数通过parser: my-custom-parser引用astFormat声明产物 AST 的格式此处复用内置的estree打印器parse可以是asyncparse的入参是(text, options)插件对象可内联传入plugins数组也可通过文件路径加载prettier/plugins/*导出见 package.json 的exports各语言内置插件见 src/plugins/。文档同时警告用这种方式做 codemod 并不推荐。Prettier 依赖 AST 节点上的位置信息locStart/locEnd来保留空行、挂载注释等在解析后再修改 AST位置信息很容易与新结构失配导致不可预测的输出。文档建议需要 codemod 请考虑专用工具如 jscodeshift而不是借道 Prettier 的自定义解析器。此外旧的--parser选项允许传入导出parse函数的模块路径现已统一改为用--pluginCLI 选项或 API 的plugins选项来加载插件详见 docs/plugins.md。十一、API 速查与选型建议API返回典型场景实现入口format(source, options)Promisestring任何给我格式化结果的调用src/index.jscheck(source, options)PromisebooleanCI 格式校验等价--checksrc/index.jsformatWithCursor(source, options)Promise{formatted, cursorOffset}编辑器 LSP/扩展集成src/main/core.jsresolveConfig(file, options)PromiseOptions \| null按文件解析配置含 overrides / EditorConfigsrc/config/resolve-config.jsresolveConfigFile([file])Promisestring \| null只查配置文件路径src/config/resolve-config.jsclearConfigCache()Promisevoid文件系统变化后清理缓存src/index.jsgetFileInfo(file, options)Promise{ignored, inferredParser}编辑器决定是否格式化src/common/get-file-info.jsgetSupportInfo([options])PromiseSupportInfo选项/语言元数据、自动补全src/main/support.js选型建议依据上文源码行为归纳纯格式化用format需要保持光标则换成formatWithCursor并传cursorOffsetCI 校验用check失败即非零退出需要尊重项目配置先resolveConfig再与filepath一起传给format配置文件会热更新时记得在合适时机clearConfigCache编辑器要不要管这个文件先getFileInfo可设resolveConfig: false提速ignored为false且inferredParser非空才进入格式化浏览器/无文件系统环境只能用standalone入口暴露的format/check/formatWithCursor/getSupportInfo子集配置需要由宿主自行解析后作为options传入。配套的完整选项定义RequiredOptions、Plugin、SupportInfo等类型可参阅仓库自带的 src/index.d.ts各选项的取值与默认值说明见 docs/options.md配置文件的搜索与overrides规则见 docs/configuration.md。【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →