Helma Logo
main list history

jsdoc-toolkit_for_ng

jsdoc-toolkit für Helma-NG

Das jsdoc-toolkit kann aufgrund von JsDoc Kommentaren im JS Quellcode automatisch Dokumentation generieren. Es stellt sich die Frage ob und wie es für Helma-NG mit seinen speziellen Eigenschaften bzgl. namespacing/scoping verwendet werden kann. Es gibt 2 Anforderungen:

  1. Es soll ein Minimum an JsDoc Code verwendet werden müssen, i.e. die statische Code Analyse das jsdoc-toolkit soll maximal ausgenützt werden.
  2. Die Helma-NG eigenen Regeln was das namespacing/scoping betrifft sollten automatisch angewendet werden, i.e. sollen Funktionen/Attribute die in einem Modul global definiert sind zu members des module namespace werden.

Minimum an JsDoc Code

Ein wünschenswerter Zustand wäre der folgende, in dem nur ein Minimum an JsDoc Tags verwendet wird um die Eigenschaften des Codes zu beschreiben.

 /**
  * Globale Variable
  */
 var meinGlobal = 2;
 /** 
  * A utility class for composing strings. This is implemented
  * as a simple wrapper around a JavaScript array.
  * @class The Buffer class
  * @constructor
  */
 function Buffer() {
     
     /**
      * child buffer
      * @constructor
      * @class
      * @param {Object} name
      */
     this.ChildBuffer = function(name) {
       return name; 
     };
    
     var content = [];
     /**
      * reset
      */
     this.reset = function() {
         content = [];
         return this;
     }
  
     return this;
 }

Die statische Code Analyse funktioniert mit diesem Codestück so gut, dass ein Minimum (eben die vorhandenen) an JsDoc Tags verwendet werden kann. Der Prototyp Buffer wird erkannt und die 3 Symbole ChildBuffer (Prototyp), content (Attribut) und reset (Funktion) werden dem Symbol Buffer zugeordnet. Die globale Variable meinGlobal wird an _global_ angehängt.

Helma-NG namespaces/scopes

Nehmen wir an der oben angeführte Code befindet sich in einer Datei mit dem Pfad helma/buffer.js . Aufgrund der Eigenschaft von Helma-NG, dass jede Datei ein Modul ist und jedes Modul seinen eigenen globalen namespace hat müsste der Code als helma.buffer zugehörig gesehen werden. Also sollte aus Buffer helma.buffer.Buffer , aus Buffer.reset helma.buffer.Buffer.reset und aus _global_.meinGlobal helma.buffer.meinGlobal werden.

Dies kann beim Parsevorgang über die Pluginschnittstelle "onSymbol", die jedesmal wenn ein neues Symbol erzeugt wird, aufgerufen wird, bewerkstelligt werden. Es wird der Dateiname (inkl. Pfad) der geparseden Datei (in der sich das Symbol befindet) ausgelesen, daraus der Modulnamespace erzeugt und das Symbol modifiziert - das funktioniert auch.

Das beschädigt jedoch die statische Codeanalyse, die verwendet wird um Symbolnamen und Beziehungen (zu welcher Klasse gehört die Funktion etc.) automatisch zu setzen (damit z.B. nicht die Funktion reset mit @name helma.buffer.Buffer.reset annotiert werden muss):

  1. Der Parser fügt das Symbol Buffer hinzu, wir modifizieren es zu helma.buffer.Buffer .
  2. Der Parser fügt das Symbol reset hinzu, wir wollen es nicht modifizieren da wir auf die statische Code Analyse bauen um das Symbol automatisch als member von helma.buffer.Buffer zu identifizieren.
  3. Der Parser führt die statische Code Analyse aus. Diese arbeitet mit Informationen, die während dem Parsevorgang aus dem Code gesammelt werden. Da der Code nicht mit den Helma-NG spezifischen Informationen über namespaces/scopes angereichert wurde sucht er das Symbol reset als member des Symbols Buffer. Und scheitert dabei, das Symbol reset wird fälschlicherweise _global_ zugeordnet.

Das jsdoc-toolkit arbeitet also in folgender Reihenfolge:

  1. Code parsen und Symbole erzeugen (Plugin Schnittstellen).
  2. Mit statischer Code Analyse die gefundenen Symbole mit Informationen anreichern.
  3. Den erstellten AST formatieren und ausgeben (eigene Templates sind möglich).

Eine andere Schwierigkeit ist das Auftreten von namensidenten Funktionen in unterschiedlichen Modulen. In Helma-NG sind diese automatisch in separaten namespaces angesiedelt und behindern sich nicht. Für das jsdoc-toolkit treten diese jedoch beide im globalen namespace auf und überschreiben sich daher. Dies kann aufgrund der Ausführungsreihenfolge und der vorhandenen Plugin Schnittstellen nicht verhindert werden: Der Parser sieht alle namensindenten Funktionen und überschreibt sie. An dieser Stelle gibt es noch keine Informationen aus der statischen Codeanalyse über ihre Zugehörigkeit, daher kann ihr namespace auch noch nicht auf den des Modules korrigiert werden. Ansonsten wurde die später durchlaufende statische Codeanalyse keine Zuordnung mehr zu Klassen etc. vornehmen können.

Fazit

Das jsdoc-toolkit (und vor allem seine statische Code Analyse) ist für "klassische" JavaScript Laufzeit Umgebungen konzipiert, wo es seine Aufgabe güt erfüllt und den Entwicklern viel Arbeit abnehmen kann. Es kann in unmodifizierter Form durchaus verwendet werden um Helma-NG Code zu dokumentieren, allerdings müsste dafür jedes Symbol (das in der Doku auftauchen soll) exakt mit @name (und bei Bedarf noch anderen JsDoc Tags) dokumentiert werden was auf Dauer eher aufwendig ist. Eine Modifikation, damit der Parser als auch die statische Code Analyse mit Helma-NG Eigenheiten zusammenarbeiten ist nur mit einem Plugin/Template nicht möglich. Es müsste entweder die Code Analyse über einen Patch mit einer Plugin Schnittstelle versehen werden (für die dann ein Plugin entwickelt wird) oder gleich die gesamte Parser/Code Analyse Kombination gepatched werden.

Falls Rhino in der nächsten version 1.7R3 tatsächlich wie in der Mailingliste unter http://groups.google.com/group/mozilla.dev.tech.js-engine.rhino/browse_thread/thread/8be8f832256531dd/de4e672e524b436c?lnk=gst&q=jsdoc#de4e672e524b436c erwähnt die gefundene JsDoc an den geparseden Abstract Syntax Tree anhängt (anhängen kann) und diese über die AST API auslesbar sind, könnte dies eine mächtige Alternative zum jsdoc-toolkit (und seiner statischen Code Analyse) sein.