@@ -4,49 +4,67 @@ import { readFileSync, writeFileSync } from "fs";
44import * as path from "path" ;
55import ts from "typescript" ;
66import { fileURLToPath } from "url" ;
7+ import { program } from "commander" ;
78
89const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
910
10- const [ inputPath , outputPath ] = process . argv . slice ( 2 ) ;
11- if ( ! inputPath || ! outputPath ) {
12- console . error (
13- "Please provide the input and output file paths as command-line arguments."
14- ) ;
15- process . exit ( 1 ) ;
16- }
17-
11+ const dtsFiles = [
12+ "node_modules/typescript/lib/lib.dom.d.ts" ,
13+ "node_modules/@types/node/web-globals/events.d.ts" ,
14+ "node_modules/undici-types/eventsource.d.ts" ,
15+ "node_modules/undici-types/websocket.d.ts" ,
16+ ] ;
17+
18+ program
19+ . name ( "easyAddEventListener parser" )
20+ . description ( "Parses TS files in order to obtain addEventListener signatures" )
21+ . argument (
22+ process . cwd ( ) === __dirname ? "[files...]" : "<files...>" ,
23+ "Files to parse"
24+ )
25+ . option ( "-o,--output" , "Output dir" , __dirname )
26+ . parse ( ) ;
27+ const { output : outputPath } = program . opts ( ) ;
28+ const files = program . args . length ? program . args : dtsFiles ;
1829const sourceFile = ts . createSourceFile (
1930 "ast.ts" ,
20- readFileSync ( inputPath ) . toString ( ) ,
31+ files
32+ . map ( ( file ) => `// file: ${ file } \n\n${ readFileSync ( file ) . toString ( ) } ` )
33+ . join ( "\n\n\n\n" ) ,
2134 ts . ScriptTarget . Latest
2235) ;
2336
2437/**
25- * @type {{ node: ts.InterfaceDeclaration, type: string, eventMap: string, ancestors: string[] }[] }
38+ * @type {{ node: ts.InterfaceDeclaration, shim: ts.InterfaceDeclaration, type: string, eventMap: string, ancestors: string[] }[] }
2639 */
2740const nodes = [ ] ;
2841ts . forEachChild ( sourceFile , visit ) ;
2942
30- // Sort so that the condition is correct for subclasses
31- nodes . sort ( ( a , b ) =>
32- b . ancestors . includes ( a . type ) ? 1 : a . ancestors . includes ( b . type ) ? - 1 : 0
33- ) ;
34-
3543const condition = nodes
3644 . filter ( ( { eventMap } ) => ! ! eventMap )
45+ // Sort so that the condition is correct for subclasses
46+ . sort ( ( a , b ) =>
47+ b . ancestors . includes ( a . type )
48+ ? 1
49+ : a . ancestors . includes ( b . type )
50+ ? - 1
51+ : b . ancestors . length - a . ancestors . length
52+ )
3753 . map ( ( { type, eventMap } ) => `T extends ${ type } ? ${ eventMap } : ` )
3854 . concat ( "never" )
3955 . join ( "" ) ;
4056const value = `export type EventMap<T extends EventTarget> = ${ condition } ` ;
41- writeFileSync ( path . resolve ( __dirname , "types.d.ts" ) , value ) ;
42- console . log ( ` Successfully written types.d.ts` ) ;
57+ writeFileSync ( path . resolve ( outputPath , "types.d.ts" ) , value ) ;
58+ console . log ( " Successfully created types.d.ts" ) ;
4359
4460const printer = ts . createPrinter ( { newLine : ts . NewLineKind . LineFeed } ) ;
4561writeFileSync (
46- outputPath ,
47- printer . printNode ( ts . EmitHint . Unspecified , sourceFile )
62+ path . resolve ( outputPath , "shim.d.ts" ) ,
63+ nodes
64+ . map ( ( { shim } ) => printer . printNode ( ts . EmitHint . Unspecified , shim ) )
65+ . join ( "\n\n" )
4866) ;
49- console . log ( ` Successfully created ${ outputPath } ` ) ;
67+ console . log ( " Successfully created shim.d.ts" ) ;
5068
5169/**
5270 * Finds a node in the source file by its name and kind.
@@ -100,45 +118,61 @@ function visit(node) {
100118 return ;
101119 }
102120
103- node . members
104- . filter (
105- ( member ) =>
106- ts . isMethodSignature ( member ) &&
107- member . name ?. getText ( sourceFile ) === "addEventListener"
108- )
109- . forEach (
110- /**
111- *
112- * @param {ts.MethodSignature } methodNode
113- * @returns
114- */
115- ( methodNode ) => {
116- methodNode . type = ts . factory . createTypeReferenceNode ( "VoidFunction" ) ;
117- }
118- ) ;
121+ /**
122+ * @type {ts.MethodSignature[] }
123+ */
124+ const addEventListenerDeclarations = node . members . filter (
125+ ( member ) =>
126+ ts . isMethodSignature ( member ) &&
127+ member . name ?. getText ( sourceFile ) === "addEventListener"
128+ ) ;
129+
130+ if ( ! addEventListenerDeclarations . length ) {
131+ return ;
132+ }
119133
120134 const heritageClauses = [ ] ;
121135 visitHeritageClauses ( node , heritageClauses ) ;
122136
123- if ( ! heritageClauses . includes ( "EventTarget" ) ) {
124- return ;
125- }
137+ // if (!heritageClauses.includes("EventTarget")) {
138+ // return;
139+ // }
126140
127- const eventMap = node . members
128- . filter (
129- ( member ) =>
130- member . name ?. getText ( sourceFile ) === "addEventListener" &&
131- member . typeParameters ?. length
132- )
141+ const eventMap = addEventListenerDeclarations
142+ . filter ( ( member ) => member . typeParameters ?. length )
133143 . flatMap ( ( member ) => member . typeParameters )
134144 . map ( ( typeParam ) => typeParam . constraint . getText ( sourceFile ) )
135145 . find ( ( k ) => k . startsWith ( "keyof" ) )
136146 ?. replace ( "keyof" , "" )
137147 . trim ( ) ;
138148
149+ const generics =
150+ node . typeParameters ?. filter ( ( node ) => ! node . default ) . length ?? 0 ;
151+
139152 nodes . push ( {
140153 node,
141- type : node . name . getText ( sourceFile ) ,
154+ shim : ts . factory . createInterfaceDeclaration (
155+ undefined ,
156+ node . name ,
157+ node . typeParameters ,
158+ undefined ,
159+ addEventListenerDeclarations . map ( ( methodDeclarationNode ) => {
160+ return ts . factory . createMethodDeclaration (
161+ methodDeclarationNode . modifiers ,
162+ undefined ,
163+ methodDeclarationNode . name ,
164+ methodDeclarationNode . questionToken ,
165+ methodDeclarationNode . typeParameters ,
166+ methodDeclarationNode . parameters ,
167+ ts . factory . createTypeReferenceNode ( "VoidFunction" )
168+ ) ;
169+ } )
170+ ) ,
171+ type : generics
172+ ? `${ node . name . getText ( sourceFile ) } <${ new Array ( generics )
173+ . fill ( "any" )
174+ . join ( ", " ) } >`
175+ : node . name . getText ( sourceFile ) ,
142176 eventMap,
143177 ancestors : heritageClauses ,
144178 } ) ;
0 commit comments