22* Add comments in a TypeScript definition file
33*/
44'use strict' ;
5- var ts = require ( 'typescript-services' ) ;
5+
6+ var ts = require ( 'typescript' ) ;
67var fs = require ( 'fs' ) ;
78
89var TypeScriptDocGenerator = ( function ( ) {
910 function TypeScriptDocGenerator ( tsDefFileName , jsdocJsonFileName ) {
10- this . pos = 0 ;
1111 this . nbCharsAdded = 0 ;
12- this . jsonDocsFileName = jsdocJsonFileName ;
13- this . tsDefFileName = tsDefFileName ;
14- this . jsonDocsFileContent = fs . readFileSync ( this . jsonDocsFileName , 'utf-8' ) ;
15- this . docs = JSON . parse ( this . jsonDocsFileContent ) ;
16- this . tsDefFileContent = fs . readFileSync ( this . tsDefFileName , 'utf-8' ) ;
17- this . tree = ts . Parser . parse ( '' , ts . SimpleText . fromString ( this . tsDefFileContent ) , true , new ts . ParseOptions ( ts . LanguageVersion . EcmaScript5 , true ) ) ;
18- this . sourceUnit = this . tree . sourceUnit ( ) ;
19- this . lineMap = this . tree . lineMap ( ) ;
12+ this . tsDefFileName = ts . normalizePath ( tsDefFileName ) ;
13+ this . tsDefFileContent = fs . readFileSync ( this . tsDefFileName , 'utf-8' ) . toString ( ) ;
14+ this . delintNodeFunction = this . delintNode . bind ( this ) ;
15+ var jsonDocsFileContent = fs . readFileSync ( jsdocJsonFileName , 'utf-8' ) . toString ( ) ;
16+ this . docs = JSON . parse ( jsonDocsFileContent ) ;
17+ var options = { target : ts . ScriptTarget . ES5 , module : ts . ModuleKind . AMD } ;
18+ var host = ts . createCompilerHost ( options ) ;
19+ var program = ts . createProgram ( [ this . tsDefFileName ] , options , host ) ;
20+ this . sourceFile = program . getSourceFile ( this . tsDefFileName ) ;
2021 }
21- TypeScriptDocGenerator . prototype . cleanEndLine = function ( str ) {
22- return str . replace ( new RegExp ( '[' + "\r\n" + ']' , 'g' ) , "\n" ) . replace ( new RegExp ( '[' + "\r" + ']' , 'g' ) , "\n" ) ;
23- } ;
24- TypeScriptDocGenerator . prototype . completePrefix = function ( oldPrefix , appendedPrefix ) {
25- if ( oldPrefix === "" ) {
26- return appendedPrefix ;
27- }
28- else {
29- return oldPrefix + "." + appendedPrefix ;
30- }
22+ TypeScriptDocGenerator . prototype . getTsDefCommentedFileContent = function ( ) {
23+ this . scan ( ) ;
24+ return this . tsDefFileContent ;
3125 } ;
3226 TypeScriptDocGenerator . prototype . repeatSpaces = function ( nb ) {
3327 var res = "" ;
@@ -36,30 +30,16 @@ var TypeScriptDocGenerator = (function () {
3630 }
3731 return res ;
3832 } ;
39- TypeScriptDocGenerator . prototype . leadingWidth = function ( nodeOrToken ) {
40- if ( nodeOrToken != null ) {
41- for ( var i = 0 ; i < nodeOrToken . childCount ( ) ; i ++ ) {
42- var ltw = nodeOrToken . childAt ( i ) . leadingTriviaWidth ( ) ;
43- if ( ltw > 0 ) {
44- return ltw ;
45- }
46- }
47- }
48- return 0 ;
49- } ;
50- TypeScriptDocGenerator . prototype . extractPropertyName = function ( pn ) {
51- return pn . withLeadingTrivia ( ) . text ( ) . trim ( ) ;
52- } ;
5333 TypeScriptDocGenerator . prototype . insertComment = function ( commentLines , position ) {
5434 if ( ( commentLines != null ) && ( commentLines . length > 0 ) ) {
5535 var nbChars = 0 ;
5636 for ( var i = 0 ; i < commentLines . length ; i ++ ) {
5737 nbChars += commentLines [ i ] . trim ( ) . length ;
5838 }
5939 if ( nbChars > 0 ) {
60- var lc = this . lineMap . getLineAndCharacterFromPosition ( position ) ;
61- var nbSpaces = lc . character ( ) ;
62- var startLinePosition = this . lineMap . getLineStartPosition ( lc . line ( ) ) ;
40+ var lc = this . sourceFile . getLineAndCharacterFromPosition ( position ) ;
41+ var nbSpaces = lc . character - 1 ;
42+ var startLinePosition = this . sourceFile . getLineStarts ( ) [ lc . line - 1 ] ;
6343 var comment = "\r\n" + this . repeatSpaces ( nbSpaces ) + "/**\r\n" ;
6444 for ( var j = 0 ; j < commentLines . length ; j ++ ) {
6545 comment += this . repeatSpaces ( nbSpaces ) + "* " + commentLines [ j ] . trimRight ( ) + "\r\n" ;
@@ -70,6 +50,9 @@ var TypeScriptDocGenerator = (function () {
7050 }
7151 }
7252 } ;
53+ TypeScriptDocGenerator . prototype . cleanEndLine = function ( str ) {
54+ return str . replace ( new RegExp ( '[' + "\r\n" + ']' , 'g' ) , "\n" ) . replace ( new RegExp ( '[' + "\r" + ']' , 'g' ) , "\n" ) ;
55+ } ;
7356 TypeScriptDocGenerator . prototype . findClass = function ( className ) {
7457 if ( className . indexOf ( "p2." ) === 0 ) {
7558 className = className . replace ( "p2." , "Phaser.Physics.P2." ) ;
@@ -79,25 +62,6 @@ var TypeScriptDocGenerator = (function () {
7962 } ) ;
8063 return elements [ 0 ] ;
8164 } ;
82- TypeScriptDocGenerator . prototype . generateMemberComments = function ( className , memberName ) {
83- var c = this . findClass ( className ) ;
84- if ( c != null ) {
85- for ( var i = 0 ; i < c . members . length ; i ++ ) {
86- if ( c . members [ i ] . name === memberName ) {
87- var m = c . members [ i ] ;
88- var comments = [ ] ;
89- comments = comments . concat ( this . cleanEndLine ( m . description ) . split ( "\n" ) ) ;
90- if ( ( m . default != null ) && ( m . default !== "" ) ) {
91- comments . push ( "Default: " + m . default ) ;
92- }
93- return comments ;
94- }
95- }
96- }
97- else {
98- return null ;
99- }
100- } ;
10165 TypeScriptDocGenerator . prototype . generateClassComments = function ( className ) {
10266 var c = this . findClass ( className ) ;
10367 if ( c != null ) {
@@ -109,35 +73,20 @@ var TypeScriptDocGenerator = (function () {
10973 return null ;
11074 }
11175 } ;
112- TypeScriptDocGenerator . prototype . generateConstructorComments = function ( className ) {
76+ TypeScriptDocGenerator . prototype . generateMemberComments = function ( className , memberName ) {
11377 var c = this . findClass ( className ) ;
11478 if ( c != null ) {
115- var con = c . constructor ;
116- var comments = [ ] ;
117- comments = comments . concat ( this . cleanEndLine ( con . description ) . split ( "\n" ) ) ;
118- if ( con . parameters . length > 0 ) {
119- comments . push ( "" ) ;
120- }
121- for ( var j = 0 ; j < con . parameters . length ; j ++ ) {
122- var p = con . parameters [ j ] ;
123- if ( p . type === "*" ) {
124- p . name = "args" ;
125- }
126- var def = "" ;
127- if ( ( p . default != null ) && ( p . default !== "" ) ) {
128- def = " - Default: " + p . default ;
129- }
130- var paramComments = this . cleanEndLine ( p . description ) . split ( "\n" ) ;
131- for ( var k = 0 ; k < paramComments . length ; k ++ ) {
132- if ( k === 0 ) {
133- comments . push ( "@param " + p . name + " " + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
134- }
135- else {
136- comments . push ( this . repeatSpaces ( ( "@param " + p . name + " " ) . length ) + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
79+ for ( var i = 0 ; i < c . members . length ; i ++ ) {
80+ if ( c . members [ i ] . name === memberName ) {
81+ var m = c . members [ i ] ;
82+ var comments = [ ] ;
83+ comments = comments . concat ( this . cleanEndLine ( m . description ) . split ( "\n" ) ) ;
84+ if ( ( m . default != null ) && ( m . default !== "" ) ) {
85+ comments . push ( "Default: " + m . default ) ;
13786 }
87+ return comments ;
13888 }
13989 }
140- return comments ;
14190 }
14291 else {
14392 return null ;
@@ -163,29 +112,23 @@ var TypeScriptDocGenerator = (function () {
163112 if ( ( p . default != null ) && ( p . default !== "" ) ) {
164113 def = " - Default: " + p . default ;
165114 }
166-
167115 var paramComments = this . cleanEndLine ( p . description ) . split ( "\n" ) ;
168- for ( var k = 0 ; k < paramComments . length ; k ++ )
169- {
170- if ( k === 0 )
171- {
116+ for ( var k = 0 ; k < paramComments . length ; k ++ ) {
117+ if ( k === 0 ) {
172118 comments . push ( "@param " + p . name + " " + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
173119 }
174- else
175- {
120+ else {
176121 comments . push ( this . repeatSpaces ( ( "@param " + p . name + " " ) . length ) + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
177122 }
178123 }
179-
180124 }
181125 if ( ( f . returns != null ) && ( f . returns . description . trim ( ) . length > 0 ) ) {
182126 var returnComments = this . cleanEndLine ( f . returns . description ) . split ( "\n" ) ;
183127 for ( var l = 0 ; l < returnComments . length ; l ++ ) {
184128 if ( l === 0 ) {
185129 comments . push ( "@return " + returnComments [ l ] . trim ( ) ) ;
186130 }
187- else
188- {
131+ else {
189132 comments . push ( this . repeatSpaces ( ( "@return " ) . length ) + returnComments [ l ] . trim ( ) ) ;
190133 }
191134 }
@@ -198,69 +141,79 @@ var TypeScriptDocGenerator = (function () {
198141 return null ;
199142 }
200143 } ;
201- TypeScriptDocGenerator . prototype . scanClass = function ( c , fullName , classPos ) {
202- for ( var i = 0 ; i < c . childCount ( ) ; i ++ ) {
203- var elem = c . childAt ( i ) ;
204- if ( elem != null ) {
205- switch ( elem . kind ( ) ) {
206- case ts . SyntaxKind . List :
207- classPos = this . scanClass ( elem , fullName , classPos ) ;
208- break ;
209- case ts . SyntaxKind . ConstructorDeclaration :
210- this . insertComment ( this . generateConstructorComments ( fullName ) , classPos + this . leadingWidth ( elem ) ) ;
211- break ;
212- case ts . SyntaxKind . MemberVariableDeclaration :
213- this . insertComment ( this . generateMemberComments ( fullName , this . extractPropertyName ( elem . variableDeclarator . propertyName ) ) , classPos + this . leadingWidth ( elem ) ) ;
214- break ;
215- case ts . SyntaxKind . MemberFunctionDeclaration :
216- this . insertComment ( this . generateFunctionComments ( fullName , this . extractPropertyName ( elem . propertyName ) ) , classPos + this . leadingWidth ( elem ) ) ;
217- break ;
144+ TypeScriptDocGenerator . prototype . generateConstructorComments = function ( className ) {
145+ var c = this . findClass ( className ) ;
146+ if ( c != null ) {
147+ var con = c . constructor ;
148+ var comments = [ ] ;
149+ comments = comments . concat ( this . cleanEndLine ( con . description ) . split ( "\n" ) ) ;
150+ if ( con . parameters . length > 0 ) {
151+ comments . push ( "" ) ;
152+ }
153+ for ( var j = 0 ; j < con . parameters . length ; j ++ ) {
154+ var p = con . parameters [ j ] ;
155+ if ( p . type === "*" ) {
156+ p . name = "args" ;
218157 }
219- if ( elem . kind ( ) !== ts . SyntaxKind . List ) {
220- classPos += elem . fullWidth ( ) ;
158+ var def = "" ;
159+ if ( ( p . default != null ) && ( p . default !== "" ) ) {
160+ def = " - Default: " + p . default ;
221161 }
222- }
223- }
224- return classPos ;
225- } ;
226- TypeScriptDocGenerator . prototype . scan = function ( elem , prefix ) {
227- if ( elem != null ) {
228- switch ( elem . kind ( ) ) {
229- case ts . SyntaxKind . List :
230- for ( var k = 0 ; k < elem . childCount ( ) ; k ++ ) {
231- this . scan ( elem . childAt ( k ) , prefix ) ;
162+ var paramComments = this . cleanEndLine ( p . description ) . split ( "\n" ) ;
163+ for ( var k = 0 ; k < paramComments . length ; k ++ ) {
164+ if ( k === 0 ) {
165+ comments . push ( "@param " + p . name + " " + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
232166 }
233- break ;
234- case ts . SyntaxKind . InterfaceDeclaration :
235- break ;
236- case ts . SyntaxKind . ClassDeclaration :
237- var fullClassName = this . completePrefix ( prefix , elem . identifier . fullText ( ) . trim ( ) ) ;
238- this . insertComment ( this . generateClassComments ( fullClassName ) , this . pos + this . leadingWidth ( elem ) ) ;
239- this . scanClass ( elem , fullClassName , this . pos ) ;
240- break ;
241- case ts . SyntaxKind . ModuleDeclaration :
242- for ( var j = 0 ; j < elem . childCount ( ) ; j ++ ) {
243- this . scan ( elem . childAt ( j ) , this . completePrefix ( prefix , elem . name . fullText ( ) . trim ( ) ) ) ;
167+ else {
168+ comments . push ( this . repeatSpaces ( ( "@param " + p . name + " " ) . length ) + paramComments [ k ] . trim ( ) + ( ( k === paramComments . length - 1 ) ? def : "" ) ) ;
244169 }
245- break ;
246- }
247- if ( ( elem . kind ( ) !== ts . SyntaxKind . List ) && ( elem . kind ( ) !== ts . SyntaxKind . ModuleDeclaration ) ) {
248- this . pos += elem . fullWidth ( ) ;
170+ }
249171 }
172+ return comments ;
173+ }
174+ else {
175+ return null ;
250176 }
251177 } ;
252- TypeScriptDocGenerator . prototype . getTsDefCommentedFileContent = function ( ) {
253- for ( var i = 0 ; i < this . sourceUnit . childCount ( ) ; i ++ ) {
254- this . scan ( this . sourceUnit . childAt ( i ) , "" ) ;
178+ TypeScriptDocGenerator . prototype . scan = function ( ) {
179+ this . delintNode ( this . sourceFile ) ;
180+ } ;
181+ TypeScriptDocGenerator . prototype . getClassName = function ( node ) {
182+ var fullName = '' ;
183+ if ( node . kind === ts . SyntaxKind . ClassDeclaration ) {
184+ fullName = node . name . getText ( ) ;
185+ }
186+ var parent = node . parent ;
187+ while ( parent != null ) {
188+ if ( parent . kind === ts . SyntaxKind . ModuleDeclaration || parent . kind === ts . SyntaxKind . ClassDeclaration ) {
189+ fullName = parent . name . getText ( ) + ( ( fullName != '' ) ? "." + fullName : fullName ) ;
190+ }
191+ parent = parent . parent ;
255192 }
256- return this . tsDefFileContent ;
193+ return fullName ;
194+ } ;
195+ TypeScriptDocGenerator . prototype . delintNode = function ( node ) {
196+ switch ( node . kind ) {
197+ case ts . SyntaxKind . Constructor :
198+ this . insertComment ( this . generateConstructorComments ( this . getClassName ( node ) ) , node . getStart ( ) ) ;
199+ break ;
200+ case ts . SyntaxKind . ClassDeclaration :
201+ this . insertComment ( this . generateClassComments ( this . getClassName ( node ) ) , node . getStart ( ) ) ;
202+ break ;
203+ case ts . SyntaxKind . Property :
204+ this . insertComment ( this . generateMemberComments ( this . getClassName ( node ) , node . name . getText ( ) ) , node . getStart ( ) ) ;
205+ break ;
206+ case ts . SyntaxKind . Method :
207+ this . insertComment ( this . generateFunctionComments ( this . getClassName ( node ) , node . name . getText ( ) ) , node . getStart ( ) ) ;
208+ break ;
209+ }
210+ ts . forEachChild ( node , this . delintNodeFunction ) ;
257211 } ;
258212 return TypeScriptDocGenerator ;
259213} ) ( ) ;
260-
261214module . exports = function ( grunt ) {
262215 grunt . registerMultiTask ( 'buildtsdoc' , 'Generate a TypeScript def with comments' , function ( ) {
263216 var tsdg = new TypeScriptDocGenerator ( this . data . tsDefFileName , this . data . jsdocJsonFileName ) ;
264217 fs . writeFileSync ( this . data . dest , tsdg . getTsDefCommentedFileContent ( ) , 'utf8' ) ;
265218 } ) ;
266- } ;
219+ } ;
0 commit comments