
# 포매터

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`로 언어를 선택합니다. JavaScript에는 `script` 또는 `module`를, `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의 스타일시트 레이아웃 규칙으로 스타일시트를 포맷합니다. 선택자 목록에서는 선택자마다 한 줄씩, 선언마다 한 줄씩 배치하고, 결합자와 값의 간격을 정규화합니다. 단순 값 목록은 줄 너비에 맞춰 채우고, 그림자와 그라디언트의 쉼표 목록은 항목마다 한 줄씩 배치합니다. 함수 인수는 모두 한 줄에 두거나 모두 여러 줄로 나누며, 빈 줄과 주석을 보존합니다. Tailwind의 `@apply`처럼 알 수 없는 at-rule의 전치부는 수정하지 않습니다. 긴 복합 선택자는 하위 선택자 결합자 앞에서 줄을 나누며, 너무 긴 의사 클래스 인수는 괄호 안에서 줄을 바꿉니다.

## JSON

`formatSource($json, 'json')`는 JavaScript 파서와 프린터를 재사용하며 prettier의 JSON 규칙을 적용합니다. 키는 따옴표로 감싸고, `singleQuote`와 관계없이 문자열은 큰따옴표를 유지하며, 후행 쉼표는 사용하지 않습니다. 문서 내부의 `//` 주석도 보존됩니다.

## 레이아웃 규칙

프린터는 prettier 문서 모델을 구현합니다. 그룹이 출력 너비에 들어가면 한 줄로 펴고, 그렇지 않으면 줄을 나눕니다. 호출 인수는 뒤따르는 함수 또는 객체 인수와 붙여 배치하며, 멤버 체인이 줄을 넘으면 각 점 앞에서 줄을 나눕니다. 여러 줄로 작성된 객체는 여러 줄 형식을 유지하고, 문장 사이에는 빈 줄을 최대 하나까지 보존합니다. 옵션이 일치하는 prettier 포맷 입력은 실제 코드에서도 바이트 단위로 동일하게 출력됩니다. 적합성 테스트는 prettier 자체에서 생성한 픽스처로 이를 검증합니다.

## 주석

토큰화 중 주석을 수집하고(`Parser::setCollectComments(true)`, 도구에서 사용할 수 있도록 파서에 노출됨) 트리에 선행, 후행 또는 독립 주석으로 다시 연결합니다. 줄 주석은 원래 줄에 유지되고, 같은 줄의 후행 주석은 해당 문장에 붙어 있으며, 주석 주변의 빈 줄도 보존됩니다. `/** ... */` 블록은 들여쓰기를 다시 적용하고 `*` 여백을 맞춥니다.

## 보장 사항

테스트 스위트가 적용하는 다음 세 가지 불변 조건은 포맷된 모든 출력에서 성립합니다.

- 출력은 동등한 프로그램으로 다시 파싱됩니다(위치는 제외).
- 입력의 모든 주석이 출력에도 유지됩니다.
- 포맷은 멱등적입니다. 포맷된 출력을 다시 포맷해도 바뀌지 않습니다.

## 성능

포맷은 파서 속도로 실행됩니다. 실제 파일은 수십 밀리초 안에 포맷되며, 일반적인 프로젝트에서 직접 작성한 JavaScript도 단일 프로세스에서 전체 포맷에 1초가 채 걸리지 않습니다.
