Skip to content

Commit ff604ef

Browse files
committed
ast-parse.js renders methods.d.ts, incomplete
1 parent 97dc47c commit ff604ef

File tree

1 file changed

+87
-26
lines changed

1 file changed

+87
-26
lines changed

types/ast-parse.js

Lines changed: 87 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import 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

512
function getParents( node /* ts.ClassDeclaration*/ )
613
{
@@ -20,8 +27,7 @@ function getParents( node /* ts.ClassDeclaration*/ )
2027

2128
const 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));
8479
extract( "node_modules/typescript/lib/lib.dom.d.ts" );
8580
const 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

Comments
 (0)