@@ -125,6 +125,94 @@ var writeTsDecls = function(apiData, path) {
125125 return name . replace ( / [ \[ \] ] / g, '' ) ;
126126 }
127127
128+ /**
129+ * Given a function, returns a function signature.
130+ */
131+ function getFunctionSignature ( name , fcn , params , isStatic ) {
132+ var fcnSig = isStatic ? 'public static' : 'public' ;
133+ fcnSig += " " + name + "(" +
134+ params . map ( function ( param ) {
135+ var paramName = fixIdentifier ( param . name ) ;
136+ // Make each param type a union type if multiple types.
137+ return paramName + ( param . optional ? "?" : "" ) + ": " + ( param . types . map ( function ( type ) { return getType ( type ) ; } ) . join ( " | " ) ) ;
138+ } ) . join ( ', ' ) + "): " ;
139+ var returnType = fcn . return ? getType ( fcn . return . type ) : "void" ;
140+ if ( fcn . isAsync ) {
141+ returnType = "PromiseLike<" + returnType + ">" ;
142+ }
143+ return fcnSig + returnType + ";"
144+ }
145+
146+ /**
147+ * Returns an array of parameter permutations to a function.
148+ */
149+ function getParamPermutations ( params ) {
150+ // Figure out which parameters are optional.
151+ var optionalParams = [ ]
152+ var nonOptionalAfterOptional = false ;
153+ var i ;
154+ for ( i = 0 ; i < params . length ; i ++ ) {
155+ if ( params [ i ] . optional ) {
156+ optionalParams . push ( i ) ;
157+ } else if ( optionalParams . length > 0 ) {
158+ nonOptionalAfterOptional = true ;
159+ }
160+ }
161+
162+ // If no non-optional functions follow optional functions,
163+ // we only need one function signature [common case].
164+ if ( ! nonOptionalAfterOptional ) {
165+ return [ params ] ;
166+ } else {
167+ var rv = [ ] ;
168+
169+ // Only toggle the ones in the middle. Ignore those at the
170+ // end -- they are benign.
171+ for ( i = params . length - 1 ; i >= 0 ; i -- ) {
172+ if ( optionalParams [ optionalParams . length - 1 ] === i ) {
173+ optionalParams . pop ( ) ;
174+ } else {
175+ break ;
176+ }
177+ }
178+
179+ var numOptionalParams = optionalParams . length ;
180+ var state = new Array ( numOptionalParams ) ;
181+ for ( i = 0 ; i < numOptionalParams ; i ++ ) {
182+ state [ i ] = 0 ;
183+ }
184+ outer:
185+ while ( true ) {
186+ // 'Clone' the params object.
187+ var paramVariant = JSON . parse ( JSON . stringify ( params ) ) ;
188+ // Remove 'disabled' optional params, from r2l to avoid messing with
189+ // array indices.
190+ for ( i = numOptionalParams - 1 ; i >= 0 ; i -- ) {
191+ var optionalIndex = optionalParams [ i ] ;
192+ if ( state [ i ] ) {
193+ paramVariant . splice ( optionalIndex , 1 ) ;
194+ } else {
195+ paramVariant [ optionalIndex ] . optional = false ;
196+ }
197+ }
198+ rv . push ( paramVariant ) ;
199+
200+ // Add '1' to 'state', from L2R.
201+ var digit = 0 ;
202+ while ( state [ digit ] === 1 ) {
203+ if ( ( digit + 1 ) < numOptionalParams ) {
204+ state [ digit ] = 0 ;
205+ digit ++ ;
206+ } else {
207+ break outer;
208+ }
209+ }
210+ state [ digit ] = 1 ;
211+ }
212+ return rv . reverse ( ) ;
213+ }
214+ }
215+
128216 /**
129217 * Converts a function in JSON format into a TypeScript function
130218 * declaration.
@@ -137,33 +225,26 @@ var writeTsDecls = function(apiData, path) {
137225 if ( fcn . description !== "" ) {
138226 jsDoc += fcn . description + "\n" ;
139227 }
140- var fcnSig = isStatic ? 'public static' : 'public' ;
141- fcnSig += " " + name + "(" +
142- fcn . params . map ( function ( param ) {
143- var paramName = fixIdentifier ( param . name ) ;
144- jsDoc += "\n@param " + paramName + " " ;
145- // Apparently param.description can be null, so check that it's not before looking at the contents!
146- if ( param . description && param . description . trim ( ) !== "" ) {
147- // Indent secondary lines of the description.
148- jsDoc += param . description . replace ( / \n / g, '\n ' ) + "\n" ;
149- }
150- // Make each param type a union type if multiple types.
151- return paramName + ( param . optional ? "?" : "" ) + ": " + ( param . types . map ( function ( type ) { return getType ( type ) ; } ) . join ( " | " ) ) ;
152- } ) . join ( ', ' ) + "): " ;
153228
154- var returnType = fcn . return ? getType ( fcn . return . type ) : "void" ;
155- if ( fcn . isAsync ) {
156- returnType = "PromiseLike<" + returnType + ">" ;
157- }
229+ var params = fcn . params ;
230+ params . map ( function ( param ) {
231+ var paramName = fixIdentifier ( param . name ) ;
232+ jsDoc += "\n@param " + paramName + " " ;
233+ // Apparently param.description can be null, so check that it's not before looking at the contents!
234+ if ( param . description && param . description . trim ( ) !== "" ) {
235+ // Indent secondary lines of the description.
236+ jsDoc += param . description . replace ( / \n / g, '\n ' ) + "\n" ;
237+ }
238+ } ) ;
239+
158240 var fcnDesc = fcn . return ? fcn . return . description . replace ( / \n / g, '\n ' ) : '' ;
159241
160242 if ( fcnDesc . trim ( ) !== "" ) {
161243 jsDoc += "\n@return " + fcnDesc ;
162244 }
163245
164- fcnSig += returnType + ";"
165-
166- return textToJSDoc ( jsDoc ) + "\n" + fcnSig ;
246+ var paramPermutations = getParamPermutations ( fcn . params ) ;
247+ return textToJSDoc ( jsDoc ) + "\n" + paramPermutations . map ( function ( params ) { return getFunctionSignature ( name , fcn , params , isStatic ) ; } ) . join ( "\n" ) ;
167248 }
168249
169250 /**
0 commit comments