11import ts from "typescript" ;
2+ import fs from 'fs' ;
23
3- let checker ;
4+ let checker , sourceFile ;
5+
6+ const getNodeName = node => node . name ?. text ;
7+ // checker.getSymbolAtLocation(node.name).getName();
8+ // checker.getFullyQualifiedName( checker.getSymbolAtLocation(node.name) )
9+ // node.name?.text;
10+ // node.name?.escapedText;
411
512function getParents ( node /* ts.ClassDeclaration*/ )
613{
@@ -20,8 +27,7 @@ function getParents( node /* ts.ClassDeclaration*/ )
2027
2128const mapInterfaceName2deps = {
2229 // HTMLElement: // given for sample
23- // {
24- // extends: [ 'Element', 'DocumentAndElementEventHandlers', 'ElementCSSInlineStyle', 'ElementContentEditable', 'GlobalEventHandlers', 'HTMLOrSVGElement' ],
30+ // { extends: [ 'Element', 'DocumentAndElementEventHandlers', 'ElementCSSInlineStyle', 'ElementContentEditable', 'GlobalEventHandlers', 'HTMLOrSVGElement' ],
2531 // inheritedBy: [ 'HTMLEmbedElement' ]
2632 // }
2733} ;
@@ -43,32 +49,21 @@ function extract( file )
4349 const sourceFile = program . getSourceFile ( file ) ;
4450 // To print the AST, we'll use TypeScript's printer
4551 const printer = ts . createPrinter ( { newLine : ts . NewLineKind . LineFeed } ) ;
46- // To give constructive error messages, keep track of found and un-found identifiers
47- const foundNodes = [ ] ;
48- // Loop through the root AST nodes of the file
49- // @ts -ignore
5052 ts . forEachChild ( sourceFile , node =>
5153 {
52- let name = "" ;
53- // This is an incomplete set of AST nodes which could have a top level identifier
54- // it's left to you to expand this list, which you can do by using
55- // https://ts-ast-viewer.com/ to see the AST of a file then use the same patterns
56- // as below
57- if ( ts . isFunctionDeclaration ( node ) )
58- {
59- // @ts -ignore
60- name = node . name . text ;
61- // Hide the method body when printing
62- // @ts -ignore
63- node . body = undefined ;
64- } else if ( ts . isVariableStatement ( node ) )
65- {
66- name = node . declarationList . declarations [ 0 ] . name . getText ( sourceFile ) ;
67- } else if ( ts . isInterfaceDeclaration ( node ) )
54+ // if( ts.isFunctionDeclaration( node ) )
55+ // { name = getNodeName(node);
56+ // console.log('function',name);
57+ // }else if( ts.isVariableStatement( node ) )
58+ // {
59+ // name = node.declarationList.declarations[ 0 ].name.getText( sourceFile );
60+ // console.log('variable',name);
61+ // }else
62+ if ( ts . isInterfaceDeclaration ( node ) )
6863 {
69- name = node . name . text ;
70- foundNodes . push ( [ name , node ] ) ;
64+ const name = getNodeName ( node ) ;
7165 let deps = assureMemberAsMap ( mapInterfaceName2deps , name ) ;
66+ deps . interfaceNode = node ;
7267 const classes = getParents ( node ) ;
7368 classes . map ( c =>
7469 {
@@ -83,4 +78,70 @@ function extract( file )
8378// extract(process.argv[2], process.argv.slice(3));
8479extract ( "node_modules/typescript/lib/lib.dom.d.ts" ) ;
8580const interfaces = Object . keys ( mapInterfaceName2deps ) ;
86- console . log ( mapInterfaceName2deps ) ;
81+ // console.log( mapInterfaceName2deps );
82+ const member2commentCount = { } ;
83+
84+
85+ function scanMembers ( dep )
86+ {
87+ dep . interfaceNode . members . map ( node =>
88+ {
89+ const name = getNodeName ( node ) ;
90+ if ( ! name )
91+ return ;
92+ const txt = node . getText ( sourceFile ) . replace ( 'readonly ' , '' ) ;
93+ const symbol = checker . getSymbolAtLocation ( node . name ) ;
94+ const comment = ts . displayPartsToString ( symbol . getDocumentationComment ( checker ) ) . trim ( ) ;
95+ if ( ! member2commentCount [ txt ] ) // assureMemberAsMap(member2commentCount,txt)[comment] )
96+ member2commentCount [ txt ] = { } ;
97+ if ( ! member2commentCount [ txt ] [ comment ] )
98+ member2commentCount [ txt ] [ comment ] = 0 ;
99+ member2commentCount [ txt ] [ comment ] ++ ;
100+
101+ // get comments
102+ // const commentRanges = ts.getLeadingCommentRanges(
103+ // sourceFile.getFullText(),
104+ // node.getFullStart());
105+ // if (commentRange?.length)
106+ // const commentStrings:string[] =
107+ // commentRanges.map(r=>sourceFile.getFullText().slice(r.pos,r.end))
108+
109+ // console.log( name, 'comment',member2commentCount[txt][comment] )
110+ } ) ;
111+ }
112+ const traverseParents = clazz =>
113+ { for ( let name in mapInterfaceName2deps [ clazz ] . extends )
114+ { scanMembers ( mapInterfaceName2deps [ name ] ) ;
115+ traverseParents ( name ) ;
116+ }
117+ } ;
118+ function traverseChildren ( clazz , parentName )
119+ { for ( let name in mapInterfaceName2deps [ clazz ] . inheritedBy )
120+ if ( name !== parentName )
121+ { scanMembers ( mapInterfaceName2deps [ name ] ) ;
122+ traverseChildren ( name , clazz )
123+ }
124+ }
125+
126+ // extract methods with JSDoc
127+ scanMembers ( mapInterfaceName2deps . HTMLElement ) ;
128+ traverseParents ( 'HTMLElement' ) ;
129+ traverseChildren ( 'HTMLElement' , 'Element' ) ;
130+
131+ const methods = Object . keys ( member2commentCount ) . map ( m =>
132+ {
133+ const comments = Object . keys ( member2commentCount [ m ] ) . filter ( c => c ) ;
134+ const commentsStr = comments . length ? '/* ' + comments . map ( c => ` ${ c } ` ) . join ( '\n\n' ) + '*/\n' : '' ;
135+ return commentsStr + m + '\n'
136+ } ) . join ( '\n' ) ;
137+
138+ var stream = fs . createWriteStream ( "methods.d.ts" ) ;
139+ stream . once ( 'open' , function ( fd ) {
140+ stream . write ( "interface HTMLInputElement {\n" ) ;
141+ stream . write ( methods ) ;
142+ stream . write ( "\n}\n" ) ;
143+ stream . end ( ) ;
144+ } ) ;
145+
146+ // how to extract JSDocs https://stackoverflow.com/questions/47429792/is-it-possible-to-get-comments-as-nodes-in-the-ast-using-the-typescript-compiler
147+ // how to write type with JSDocs https://stackoverflow.com/questions/67575784/typescript-ast-factory-how-to-use-comments
0 commit comments