Skip to content

Formatter

Phasis ships a native JavaScript formatter built on its own parser. It reprints source with prettier-compatible layout semantics, entirely in PHP: no Node.js, no interpreted formatter bundles, no external processes.

formatSource

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

The one-call entry point on Phasis\Formatter\Formatter. $sourceType selects the language: script or module for JavaScript, json, or css. JavaScript parses under the given goal, gets its comments reattached, and prints against the configured print width.

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"

Invalid source throws the same Phasis\Exceptions\SyntaxError as the parser, with line, column, and offset.

FormatOptions

Layout options mirror prettier 3.x and default to prettier's defaults:

Option Default Meaning
printWidth 80 Target line width the layout is fitted against.
tabWidth 2 Spaces per indent level (and the measured width of a tab).
useTabs false Indent with tabs instead of spaces.
semi true Statement semicolons.
singleQuote false Prefer ' over " where it needs fewer escapes.
trailingComma 'all' 'all', 'es5', or 'none'.
bracketSpacing true Spaces inside object braces: { a } versus {a}.
arrowParens 'always' 'always' or 'avoid' for single-parameter arrow functions.

CSS

formatSource($css, 'css') formats stylesheets with prettier's stylesheet layout: one selector per line in selector lists, one declaration per line, normalized combinator and value spacing, fill-packed simple value lists, one-per-line comma lists for shadows and gradients, all-or-nothing function arguments, preserved blank lines and comments, and untouched preludes for unknown at-rules such as Tailwind's @apply. Long compound selectors break at descendant combinators, and overlong pseudo-class arguments wrap inside their parentheses.

JSON

formatSource($json, 'json') reuses the JavaScript parser and printers with prettier's json rules: keys stay quoted, strings stay double quoted regardless of singleQuote, trailing commas never appear, and // comments inside the document survive.

Layout semantics

The printer implements the prettier document model: groups flatten when they fit the print width and break otherwise, call arguments hug a trailing function or object argument, member chains break before each dot when they outgrow the line, objects written across multiple lines stay multiline, and at most one blank line is preserved between statements. On prettier-formatted input with matching options the formatter is byte-identical on real-world code; its conformance suite asserts exactly that against fixtures generated by prettier itself.

Comments

Comments are collected during tokenization (Parser::setCollectComments(true), exposed on the parser for tooling) and reattached to the tree as leading, trailing, or dangling attachments. Line comments keep their own lines, same-line trailing comments stay on their statement, blank lines around comments survive, and /** ... */ blocks are reindented with their * gutter aligned.

Guarantees

Three invariants hold for every formatted output, enforced by the test suite:

  • The output reparses to an equivalent program (locations aside).
  • Every comment in the input survives into the output.
  • Formatting is idempotent: formatting formatted output changes nothing.

Performance

Formatting is parser-speed work: real-world files format in tens of milliseconds, and a typical project's hand-written JavaScript formats end to end in well under a second in a single process.