1
- const { spawnSync } = require ( 'child_process' ) ;
2
- const { resolve } = require ( 'path' ) ;
3
- const { writeFileSync } = require ( 'fs' ) ;
4
-
5
- function getSymbolsForVersion ( version ) {
6
- const spawned = spawnSync ( 'clang' ,
7
- [ '-Xclang' , '-ast-dump=json' , '-fsyntax-only' , '-fno-diagnostics-color' , version ? `-DNAPI_VERSION=${ version } ` : '-DNAPI_EXPERIMENTAL' , resolve ( __dirname , '..' , 'include' , 'node_api.h' ) ] ,
8
- { maxBuffer : 2_000_000 }
9
- ) ;
10
-
11
- if ( spawned . error ) {
12
- if ( spawned . error . code === 'ENOENT' ) {
13
- throw new Error ( 'This tool requires clang to be installed.' ) ;
1
+ // @ts -check
2
+ 'use strict' ;
3
+
4
+ const { spawn } = require ( 'child_process' ) ;
5
+ const { resolve : resolvePath } = require ( 'path' ) ;
6
+ const { writeFile } = require ( 'fs/promises' ) ;
7
+
8
+ /** @typedef {{ js_native_api_symbols: string[]; node_api_symbols: string[]; } } SymbolInfo */
9
+
10
+ /**
11
+ * @param {number | undefined } [version]
12
+ * @returns {Promise<SymbolInfo> }
13
+ */
14
+ async function getSymbolsForVersion ( version ) {
15
+ try {
16
+ const { exitCode, stdout, stderr } = await new Promise ( ( resolve , reject ) => {
17
+ const spawned = spawn ( 'clang' ,
18
+ [ '-Xclang' , '-ast-dump=json' , '-fsyntax-only' , '-fno-diagnostics-color' , version ? `-DNAPI_VERSION=${ version } ` : '-DNAPI_EXPERIMENTAL' , resolvePath ( __dirname , '..' , 'include' , 'node_api.h' ) ]
19
+ ) ;
20
+
21
+ let stdout = '' ;
22
+ let stderr = '' ;
23
+
24
+ spawned . stdout ?. on ( 'data' , ( data ) => {
25
+ stdout += data . toString ( 'utf-8' ) ;
26
+ } ) ;
27
+ spawned . stderr ?. on ( 'data' , ( data ) => {
28
+ stderr += data . toString ( 'utf-8' ) ;
29
+ } ) ;
30
+
31
+ spawned . on ( 'exit' , function ( exitCode ) {
32
+ resolve ( { exitCode, stdout, stderr } ) ;
33
+ } ) ;
34
+
35
+ spawned . on ( 'error' , function ( err ) {
36
+ reject ( err ) ;
37
+ } ) ;
38
+ } ) ;
39
+
40
+ if ( exitCode !== 0 ) {
41
+ throw new Error ( `clang exited with non-zero exit code ${ exitCode } . stderr: ${ stderr ? stderr : '<empty>' } ` ) ;
14
42
}
15
- throw spawned . error ;
16
- } else if ( spawned . stderr . length > 0 ) {
17
- throw new Error ( spawned . stderr . toString ( 'utf-8' ) ) ;
18
- }
19
43
20
- const ast = JSON . parse ( spawned . stdout . toString ( 'utf-8' ) ) ;
21
- const symbols = { js_native_api_symbols : [ ] , node_api_symbols : [ ] } ;
44
+ const ast = JSON . parse ( stdout ) ;
22
45
23
- for ( const statement of ast . inner ) {
24
- if ( statement . kind !== 'FunctionDecl' ) {
25
- continue ;
26
- }
46
+ /** @type {{js_native_api_symbols: string[], node_api_symbols: string[]} } */
47
+ const symbols = { js_native_api_symbols : [ ] , node_api_symbols : [ ] } ;
27
48
28
- const name = statement . name ;
29
- const file = statement . loc . includedFrom ?. file ;
49
+ for ( const statement of ast . inner ) {
50
+ if ( statement . kind !== 'FunctionDecl' ) {
51
+ continue ;
52
+ }
53
+
54
+ const name = statement . name ;
55
+ const file = statement . loc . includedFrom ?. file ;
30
56
31
- if ( file ) {
32
- symbols . js_native_api_symbols . push ( name ) ;
33
- } else {
34
- symbols . node_api_symbols . push ( name ) ;
57
+ if ( file ) {
58
+ symbols . js_native_api_symbols . push ( name ) ;
59
+ } else {
60
+ symbols . node_api_symbols . push ( name ) ;
61
+ }
35
62
}
36
- }
37
63
38
- symbols . js_native_api_symbols . sort ( ) ;
39
- symbols . node_api_symbols . sort ( ) ;
64
+ symbols . js_native_api_symbols . sort ( ) ;
65
+ symbols . node_api_symbols . sort ( ) ;
40
66
41
- return symbols ;
67
+ return symbols ;
68
+ } catch ( err ) {
69
+ if ( err . code === 'ENOENT' ) {
70
+ throw new Error ( 'This tool requires clang to be installed.' ) ;
71
+ }
72
+ throw err ;
73
+ }
42
74
}
43
75
44
-
45
- function getAllSymbols ( ) {
76
+ /** @returns {Promise<{maxVersion: number, symbols: {[x: string]: SymbolInfo}}> } */
77
+ async function getAllSymbols ( ) {
78
+ /** @type {{[x: string]: SymbolInfo} } */
46
79
const allSymbols = { } ;
47
80
let version = 1 ;
48
81
49
82
console . log ( 'Processing symbols from clang:' )
50
83
while ( true ) {
51
- const symbols = getSymbolsForVersion ( version ) ;
84
+ const symbols = await getSymbolsForVersion ( version ) ;
52
85
53
86
if ( version > 1 ) {
54
87
const previousSymbols = allSymbols [ `v${ version - 1 } ` ] ;
@@ -62,15 +95,21 @@ function getAllSymbols() {
62
95
++ version ;
63
96
}
64
97
65
- const symbols = allSymbols [ `experimental` ] = getSymbolsForVersion ( ) ;
98
+ const symbols = allSymbols [ `experimental` ] = await getSymbolsForVersion ( ) ;
66
99
console . log ( ` Experimental: ${ symbols . js_native_api_symbols . length } js_native_api_symbols, ${ symbols . node_api_symbols . length } node_api_symbols` ) ;
67
100
return {
68
101
maxVersion : version ,
69
102
symbols : allSymbols
70
103
} ;
71
104
}
72
105
106
+ /**
107
+ * @param {SymbolInfo } previousSymbols
108
+ * @param {SymbolInfo } currentSymbols
109
+ * @returns {SymbolInfo }
110
+ */
73
111
function getUniqueSymbols ( previousSymbols , currentSymbols ) {
112
+ /** @type {SymbolInfo } */
74
113
const symbols = { js_native_api_symbols : [ ] , node_api_symbols : [ ] } ;
75
114
for ( const symbol of currentSymbols . js_native_api_symbols ) {
76
115
if ( ! previousSymbols . js_native_api_symbols . includes ( symbol ) ) {
@@ -85,22 +124,25 @@ function getUniqueSymbols(previousSymbols, currentSymbols) {
85
124
return symbols ;
86
125
}
87
126
88
- function joinSymbols ( symbols , prependNewLine ) {
89
- if ( symbols . length === 0 ) return '' ;
90
- return `${ prependNewLine ? ',\n ' : '' } '${ symbols . join ( "',\n '" ) } '` ;
127
+ /**
128
+ * @param {string[] } strings
129
+ */
130
+ function joinStrings ( strings , prependNewLine = false ) {
131
+ if ( strings . length === 0 ) return '' ;
132
+ return `${ prependNewLine ? ',\n ' : '' } '${ strings . join ( "',\n '" ) } '` ;
91
133
}
92
134
93
- function getSymbolData ( ) {
94
- const { maxVersion, symbols } = getAllSymbols ( ) ;
135
+ async function getSymbolData ( ) {
136
+ const { maxVersion, symbols } = await getAllSymbols ( ) ;
95
137
96
138
let data = `'use strict'
97
139
98
140
const v1 = {
99
141
js_native_api_symbols: [
100
- ${ joinSymbols ( symbols . v1 . js_native_api_symbols ) }
142
+ ${ joinStrings ( symbols . v1 . js_native_api_symbols ) }
101
143
],
102
144
node_api_symbols: [
103
- ${ joinSymbols ( symbols . v1 . node_api_symbols ) }
145
+ ${ joinStrings ( symbols . v1 . node_api_symbols ) }
104
146
]
105
147
}
106
148
` ;
@@ -111,10 +153,10 @@ const v1 = {
111
153
data += `
112
154
const ${ version === maxVersion + 1 ? 'experimental' : `v${ version } ` } = {
113
155
js_native_api_symbols: [
114
- ...v${ version - 1 } .js_native_api_symbols${ joinSymbols ( newSymbols . js_native_api_symbols , true ) }
156
+ ...v${ version - 1 } .js_native_api_symbols${ joinStrings ( newSymbols . js_native_api_symbols , true ) }
115
157
],
116
158
node_api_symbols: [
117
- ...v${ version - 1 } .node_api_symbols${ joinSymbols ( newSymbols . node_api_symbols , true ) }
159
+ ...v${ version - 1 } .node_api_symbols${ joinStrings ( newSymbols . node_api_symbols , true ) }
118
160
]
119
161
}
120
162
` ;
@@ -129,16 +171,14 @@ module.exports = {
129
171
return data ;
130
172
}
131
173
132
- function main ( ) {
133
- const path = resolve ( __dirname , '../symbols.js' ) ;
134
- const data = getSymbolData ( ) ;
174
+ async function main ( ) {
175
+ const path = resolvePath ( __dirname , '../symbols.js' ) ;
176
+ const data = await getSymbolData ( ) ;
135
177
console . log ( `Writing symbols to ${ path } ` )
136
- writeFileSync ( path , data ) ;
178
+ return writeFile ( path , data ) ;
137
179
}
138
180
139
- try {
140
- main ( ) ;
141
- } catch ( e ) {
181
+ main ( ) . catch ( e => {
142
182
console . error ( e ) ;
143
183
process . exitCode = 1 ;
144
- }
184
+ } ) ;
0 commit comments