Formatter
Phasis bietet einen nativen JavaScript-Formatter, der auf einem eigenen Parser basiert. Er gibt Quellcode mit einem prettier-kompatiblen Layout aus, vollständig in PHP: kein Node.js, keine interpretierten Formatter-Bundles, keine externen Prozesse.
formatSource
public static function formatSource(
string $source,
string $sourceType = 'script',
?FormatOptions $options = null,
): string
Der Einstiegspunkt mit einem Aufruf in Phasis\Formatter\Formatter. $sourceType legt die Sprache fest: script oder module für JavaScript, json oder css. JavaScript parst mit dem angegebenen Ziel, fügt die Kommentare wieder ein und gibt den Code mit der konfigurierten Zeilenbreite aus.
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"
Ungültiger Quellcode löst denselben Phasis\Exceptions\SyntaxError wie der Parser aus, einschließlich Zeile, Spalte und Offset.
FormatOptions
Die Layoutoptionen entsprechen prettier 3.x und verwenden standardmäßig die Voreinstellungen von prettier:
| Option | Standard | Bedeutung |
|---|---|---|
printWidth |
80 |
Zielzeilenbreite, an die das Layout angepasst wird. |
tabWidth |
2 |
Leerzeichen pro Einrückungsebene (und gemessene Breite eines Tabs). |
useTabs |
false |
Tabs statt Leerzeichen zur Einrückung verwenden. |
semi |
true |
Semikolons nach Anweisungen. |
singleQuote |
false |
' gegenüber " bevorzugen, wenn dadurch weniger Escape-Sequenzen nötig sind. |
trailingComma |
'all' |
'all', 'es5' oder 'none'. |
bracketSpacing |
true |
Leerzeichen innerhalb von Objektklammern: { a } gegenüber {a}. |
arrowParens |
'always' |
'always' oder 'avoid' bei Arrow-Funktionen mit einem Parameter. |
CSS
formatSource($css, 'css') formatiert Stylesheets nach dem Stylesheet-Layout von prettier: ein Selektor pro Zeile in Selektorlisten, eine Deklaration pro Zeile, normalisierte Abstände bei Kombinatoren und Werten, kompakt gesetzte einfache Wertelisten, kommaseparierte Listen mit einem Eintrag pro Zeile bei Schatten und Verläufen, Funktionsargumente entweder alle in einer Zeile oder alle mit Zeilenumbruch, erhaltene Leerzeilen und Kommentare sowie unveränderte Präambeln bei unbekannten At-Regeln wie @apply von Tailwind. Lange zusammengesetzte Selektoren werden an Nachfahren-Kombinatoren umgebrochen, und zu lange Argumente von Pseudoklassen werden innerhalb ihrer Klammern umgebrochen.
JSON
formatSource($json, 'json') verwendet den JavaScript-Parser und die Printer erneut, diesmal mit den JSON-Regeln von prettier: Schlüssel bleiben in Anführungszeichen, Strings bleiben unabhängig von singleQuote in doppelten Anführungszeichen, nachgestellte Kommas entfallen immer und //-Kommentare im Dokument bleiben erhalten.
Layoutsemantik
Der Printer setzt das Dokumentmodell von prettier um: Gruppen werden zu einer Zeile zusammengezogen, wenn sie in die Druckbreite passen, und andernfalls umgebrochen; Aufrufargumente bleiben bei einem abschließenden Funktions- oder Objektargument, Elementketten werden bei Überschreiten der Zeilenbreite vor jedem Punkt umgebrochen, mehrzeilig geschriebene Objekte bleiben mehrzeilig, und zwischen Anweisungen bleibt höchstens eine Leerzeile erhalten. Bei mit passenden Optionen von prettier formatiertem Eingabecode ist die Ausgabe bei echtem Code byte-identisch; die Konformitätstestsuite prüft dies genau anhand von Fixtures, die mit prettier selbst erzeugt wurden.
Kommentare
Kommentare werden während der Tokenisierung gesammelt (Parser::setCollectComments(true), im Parser für Tools zugänglich) und als vorangestellte, nachgestellte oder freistehende Anhänge wieder am Baum angebracht. Zeilenkommentare bleiben in ihrer eigenen Zeile, nachgestellte Kommentare in derselben Zeile bleiben bei ihrer Anweisung, Leerzeilen um Kommentare bleiben erhalten und /** ... */-Blöcke werden mit ausgerichteter *-Einrückung neu eingerückt.
Garantien
Für jede formatierte Ausgabe gelten drei Invarianten, die von der Testsuite geprüft werden:
- Die Ausgabe lässt sich zu einem gleichwertigen Programm parsen (abgesehen von Positionen).
- Jeder Kommentar aus der Eingabe bleibt in der Ausgabe erhalten.
- Die Formatierung ist idempotent: Wird eine formatierte Ausgabe erneut formatiert, ändert sich nichts.
Leistung
Formatierung ist so schnell wie das Parsen: Dateien aus der Praxis werden in wenigen Dutzend Millisekunden formatiert, und der handgeschriebene JavaScript-Code eines typischen Projekts wird in einem einzelnen Prozess in deutlich weniger als einer Sekunde komplett formatiert.