Pular para o conteúdo

Formatador

Phasis oferece um formatador JavaScript nativo, baseado no próprio parser. Ele reimprime o código-fonte com regras de layout compatíveis com prettier, inteiramente em PHP: sem Node.js, sem pacotes de formatação interpretados, sem processos externos.

formatSource

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

O ponto de entrada de chamada única em Phasis\Formatter\Formatter. $sourceType seleciona a linguagem: script ou module para JavaScript, json ou css. JavaScript analisa conforme o objetivo informado, reanexa os comentários e imprime com a largura de impressão configurada.

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"

Código-fonte inválido gera o mesmo Phasis\Exceptions\SyntaxError que o parser, com linha, coluna e deslocamento.

FormatOptions

As opções de layout espelham 3.x do prettier e usam os valores padrão do prettier:

Opção Padrão Significado
printWidth 80 Largura de linha desejada para ajustar o layout.
tabWidth 2 Espaços por nível de indentação (e largura medida de uma tabulação).
useTabs false Indentar com tabulações em vez de espaços.
semi true Ponto e vírgula em instruções.
singleQuote false Preferir ' a " quando exigir menos escapes.
trailingComma 'all' 'all', 'es5' ou 'none'.
bracketSpacing true Espaços dentro de chaves de objetos: { a } versus {a}.
arrowParens 'always' 'always' ou 'avoid' para funções arrow de parâmetro único.

CSS

formatSource($css, 'css') formata folhas de estilo com o layout de folhas de estilo do prettier: um seletor por linha em listas de seletores, uma declaração por linha, espaçamento normalizado de combinadores e valores, listas simples de valores compactadas ao preencher a linha, listas separadas por vírgulas de sombras e gradientes com um item por linha, argumentos de função que são formatados todos juntos ou não são formatados, linhas em branco e comentários preservados e preâmbulos intocados para regras at desconhecidas, como Tailwind de @apply. Seletores compostos longos quebram nos combinadores descendentes, e argumentos extensos de pseudoclasses são distribuídos dentro dos parênteses.

JSON

formatSource($json, 'json') reutiliza o parser e os formatadores JavaScript com as regras json do prettier: as chaves permanecem entre aspas, as strings continuam entre aspas duplas independentemente de singleQuote, nunca são adicionadas vírgulas finais e os comentários // dentro do documento são preservados.

Regras de layout

O formatador implementa o modelo de documento do prettier: grupos são achatados quando cabem na largura de impressão e quebram caso contrário; os argumentos de chamadas ficam junto ao argumento de função ou objeto no fim; cadeias de membros quebram antes de cada ponto quando ultrapassam a linha; objetos escritos em várias linhas continuam em várias linhas; e no máximo uma linha em branco é preservada entre instruções. Com opções correspondentes, o formatador gera saída idêntica byte a byte para código real formatado pelo prettier; a suíte de conformidade verifica isso exatamente com fixtures gerados pelo próprio prettier.

Comentários

Os comentários são coletados durante a tokenização (Parser::setCollectComments(true), expostos no parser para ferramentas) e reanexados à árvore como anexos iniciais, finais ou soltos. Comentários de linha mantêm suas próprias linhas, comentários finais na mesma linha permanecem na instrução, as linhas em branco ao redor dos comentários são preservadas e blocos /** ... */ são reindentados com o recuo de margem * alinhado.

Garantias

Três invariantes valem para toda saída formatada, conforme verificado pela suíte de testes:

  • A saída é analisada novamente como um programa equivalente (exceto pelas localizações).
  • Todos os comentários da entrada são preservados na saída.
  • A formatação é idempotente: formatar uma saída já formatada não altera nada.

Desempenho

A formatação é tão rápida quanto a análise: arquivos reais são formatados em dezenas de milissegundos, e o código-fonte JavaScript escrito à mão em um projeto típico é formatado de ponta a ponta em bem menos de um segundo, em um único processo.