
# 格式化程序

Phasis 提供原生 JavaScript 格式化程序，基于自有解析器构建。它会按照兼容 prettier 的布局语义重新打印源代码，完全在 PHP 中运行：无需 Node.js、无需解释型格式化程序包，也无需外部进程。

## formatSource

```php
public static function formatSource(
    string $source,
    string $sourceType = 'script',
    ?FormatOptions $options = null,
): string
```

`Phasis\Formatter\Formatter` 上的一站式调用入口。`$sourceType` 用于选择语言：`script` 或 `module` 对应 JavaScript、`json` 或 `css`。JavaScript 会按给定的目标解析，重新附加注释，然后按照配置的打印宽度输出。

```php
use Phasis\Formatter\Formatter;
use Phasis\Formatter\FormatOptions;

$formatted = Formatter::formatSource(
    "const a={x:1,y:2};",
    'script',
    new FormatOptions(useTabs: true, singleQuote: true),
);
// "const a = { x: 1, y: 2 };\n"
```

无效源代码会抛出与解析器相同的 `Phasis\Exceptions\SyntaxError`，并包含行、列和偏移量。

## FormatOptions

布局选项与 prettier 的 3.x 相同，默认值也与 prettier 的默认值一致：

| 选项 | 默认值 | 含义 |
| --------------- | ---------- | -------------------------------------------------------------- |
| `printWidth` | `80` | 布局适配的目标行宽。 |
| `tabWidth` | `2` | 每个缩进级别的空格数（也是制表符的测量宽度）。 |
| `useTabs` | `false` | 使用制表符而非空格缩进。 |
| `semi` | `true` | 语句分号。 |
| `singleQuote` | `false` | 在转义更少时优先使用 `'` 而非 `"`。 |
| `trailingComma` | `'all'` | `'all'`、`'es5'` 或 `'none'`。 |
| `bracketSpacing` | `true` | 对象花括号内的空格：`{ a }` 与 `{a}`。 |
| `arrowParens` | `'always'` | 单参数箭头函数使用 `'always'` 或 `'avoid'`。 |

## CSS

`formatSource($css, 'css')` 使用 prettier 的样式表布局规则格式化样式表：选择器列表中每行一个选择器，每行一个声明，规范化组合符和取值的空格，简单取值列表尽量填满行，阴影和渐变的逗号分隔列表每行一个条目，函数参数要么全都换行、要么都不换行，保留空行和注释，并且不改动未知 at 规则的前导内容，例如 Tailwind 的 `@apply`。较长的复合选择器会在后代组合符处换行，过长的伪类参数则会在括号内换行。

## JSON

`formatSource($json, 'json')` 重用 JavaScript 解析器和打印器，并采用 prettier 的 json 规则：键保持带引号，字符串始终使用双引号，不受 `singleQuote` 影响，不会出现尾随逗号，文档内的 `//` 注释也会保留。

## 布局语义

打印器采用 prettier 文档模型：内容适合打印宽度时会将组展平，否则会换行；调用参数会紧贴末尾的函数或对象参数；成员链超出行宽时会在每个点号前换行；跨多行书写的对象会保持多行；语句间最多保留一个空行。对于选项匹配的 prettier 格式输入，格式化结果与真实项目代码逐字节一致；其一致性测试套件会针对由 prettier 本身生成的样例验证这一点。

## 注释

注释在词法分析期间收集（`Parser::setCollectComments(true)`，可通过解析器提供给工具使用），随后作为前置、尾随或游离注释重新附加到语法树。行注释保留在各自的行上，同一行的尾随注释仍留在对应语句上，注释周围的空行会保留，`/** ... */` 块会重新缩进，并对齐其 `*` 竖线边栏。

## 保证

测试套件会强制确保每次格式化输出都满足以下三项不变量：

- 输出重新解析后会得到等效程序（位置除外）。
- 输入中的每条注释都会保留在输出中。
- 格式化具有幂等性：格式化后的输出再次格式化不会发生变化。

## 性能

格式化速度与解析器相当：真实项目文件通常在几十毫秒内完成格式化，典型项目中手写的 JavaScript 在单个进程中从头到尾通常不到一秒。
