Formatowanie plików JavaScript w generatorze XPAND

Mechanizm szablonów XPAND jest moim ulubionym generatorem kodu. Jest nieprawdopodobnie wygodny i posiada wiele unikalnych cech które naprawdę ułatwiają pracę. Tematem tego wpisu (tutoriala) będą tzw. upiększacze kodu.

W generatorze XPAND domyślnie mamy dwa takie upiększacze: JavaBeautifier oraz XmlBeautifier. Jeżeli generujemy kod w jednej z obsługiwanych notacji dzięki dodaniu tych klas do procesu mamy pięknie sformatowany i czytelny kod wynikowy. Co jednak jeżeli generujemy kod JavaScript gdy budujemy aplikację webową? Cóż wynik nie jest najciekawszy. Praktycznie wygenerowanie czytelnego kodu graniczy z cudem i wymaga tworzenie naprawdę nieczytelnych szablonów które symulują częściowo formatowanie wynikowe co stanowi wyjątkowo brzydki anty-wzorzec. Koszmar którego nawet nie będę prezentował.

Dlaczego nie ma domyślnie klasy formatującej JavaScript w pakiecie XPAND? Odpowiedzią jest oczywiście nieskończona ilość generowanych notacji. Spróbujmy więc czy napisanie klasy pomocniczej dla JavaScript jest trudne.

Od czego zacząć? Myślę że powinniśmy postępować zgodnie z metodologią "Monkey see/Monkey do" zaprezentowaną kilka lat temu przez Ericha Gammę w książce "Contributing to Eclipse". Co kryje się pod tym tajemniczym sformułowaniem? Prosta zasada "zobacz jak robią to inni, skopiuj i dostosuj rozwiązanie do swoich potrzeb".

Zobaczmy więc jak działa klasa JavaBeautifier. Otwieramy sobie jej źródło i wszystko staje się jasne. Klasa ta implementuje interfejs PostProcessor z metodą: beforeWriteAndClose(FileHandle fileHandle) odpowiedzialną za formatowanie kodu. Sam proces formatowania przekazywany jest do mechanizmów JDT wykorzystując klasę: org.eclipse.jdt.core.formatter.CodeFormatter;

Cały process wygląda mniej więcej następująco:

beforeWriteAndClose(final FileHandle fileHandle){
  jeżeli rozszerzenie == 'java' to:
    Document doc = new Document(fileHandle.getBuffer().toString());
    TextEdit edit = getCodeFormatter().format(
      CodeFormatter.K_COMPILATION_UNIT, doc.get(), 0, doc.get().length(), 0, null);
    edit.apply(doc);
    fileHandle.setBuffer(new StringBuffer(doc.get()));
}


CodeFormatter getCodeFormatter() {
  inicjacja opcji na podstawie ustawień formatowania
  return ToolFactory.createCodeFormatter(options);
}


Jak widać całość opiera się o gotowe mechanizmy formatujące. Ponieważ identyczne możliwości formatowania kodu zostały zaimplementowane także w WTP dla edytora JavaScript wykorzystanie tego podejścia nie wydaje się być problemem. Jak jednak znaleźć odpowiedni kod w środowisku złożonym z grubo ponad tysiąca projektów jeżeli nie wiemy gdzie mechanizmy te zostały zaimplementowane? Wykorzystamy mechanizm Plugin Spy pokazujący nam informacje o praktycznie dowolnym elemencie środowiska. Otwieramy edytor JavaScript dostarczany z pakietem WTP, ALT+SHIFT+F1 i pojawia nam się następująca informacja:



Skoro wiemy już że edytor ten został dostarczony przez plugin WST.JSDT wgrywamy go do naszego workspace. W tym celu wykorzystujemy kreator:

Plug-in Development|Plug-ins and Fragments|Binary Project with linked content|filtr *wst.jstd i ściągamy podejrzane projekty:

org.eclipse.wst.jsdt.core
org.eclipse.wst.jsdt.core.ui


Praktycznie od razu zauważamy pakiet formatter a w nim klasę w której znajduje się identyczny kod:

org.eclipse.wst.jsdt.core.formatter.CodeFormatterApplication

Wywołanie mechanizmów formatujących JSDT wymagać będzie od nas zaledwie zmiany dwóch importów z JDT na JSDT oraz identyfikatora określającego formatowaną zawartość. Postępując z wzorcem małpki kopiujemy oryginalną zawartość klasy JavaBeautifer do nowej klasy o nazwie JavaScriptBeautifier. Następnie modyfikujemy importy:

//import org.eclipse.jdt.core.ToolFactory;
//import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.wst.jsdt.core.ToolFactory;
import org.eclipse.wst.jsdt.core.formatter.CodeFormatter;


sprawdzane rozszerzenie pliku oraz identyfikator:

//getCodeFormatter().format(CodeFormatter.K_COMPILATION_UNIT,..
getCodeFormatter().format(CodeFormatter.K_JAVASCRIPT_UNIT,...


Klasa upiększająca kod JavaScript jest gotowa. Ostatnim elementem jest ustalenie konfiguracji w jaki sposób kod powinien się formatować. W tym celu korzystając z kreatora tworzymy właściwy dla naszych projektów sposób formatowania (najlepiej zwiększyć długość linii z 80 do 140...160 co jest moim zdaniem optymalne dla kodu generowanego)



Ustawienia te zostaną zapisane w pliku:
[workspace].metadata\.plugins\org.eclipse.core.runtime\.settings\ org.eclipse.wst.jsdt.core.prefs

Kopiujemy plik konfiguracyjny do naszego projektu w którym wykorzystujemy nasz formater i gotowe. Całość zabrała nam zaledwie kilka minut (napisanie tego tutoriala trochę więcej).

Mam nadzieję że komuś taka klasa się przyda. W czasach absolutnej dominacji aplikacji webowych, technologii Ajax, przeglądarki Google Chrome etc. coraz częściej generujemy kod JavaScript a nic tak nie cieszy jak kod czytelny i dobrze sformatowany :)