1
+ /**
2
+ * Module dependencies.
3
+ */
4
+
5
+ import fs from 'fs' ;
6
+ import path from 'path' ;
7
+ import { fileURLToPath } from 'url' ;
8
+ import { createRequire } from 'module' ;
9
+
10
+ const require = createRequire ( import . meta. url ) ;
11
+
12
+ const join = path . join ;
13
+ const dirname = path . dirname ;
14
+ const exists =
15
+ ( fs . accessSync &&
16
+ function ( path ) {
17
+ try {
18
+ fs . accessSync ( path ) ;
19
+ } catch ( e ) {
20
+ return false ;
21
+ }
22
+ return true ;
23
+ } ) ||
24
+ fs . existsSync ||
25
+ path . existsSync ;
26
+
27
+ const defaults = {
28
+ arrow : process . env . NODE_BINDINGS_ARROW || ' → ' ,
29
+ compiled : process . env . NODE_BINDINGS_COMPILED_DIR || 'compiled' ,
30
+ platform : process . platform ,
31
+ arch : process . arch ,
32
+ nodePreGyp :
33
+ 'node-v' +
34
+ process . versions . modules +
35
+ '-' +
36
+ process . platform +
37
+ '-' +
38
+ process . arch ,
39
+ version : process . versions . node ,
40
+ bindings : 'bindings.node' ,
41
+ try : [
42
+ // node-gyp's linked version in the "build" dir
43
+ [ 'module_root' , 'build' , 'bindings' ] ,
44
+ // node-waf and gyp_addon (a.k.a node-gyp)
45
+ [ 'module_root' , 'build' , 'Debug' , 'bindings' ] ,
46
+ [ 'module_root' , 'build' , 'Release' , 'bindings' ] ,
47
+ // Debug files, for development (legacy behavior, remove for node v0.9)
48
+ [ 'module_root' , 'out' , 'Debug' , 'bindings' ] ,
49
+ [ 'module_root' , 'Debug' , 'bindings' ] ,
50
+ // Release files, but manually compiled (legacy behavior, remove for node v0.9)
51
+ [ 'module_root' , 'out' , 'Release' , 'bindings' ] ,
52
+ [ 'module_root' , 'Release' , 'bindings' ] ,
53
+ // Legacy from node-waf, node <= 0.4.x
54
+ [ 'module_root' , 'build' , 'default' , 'bindings' ] ,
55
+ // Production "Release" buildtype binary (meh...)
56
+ [ 'module_root' , 'compiled' , 'version' , 'platform' , 'arch' , 'bindings' ] ,
57
+ // node-qbs builds
58
+ [ 'module_root' , 'addon-build' , 'release' , 'install-root' , 'bindings' ] ,
59
+ [ 'module_root' , 'addon-build' , 'debug' , 'install-root' , 'bindings' ] ,
60
+ [ 'module_root' , 'addon-build' , 'default' , 'install-root' , 'bindings' ] ,
61
+ // node-pre-gyp path ./lib/binding/{node_abi}-{platform}-{arch}
62
+ [ 'module_root' , 'lib' , 'binding' , 'nodePreGyp' , 'bindings' ]
63
+ ]
64
+ } ;
65
+
66
+ /**
67
+ * The main `bindings()` function loads the compiled bindings for a given module.
68
+ * It uses V8's Error API to determine the parent filename that this function is
69
+ * being invoked from, which is then used to find the root directory.
70
+ */
71
+
72
+ function bindings ( opts ) {
73
+ // Argument surgery
74
+ if ( typeof opts == 'string' ) {
75
+ opts = { bindings : opts } ;
76
+ } else if ( ! opts ) {
77
+ opts = { } ;
78
+ }
79
+
80
+ // maps `defaults` onto `opts` object
81
+ Object . keys ( defaults ) . map ( function ( i ) {
82
+ if ( ! ( i in opts ) ) opts [ i ] = defaults [ i ] ;
83
+ } ) ;
84
+
85
+ // Get the module root
86
+ if ( ! opts . module_root ) {
87
+ opts . module_root = getRoot ( getFileName ( ) ) ;
88
+ }
89
+
90
+ // Ensure the given bindings name ends with .node
91
+ if ( path . extname ( opts . bindings ) != '.node' ) {
92
+ opts . bindings += '.node' ;
93
+ }
94
+
95
+ // https://github.com/webpack/webpack/issues/4175#issuecomment-342931035
96
+ const requireFunc =
97
+ typeof __webpack_require__ === 'function'
98
+ ? __non_webpack_require__
99
+ : require ;
100
+
101
+ const tries = [ ] ;
102
+ let i = 0 ;
103
+ const l = opts . try . length ;
104
+ let n , b , err ;
105
+
106
+ for ( ; i < l ; i ++ ) {
107
+ n = join . apply (
108
+ null ,
109
+ opts . try [ i ] . map ( function ( p ) {
110
+ return opts [ p ] || p ;
111
+ } )
112
+ ) ;
113
+ tries . push ( n ) ;
114
+ try {
115
+ b = opts . path ? requireFunc . resolve ( n ) : requireFunc ( n ) ;
116
+ if ( ! opts . path ) {
117
+ b . path = n ;
118
+ }
119
+ return b ;
120
+ } catch ( e ) {
121
+ if (
122
+ e . code !== 'MODULE_NOT_FOUND' &&
123
+ e . code !== 'QUALIFIED_PATH_RESOLUTION_FAILED' &&
124
+ ! / n o t f i n d / i. test ( e . message )
125
+ ) {
126
+ throw e ;
127
+ }
128
+ }
129
+ }
130
+
131
+ err = new Error (
132
+ 'Could not locate the bindings file. Tried:\n' +
133
+ tries
134
+ . map ( function ( a ) {
135
+ return opts . arrow + a ;
136
+ } )
137
+ . join ( '\n' )
138
+ ) ;
139
+ err . tries = tries ;
140
+ throw err ;
141
+ }
142
+
143
+ /**
144
+ * Gets the filename of the JavaScript file that invokes this function.
145
+ * Used to help find the root directory of a module.
146
+ * Optionally accepts an filename argument to skip when searching for the invoking filename
147
+ */
148
+
149
+ function getFileName ( calling_file ) {
150
+ const origPST = Error . prepareStackTrace ;
151
+ const origSTL = Error . stackTraceLimit ;
152
+ const dummy = { } ;
153
+ let fileName ;
154
+
155
+ Error . stackTraceLimit = 10 ;
156
+
157
+ Error . prepareStackTrace = function ( e , st ) {
158
+ for ( let i = 0 , l = st . length ; i < l ; i ++ ) {
159
+ fileName = st [ i ] . getFileName ( ) ;
160
+ if ( fileName !== import . meta. url ) {
161
+ if ( calling_file ) {
162
+ if ( fileName !== calling_file ) {
163
+ return ;
164
+ }
165
+ } else {
166
+ return ;
167
+ }
168
+ }
169
+ }
170
+ } ;
171
+
172
+ // run the 'prepareStackTrace' function above
173
+ Error . captureStackTrace ( dummy ) ;
174
+ dummy . stack ;
175
+
176
+ // cleanup
177
+ Error . prepareStackTrace = origPST ;
178
+ Error . stackTraceLimit = origSTL ;
179
+
180
+ // handle filename that starts with "file://"
181
+ const fileSchema = 'file://' ;
182
+ if ( fileName && fileName . indexOf ( fileSchema ) === 0 ) {
183
+ fileName = fileURLToPath ( fileName ) ;
184
+ }
185
+
186
+ return fileName ;
187
+ }
188
+
189
+ /**
190
+ * Gets the root directory of a module, given an arbitrary filename
191
+ * somewhere in the module tree. The "root directory" is the directory
192
+ * containing the `package.json` file.
193
+ *
194
+ * In: /home/nate/node-native-module/lib/index.js
195
+ * Out: /home/nate/node-native-module
196
+ */
197
+
198
+ function getRoot ( file ) {
199
+ let dir = dirname ( file ) ;
200
+ let prev ;
201
+ while ( true ) {
202
+ if ( dir === '.' ) {
203
+ // Avoids an infinite loop in rare cases, like the REPL
204
+ dir = process . cwd ( ) ;
205
+ }
206
+ if (
207
+ exists ( join ( dir , 'package.json' ) ) ||
208
+ exists ( join ( dir , 'node_modules' ) )
209
+ ) {
210
+ // Found the 'package.json' file or 'node_modules' dir; we're done
211
+ return dir ;
212
+ }
213
+ if ( prev === dir ) {
214
+ // Got to the top
215
+ throw new Error (
216
+ 'Could not find module root given file: "' +
217
+ file +
218
+ '". Do you have a `package.json` file? '
219
+ ) ;
220
+ }
221
+ // Try the parent dir next
222
+ prev = dir ;
223
+ dir = join ( dir , '..' ) ;
224
+ }
225
+ }
226
+
227
+ export default bindings ;
228
+ export { getFileName , getRoot } ;
0 commit comments