2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Copyright  ( c )  Microsoft  Corporation . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Licensed  under  the  Apache  License ,  Version  2.0  ( the  "License" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  you  may  not  use  this  file  except  in  compliance  with  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  You  may  obtain  a  copy  of  the  License  at 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  http : //www.apache.org/licenses/LICENSE-2.0
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Unless  required  by  applicable  law  or  agreed  to  in  writing ,  software 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  distributed  under  the  License  is  distributed  on  an  "AS IS"  BASIS , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  WITHOUT  WARRANTIES  OR  CONDITIONS  OF  ANY  KIND ,  either  express  or  implied . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  the  License  for  the  specific  language  governing  permissions  and 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  limitations  under  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// @ts-check
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  path  =  require ( 'path' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  Documentation  =  require ( './documentation' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  XmlDoc  =  require ( './xmlDocumentation' )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  PROJECT _DIR  =  path . join ( _ _dirname ,  '..' ,  '..' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  fs  =  require ( 'fs' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  {  parseApi  }  =  require ( './api_parser' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  {  Type  }  =  require ( './documentation' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  {  args  }  =  require ( 'commander' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  {  EOL  }  =  require ( 'os' ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  maxDocumentationColumnWidth  =  80 ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/** @type {Map<string, Documentation.Type>} */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  additionalTypes  =  new  Map ( ) ;  // this will hold types that we discover, because of .NET specifics, like results
  
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/** @type {Map<string, string>} */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  documentedResults  =  new  Map ( ) ;  // will hold documentation for new types
  
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/** @type {Map<string, string[]>} */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  enumTypes  =  new  Map ( ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								let  documentation ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/** @type {Map<string, string>} */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								let  classNameMap ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  typesDir  =  process . argv [ 2 ]  ||  '../generate_types/csharp/' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  checkAndMakeDir  =  ( path )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! fs . existsSync ( path ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      fs . mkdirSync ( path ,  {  recursive :  true  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  modelsDir  =  path . join ( typesDir ,  "models" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  enumsDir  =  path . join ( typesDir ,  "enums" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  checkAndMakeDir ( typesDir ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  checkAndMakeDir ( modelsDir ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  checkAndMakeDir ( enumsDir ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  documentation  =  parseApi ( path . join ( PROJECT _DIR ,  'docs' ,  'src' ,  'api' ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  documentation . filterForLanguage ( 'csharp' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  documentation . setLinkRenderer ( item  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( item . clazz ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` <see cref=" ${ translateMemberName ( "interface" ,  item . clazz . name ,  null ) } "/> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( item . member ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` <see cref=" ${ translateMemberName ( "interface" ,  item . member . clazz . name ,  null ) } . ${ translateMemberName ( item . member . kind ,  item . member . name ,  item . member ) } "/> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( item . option ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` <paramref name=" ${ item . option } "/> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( item . param ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` <paramref name=" ${ item . param } "/> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  new  Error ( 'Unknown link format.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // get the template for a class
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  template  =  fs . readFileSync ( "./templates/interface.cs" ,  'utf-8' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    . replace ( '[PW_TOOL_VERSION]' ,  ` ${ _ _filename . substring ( path . join ( _ _dirname ,  '..' ,  '..' ) . length ) . split ( path . sep ) . join ( path . posix . sep ) } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // we have some "predefined" types, like the mixed state enum, that we can map in advance
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  enumTypes . set ( "MixedState" ,  [ "On" ,  "Off" ,  "Mixed" ] ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // map the name to a C# friendly one (we prepend an I to denote an interface)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap  =  new  Map ( documentation . classesArray . map ( x  =>  [ x . name ,  translateMemberName ( 'interface' ,  x . name ,  null ) ] ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // map some types that we know of
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'Error' ,  'Exception' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'TimeoutError' ,  'TimeoutException' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'EvaluationArgument' ,  'object' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'boolean' ,  'bool' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'Serializable' ,  'T' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'any' ,  'object' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'Buffer' ,  'byte[]' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'path' ,  'string' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'URL' ,  'string' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  classNameMap . set ( 'RegExp' ,  'Regex' ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  // this are types that we don't explicility render even if we get the specs
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  ignoredTypes  =  [ 'TimeoutException' ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  writeFile  =  ( name ,  out ,  folder )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  content  =  template . replace ( '[CONTENT]' ,  out . join ( ` ${ EOL } \t ` ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-03 01:29:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    fs . writeFileSync ( ` ${ path . join ( folder ,  name ) } .generated.cs ` ,  content ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  / * * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  kind  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  name  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { Documentation . MarkdownNode [ ] }  spec 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { function ( string [ ] ) :  void }  callback  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  folder 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  extendsName 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  innerRenderElement  =  ( kind ,  name ,  spec ,  callback ,  folder  =  typesDir ,  extendsName  =  null )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  out  =  [ ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    console . log ( ` Generating  ${ name } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( spec ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      out . push ( ... XmlDoc . renderXmlDoc ( spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  ownDocumentation  =  documentedResults . get ( name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ownDocumentation )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        out . push ( '/// <summary>' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        out . push ( ` ///  ${ ownDocumentation } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        out . push ( '/// </summary>' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( extendsName  ===  'IEventEmitter' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      extendsName  =  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    out . push ( ` public  ${ kind }   ${ name } ${ extendsName  ?  `  :  ${ extendsName } `  :  '' } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    out . push ( '{' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    callback ( out ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // we want to separate the items with a space and this is nicer, than holding 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // an index in each iterator down the line
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  lastLine  =  out . pop ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( lastLine  !==  '' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      out . push ( lastLine ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    out . push ( '}' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    writeFile ( name ,  out ,  folder ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  for  ( const  element  of  documentation . classesArray )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  name  =  classNameMap . get ( element . name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ignoredTypes . includes ( name ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    innerRenderElement ( 'partial interface' ,  name ,  element . spec ,  ( out )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  ( const  member  of  element . membersArray )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        renderMember ( member ,  element ,  out ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ,  typesDir ,  translateMemberName ( 'interface' ,  element . extends ,  null ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  additionalTypes . forEach ( ( type ,  name )  => 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    innerRenderElement ( 'partial class' ,  name ,  null ,  ( out )  =>  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      // TODO: consider how this could be merged with the `translateType` check
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( type . union 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        &&  type . union [ 0 ] . name  ===  'null' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        &&  type . union . length  ==  2 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        type  =  type . union [ 1 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( type . name  ===  'Array' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( 'Array at this stage is unexpected.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  if  ( type . properties )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( const  member  of  type . properties )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          let  fakeType  =  new  Type ( name ,  null ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          renderMember ( member ,  fakeType ,  out ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        console . log ( type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( ` Not sure what to do in this case. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ,  modelsDir ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  enumTypes . forEach ( ( values ,  name )  => 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    innerRenderElement ( 'enum' ,  name ,  null ,  ( out )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      out . push ( '\tUndefined = 0,' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      values . forEach ( ( v ,  i )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // strip out the quotes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        v  =  v . replace ( /[\"]/g ,  ` ` ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        let  escapedName  =  v . replace ( /[-]/g ,  ' ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . split ( ' ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . map ( word  =>  word [ 0 ] . toUpperCase ( )  +  word . substring ( 1 ) ) . join ( '' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        out . push ( ` \t [EnumMember(Value = " ${ v } ")] ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        out . push ( ` \t ${ escapedName } , ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ,  enumsDir ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { string }  memberKind   
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { string }  name  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Member }  member  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  translateMemberName ( memberKind ,  name ,  member  =  null )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ! name )  return  name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // we strip it for special chars, like @ because we might get called back with it in some special cases
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // like, when generating classes inside methods for params
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  name  =  name . replace ( /[@-]/g ,  '' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( memberKind  ===  'argument' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( [ 'params' ,  'event' ] . includes ( name ) )  {  // just in case we want to add others
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` @ ${ name } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  // check if there's an alias in the docs, in which case
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // we return that, otherwise, we apply our dotnet magic to it
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( member )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( member . alias  !==  name )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  member . alias ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // we sanitize some common abbreviations to ensure consistency
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  name  =  name . replace ( /(HTTP[S]?)/g ,  ( m ,  g )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  g [ 0 ] . toUpperCase ( )  +  g . substring ( 1 ) . toLowerCase ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  let  assumedName  =  name . charAt ( 0 ) . toUpperCase ( )  +  name . substring ( 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  switch  ( memberKind )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    case  "interface" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // apply name mapping if the map exists
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  mappedName  =  classNameMap  ?  classNameMap . get ( assumedName )  :  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( mappedName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  mappedName ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` I ${ assumedName } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    case  "method" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( member  &&  member . async ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  ` ${ assumedName } Async ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  assumedName ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    case  "event" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` ${ assumedName } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    case  "enum" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` ${ assumedName } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` ${ assumedName } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Member }  member  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Class | Documentation . Type }  parent  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { string [ ] }  out 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  renderMember ( member ,  parent ,  out )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  output  =  line  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( typeof  ( line )  ===  'string' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      out . push ( ` \t ${ line } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      out . push ( ... line . map ( x  =>  ` \t ${ x } ` ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  name  =  translateMemberName ( member . kind ,  member . name ,  member ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( member . kind  ===  'method' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    renderMethod ( member ,  parent ,  output ,  name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  type  =  translateType ( member . type ,  parent ,  t  =>  generateNameDefault ( member ,  name ,  t ,  parent ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( member . kind  ===  'event' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! member . type ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( ` No Event Type for  ${ name }  in  ${ parent . name } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( member . spec ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        output ( XmlDoc . renderXmlDoc ( member . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      if  ( parent  &&  ( classNameMap . get ( parent . name )  ===  type ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        output ( ` event EventHandler  ${ name } ; ` ) ;  // event sender will be the type, so we're fine to ignore
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        output ( ` event EventHandler< ${ type } >  ${ name } ; ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( member . kind  ===  'property' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( member . spec ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        output ( XmlDoc . renderXmlDoc ( member . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  propertyOrigin  =  member . name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( member . type . expression  ===  '[string]|[float]' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        propertyOrigin  =  ` ${ member . name } String ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` [JsonPropertyName(" ${ propertyOrigin } ")] ` ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( parent  &&  member  &&  member . name  ===  'children' )  {   // this is a special hack for Accessibility
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        console . warn ( ` children property found in  ${ parent . name } , assuming array. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        type  =  ` IEnumerable< ${ parent . name } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` public  ${ type }   ${ name }  { get; set; } ` ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  new  Error ( ` Problem rendering a member:  ${ type }  -  ${ name }  ( ${ member . kind } ) ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // we're separating each entry and removing the final blank line when rendering
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  out . push ( '' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Member }  member  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { string }  name  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Type }  t  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { * }  parent  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  generateNameDefault ( member ,  name ,  t ,  parent )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ! t . properties 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  ! t . templates 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  ! t . union 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  t . expression  ===  '[Object]' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  'object' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // we'd get this call for enums, primarily
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  enumName  =  generateEnumNameIfApplicable ( member ,  name ,  t ,  parent ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ! enumName  &&  member )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( member . kind  ===  'method'  ||  member . kind  ===  'property' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // this should be easy to name... let's call it the same as the argument (eternal optimist)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  probableName  =  ` ${ parent . name } ${ translateMemberName ( ` ` ,  name ,  null ) } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  probableType  =  additionalTypes . get ( probableName ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( probableType )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // compare it with what?
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( probableType . expression  !=  t . expression )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          throw  new  Error ( ` Non-matching types with the same name. Panic. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        additionalTypes . set ( probableName ,  t ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  probableName ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( member . kind  ===  'event' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` ${ name } Payload ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  enumName  ||  t . name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  generateEnumNameIfApplicable ( member ,  name ,  type ,  parent )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ! type . union ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  potentialValues  =  type . union . filter ( u  =>  u . name . startsWith ( '"' ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( ( potentialValues . length  !==  type . union . length ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  ! ( type . union [ 0 ] . name  ===  'null'  &&  potentialValues . length  ===  type . union . length  -  1 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  null ;  // this isn't an enum, so we don't care, we let the caller generate the name
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type  &&  type . name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  type . name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // our enum naming policy leaves a few bits to be desired, but it'll do for now
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // however, with the recent changes, this almost never gets called anymore
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  translateMemberName ( 'enum' ,  name ,  type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Rendering  a  method  is  so  _special _ ,  with  so  many  weird  edge  cases ,  that  it 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  makes  sense  to  put  it  separate  from  the  other  logic .  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Member }  member  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Class | Documentation . Type }  parent  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Function }  output 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  renderMethod ( member ,  parent ,  output ,  name )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  typeResolve  =  ( type )  =>  translateType ( type ,  parent ,  ( t )  =>  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    let  newName  =  ` ${ parent . name } ${ translateMemberName ( member . kind ,  member . name ,  null ) } Result ` ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-12 01:07:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    documentedResults . set ( newName ,  ` Result of calling <see cref=" ${ translateMemberName ( "interface" ,  parent . name ) } . ${ translateMemberName ( member . kind ,  member . name ,  member ) } "/>. ` ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  newName ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /** @type {Map<string, string[]>} */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  paramDocs  =  new  Map ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  addParamsDoc  =  ( paramName ,  docs )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( paramName . startsWith ( '@' ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      paramName  =  paramName . substring ( 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( paramDocs . get ( paramName ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  new  Error ( ` Parameter  ${ paramName }  already exists in the docs. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    paramDocs . set ( paramName ,  docs ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /** @type {string} */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  type  =  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // need to check the original one
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( member . type . name  ===  'Object'  ||  member . type . name  ===  'Array' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  innerType  =  member . type ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  isArray  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( innerType . name  ===  'Array' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // we want to influence the name, but also change the object type
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      innerType  =  member . type . templates [ 0 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      isArray  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( innerType . expression  ===  '[Object]<[string], [string]>' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // do nothing, because this is handled down the road
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( ! isArray  &&  ! innerType . properties )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      type  =  ` dynamic ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      type  =  classNameMap . get ( innerType . name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! type )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        type  =  typeResolve ( innerType ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( isArray ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        type  =  ` IReadOnlyCollection< ${ type } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  type  =  type  ||  typeResolve ( member . type ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  // TODO: this is something that will probably go into the docs
 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // translate simple getters into read-only properties, and simple
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // set-only methods to settable properties
 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  if  ( member . args . size  ==  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  type  !==  'void' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  ! name . startsWith ( 'Get' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! member . async )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( member . spec ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        output ( XmlDoc . renderXmlDoc ( member . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` ${ type }   ${ name }  { get; } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    name  =  ` Get ${ name } ` ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-02 01:49:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  }  else  if  ( member . args . size  ==  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  type  ===  'void' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  name . startsWith ( 'Set' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    &&  ! member . async )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    name  =  name . substring ( 3 ) ;  // remove the 'Set'
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( member . spec ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( XmlDoc . renderXmlDoc ( member . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    output ( ` ${ translateType ( member . argsArray [ 0 ] . type ,  parent ) }   ${ name }  { set; } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // HACK: special case for generics handling!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type  ===  'T' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    name  =  ` ${ name } <T> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // adjust the return type for async methods
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( member . async )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type  ===  'void' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      type  =  ` Task ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      type  =  ` Task< ${ type } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // render args
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  args  =  [ ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  / * * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  innerArgType  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { string }  innerArgName  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   *  @ param  { Documentation . Member }  argument  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  pushArg  =  ( innerArgType ,  innerArgName ,  argument )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  isEnum  =  enumTypes . has ( innerArgType ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  isNullable  =  [ 'int' ,  'bool' ,  'decimal' ,  'float' ] . includes ( innerArgType ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  requiredPrefix  =  argument . required  ?  ""  :  isNullable  ?  "?"  :  "" ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-10 01:16:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    const  requiredSuffix  =  argument . required  ?  ""  :  " = default" ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    args . push ( ` ${ innerArgType } ${ requiredPrefix }   ${ innerArgName } ${ requiredSuffix } ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  parseArg  =  ( /** @type {Documentation.Member} */  arg )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( arg . name  ===  "options" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      arg . type . properties . forEach ( prop  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        parseArg ( prop ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( arg . type . expression  ===  '[string]|[path]' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  argName  =  translateMemberName ( 'argument' ,  arg . name ,  null ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      pushArg ( "string" ,  argName ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      pushArg ( "string" ,  ` ${ argName } Path ` ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( arg . spec )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        addParamsDoc ( argName ,  XmlDoc . renderTextOnly ( arg . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        addParamsDoc ( ` ${ argName } Path ` ,  [ ` Instead of specifying <paramref name=" ${ argName } "/>, gives the file name to load from. ` ] ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( arg . type . expression  ===  '[boolean]|[Array]<[string]>' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // HACK: this hurts my brain too
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // we split this into two args, one boolean, with the logical name
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  argName  =  translateMemberName ( 'argument' ,  arg . name ,  null ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  leftArgType  =  translateType ( arg . type . union [ 0 ] ,  parent ,  ( t )  =>  {  throw  new  Error ( 'Not supported' ) ;  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  rightArgType  =  translateType ( arg . type . union [ 1 ] ,  parent ,  ( t )  =>  {  throw  new  Error ( 'Not supported' ) ;  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      pushArg ( leftArgType ,  argName ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      pushArg ( rightArgType ,  ` ${ argName } Values ` ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      addParamsDoc ( argName ,  XmlDoc . renderTextOnly ( arg . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      addParamsDoc ( ` ${ argName } Values ` ,  [ ` The values to take into account when <paramref name=" ${ argName } "/> is <code>true</code>. ` ] ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  argName  =  translateMemberName ( 'argument' ,  arg . alias  ||  arg . name ,  null ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  argType  =  translateType ( arg . type ,  parent ,  ( t )  =>  generateNameDefault ( member ,  argName ,  t ,  parent ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( argType  ===  null  &&  arg . type . union )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // we might have to split this into multiple arguments
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  translatedArguments  =  arg . type . union . map ( t  =>  translateType ( t ,  parent ,  ( x )  =>  generateNameDefault ( member ,  argName ,  x ,  parent ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( translatedArguments . includes ( null ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( 'Unexpected null in translated argument types. Aborting.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  argDocumentation  =  XmlDoc . renderTextOnly ( arg . spec ,  maxDocumentationColumnWidth ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  ( const  newArg  of  translatedArguments )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        const  sanitizedArgName  =  newArg . match ( /(?<=^[\s"']*)(\w+)/g ,  '' ) [ 0 ]  ||  newArg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        const  newArgName  =  ` ${ argName } ${ sanitizedArgName [ 0 ] . toUpperCase ( )  +  sanitizedArgName . substring ( 1 ) } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pushArg ( newArg ,  newArgName ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        addParamsDoc ( newArgName ,  argDocumentation ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    addParamsDoc ( argName ,  XmlDoc . renderTextOnly ( arg . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( argName  ===  'timeout'  &&  argType  ===  'decimal' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      args . push ( ` int timeout = 0 ` ) ;  // a special argument, we ignore our convention
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pushArg ( argType ,  argName ,  arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  member . args . forEach ( parseArg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  output ( XmlDoc . renderXmlDoc ( member . spec ,  maxDocumentationColumnWidth ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  paramDocs . forEach ( ( val ,  ind )  =>  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( val  &&  val . length  ===  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` /// <param name=" ${ ind } "> ${ val } </param> ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` /// <param name=" ${ ind } "> ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( val . map ( l  =>  ` ///  ${ l } ` ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      output ( ` /// </param> ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  output ( ` ${ type }   ${ name } ( ${ args . join ( ', ' ) } ); ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ callback  generateNameCallback 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ param  { Documentation . Type }  t 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ returns  { string } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ param  { Documentation . Type }  type  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ param  { Documentation . Class | Documentation . Type }  parent 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *   @ param  { generateNameCallback }  generateNameCallback 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* /  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  translateType ( type ,  parent ,  generateNameCallback  =  t  =>  t . name )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // a few special cases we can fix automatically
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . expression  ===  '[null]|[Error]' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  'void' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  else  if  ( type . expression  ===  '[boolean]|"mixed"' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  'MixedState' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  isNullableEnum  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . union )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . union [ 0 ] . name  ===  'null' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // for dotnet, this is a nullable type
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // if the other side is a primitive type
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( type . union . length  >  2 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( type . union . filter ( x  =>  x . name . startsWith ( '"' ) ) . length  ==  type . union . length  -  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          isNullableEnum  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          throw  new  Error ( ` Union ( ${ parent . name } ) with null is too long. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        const  innerTypeName  =  translateType ( type . union [ 1 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // if type is primitive, or an enum, then it's nullable
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( innerTypeName  ===  'bool' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ||  innerTypeName  ===  'int' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          return  ` ${ innerTypeName } ? ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // if it's not a value type, it'll be nullable by default, so we can ignore it
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  ` ${ innerTypeName } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . union . filter ( u  =>  u . name . startsWith ( ` " ` ) ) . length  ==  type . union . length 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ||  isNullableEnum )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // this is an enum
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  enumName  =  generateNameCallback ( type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! enumName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( ` This was supposed to be an enum, but it failed generating a name,  ${ type . name }   ${ parent  ?  parent . name  :  "" } . ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // make sure we map the enum, or invalidate the name, in case it doesn't match well
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      const  potentialEnum  =  enumTypes . get ( enumName ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  enumValues  =  type . union . filter ( x  =>  x . name  !==  'null' ) . map ( x  =>  x . name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( potentialEnum )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // compare values
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( potentialEnum . join ( ',' )  !==  enumValues . join ( ',' ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // for now, we'll merge the two enums, if they have the same name, and we'll go from there
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          potentialEnum . concat ( enumValues . filter ( x  =>  ! potentialEnum . includes ( x ) ) ) ;  // merge & de-dupe
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // TODO: think about doing global type annotation, where we can add comments, such as this?
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          enumTypes . set ( enumName ,  potentialEnum ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        enumTypes . set ( enumName ,  enumValues ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( isNullableEnum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  ` ${ enumName } ? ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  enumName ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . expression  ===  '[string]|[Buffer]' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` byte[] ` ;  // TODO: make sure we implement extension methods for this!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( type . expression  ===  '[string]|[float]' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ||  type . expression  ===  '[string]|[float]|[boolean]' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      console . warn ( ` ${ type . name }  should be a 'string', but was a  ${ type . expression } ` ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 02:36:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      return  ` string ` ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:04:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( type . union . length  ==  2  &&  type . union [ 1 ] . name  ===  'Array'  &&  type . union [ 1 ] . templates [ 0 ] . name  ===  type . union [ 0 ] . name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` IEnumerable< ${ type . union [ 0 ] . name } > ` ;  // an example of this is [string]|[Array]<[string]>
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( type . union [ 0 ] . name  ===  'path' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // we don't support path, but we know it's usually an object on the other end, and we expect
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // the dotnet folks to use [NameOfTheObject].LoadFromPath(); method which we can provide separately
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  translateType ( type . union [ 1 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  if  ( type . expression  ===  '[float]|"raf"' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` Polling ` ;  // hardcoded because there's no other way to denote this
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . name  ===  'Array' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . templates . length  !=  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  new  Error ( ` Array ( ${ type . name }  from  ${ parent . name } ) has more than 1 dimension. Panic. ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  innerType  =  translateType ( type . templates [ 0 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  ` IEnumerable< ${ innerType } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . name  ===  'Object' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // take care of some common cases
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // TODO: this can be genericized
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . templates  &&  type . templates . length  ==  2 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // get the inner types of both templates, and if they're strings, it's a keyvaluepair string, string, 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  keyType  =  translateType ( type . templates [ 0 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  valueType  =  translateType ( type . templates [ 1 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` IEnumerable<KeyValuePair< ${ keyType } ,  ${ valueType } >> ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ( type . name  ===  'Object' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      &&  ! type . properties 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      &&  ! type . union )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  'object' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // this is an additional type that we need to generate
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  objectName  =  generateNameCallback ( type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( objectName  ===  'Object' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  new  Error ( 'Object unexpected' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( type . name  ===  'Object' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      registerAdditionalType ( objectName ,  type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  objectName ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . name  ===  'Map' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . templates  &&  type . templates . length  ==  2 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // we map to a dictionary
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  keyType  =  translateType ( type . templates [ 0 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  valueType  =  translateType ( type . templates [ 1 ] ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` Dictionary< ${ keyType } ,  ${ valueType } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      throw  'Map has invalid number of templates.' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( type . name  ===  'function' )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . expression  ===  '[function]'  ||  ! type . args ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  'Action' ;  // super simple mapping
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    let  argsList  =  '' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( type . args )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  translatedCallbackArguments  =  type . args . map ( t  =>  translateType ( t ,  parent ,  generateNameCallback ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( translatedCallbackArguments . includes ( null ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( 'There was an argument we could not parse. Aborting.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      argsList  =  translatedCallbackArguments . join ( ', ' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! type . returnType )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // this is an Action
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` Action< ${ argsList } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      let  returnType  =  translateType ( type . returnType ,  parent ,  generateNameCallback ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( returnType  ==  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        throw  new  Error ( 'Unexpected null as return type.' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  ` Func< ${ argsList } ,  ${ returnType } > ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // there's a chance this is a name we've already seen before, so check
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // this is also where we map known types, like boolean -> bool, etc.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  name  =  classNameMap . get ( type . name )  ||  type . name ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  ` ${ name } ` ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { string }  typeName  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  @ param  { Documentation . Type }  type  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								function  registerAdditionalType ( typeName ,  type )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( [ 'object' ,  'string' ,  'int' ] . includes ( typeName ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  let  potentialType  =  additionalTypes . get ( typeName ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( potentialType )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    console . log ( ` Type  ${ typeName }  already exists, so skipping... ` ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  additionalTypes . set ( typeName ,  type ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}