| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5fff46a commit 84c9e4f
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -140,168 +140,182 @@ let internalBinding; | |||
| 140 | 140 | }; | |
| 141 | 141 | } | |
| 142 | 142 | ||
| 143 | - // Think of this as module.exports in this file even though it is not | ||
| 144 | - // written in CommonJS style. | ||
| 145 | - const loaderExports = { | ||
| 146 | - internalBinding, | ||
| 147 | - NativeModule, | ||
| 148 | - require: nativeModuleRequire | ||
| 149 | - }; | ||
| 150 | - | ||
| 151 | 143 | const loaderId = 'internal/bootstrap/loaders'; | |
| 152 | - | ||
| 153 | - // Set up NativeModule. | ||
| 154 | - function NativeModule(id) { | ||
| 155 | - this.filename = `${id}.js`; | ||
| 156 | - this.id = id; | ||
| 157 | - this.exports = {}; | ||
| 158 | - this.module = undefined; | ||
| 159 | - this.exportKeys = undefined; | ||
| 160 | - this.loaded = false; | ||
| 161 | - this.loading = false; | ||
| 162 | - this.canBeRequiredByUsers = !id.startsWith('internal/'); | ||
| 163 | - } | ||
| 164 | - | ||
| 165 | - // To be called during pre-execution when --expose-internals is on. | ||
| 166 | - // Enables the user-land module loader to access internal modules. | ||
| 167 | - NativeModule.exposeInternals = function() { | ||
| 168 | - for (const [id, mod] of NativeModule.map) { | ||
| 169 | - // Do not expose this to user land even with --expose-internals. | ||
| 170 | - if (id !== loaderId) { | ||
| 171 | - mod.canBeRequiredByUsers = true; | ||
| 172 | - } | ||
| 173 | - } | ||
| 174 | - }; | ||
| 175 | - | ||
| 176 | 144 | const { | |
| 177 | 145 | moduleIds, | |
| 178 | 146 | compileFunction | |
| 179 | 147 | } = internalBinding('native_module'); | |
| 180 | 148 | ||
| 181 | - NativeModule.map = new Map(); | ||
| 182 | - for (let i = 0; i < moduleIds.length; ++i) { | ||
| 183 | - const id = moduleIds[i]; | ||
| 184 | - const mod = new NativeModule(id); | ||
| 185 | - NativeModule.map.set(id, mod); | ||
| 186 | - } | ||
| 149 | + const getOwn = (target, property, receiver) => { | ||
| 150 | + return ObjectPrototypeHasOwnProperty(target, property) ? | ||
| 151 | + ReflectGet(target, property, receiver) : | ||
| 152 | + undefined; | ||
| 153 | + }; | ||
| 187 | 154 | ||
| 188 | - function nativeModuleRequire(id) { | ||
| 189 | - if (id === loaderId) { | ||
| 190 | - return loaderExports; | ||
| 155 | + /** | ||
| 156 | + * An internal abstraction for the built-in JavaScript modules of Node.js. | ||
| 157 | + * Be careful not to expose this to user land unless --expose-internals is | ||
| 158 | + * used, in which case there is no compatibility guarantee about this class. | ||
| 159 | + */ | ||
| 160 | + class NativeModule { | ||
| 161 | + /** | ||
| 162 | + * A map from the module IDs to the module instances. | ||
| 163 | + * @type {Map<string, NativeModule>} | ||
| 164 | + */ | ||
| 165 | + static map = new Map(moduleIds.map((id) => [id, new NativeModule(id)])); | ||
| 166 | + | ||
| 167 | + constructor(id) { | ||
| 168 | + this.filename = `${id}.js`; | ||
| 169 | + this.id = id; | ||
| 170 | + this.canBeRequiredByUsers = !id.startsWith('internal/'); | ||
| 171 | + | ||
| 172 | + // The CJS exports object of the module. | ||
| 173 | + this.exports = {}; | ||
| 174 | + // States used to work around circular dependencies. | ||
| 175 | + this.loaded = false; | ||
| 176 | + this.loading = false; | ||
| 177 | + | ||
| 178 | + // The following properties are used by the ESM implementation and only | ||
| 179 | + // initialized when the native module is loaded by users. | ||
| 180 | + /** | ||
| 181 | + * The C++ ModuleWrap binding used to interface with the ESM implementation. | ||
| 182 | + * @type {ModuleWrap|undefined} | ||
| 183 | + */ | ||
| 184 | + this.module = undefined; | ||
| 185 | + /** | ||
| 186 | + * Exported names for the ESM imports. | ||
| 187 | + * @type {string[]|undefined} | ||
| 188 | + */ | ||
| 189 | + this.exportKeys = undefined; | ||
| 191 | 190 | } | |
| 192 | 191 | ||
| 193 | - const mod = NativeModule.map.get(id); | ||
| 194 | - // Can't load the internal errors module from here, have to use a raw error. | ||
| 195 | - // eslint-disable-next-line no-restricted-syntax | ||
| 196 | - if (!mod) throw new TypeError(`Missing internal module '${id}'`); | ||
| 197 | - return mod.compile(); | ||
| 198 | - } | ||
| 192 | + // To be called during pre-execution when --expose-internals is on. | ||
| 193 | + // Enables the user-land module loader to access internal modules. | ||
| 194 | + static exposeInternals() { | ||
| 195 | + for (const [id, mod] of NativeModule.map) { | ||
| 196 | + // Do not expose this to user land even with --expose-internals. | ||
| 197 | + if (id !== loaderId) { | ||
| 198 | + mod.canBeRequiredByUsers = true; | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + } | ||
| 199 | 202 | ||
| 200 | - NativeModule.exists = function(id) { | ||
| 201 | - return NativeModule.map.has(id); | ||
| 202 | - }; | ||
| 203 | + static exists(id) { | ||
| 204 | + return NativeModule.map.has(id); | ||
| 205 | + } | ||
| 203 | 206 | ||
| 204 | - NativeModule.canBeRequiredByUsers = function(id) { | ||
| 205 | - const mod = NativeModule.map.get(id); | ||
| 206 | - return mod && mod.canBeRequiredByUsers; | ||
| 207 | - }; | ||
| 207 | + static canBeRequiredByUsers(id) { | ||
| 208 | + const mod = NativeModule.map.get(id); | ||
| 209 | + return mod && mod.canBeRequiredByUsers; | ||
| 210 | + } | ||
| 208 | 211 | ||
| 209 | - // Allow internal modules from dependencies to require | ||
| 210 | - // other modules from dependencies by providing fallbacks. | ||
| 211 | - function requireWithFallbackInDeps(request) { | ||
| 212 | - if (!NativeModule.map.has(request)) { | ||
| 213 | - request = `internal/deps/${request}`; | ||
| 212 | + // Used by user-land module loaders to compile and load builtins. | ||
| 213 | + compileForPublicLoader(needToSyncExports) { | ||
| 214 | + if (!this.canBeRequiredByUsers) { | ||
| 215 | + // No code because this is an assertion against bugs | ||
| 216 | + // eslint-disable-next-line no-restricted-syntax | ||
| 217 | + throw new Error(`Should not compile ${this.id} for public use`); | ||
| 218 | + } | ||
| 219 | + this.compileForInternalLoader(); | ||
| 220 | + if (needToSyncExports) { | ||
| 221 | + if (!this.exportKeys) { | ||
| 222 | + // When using --expose-internals, we do not want to reflect the named | ||
| 223 | + // exports from core modules as this can trigger unnecessary getters. | ||
| 224 | + const internal = this.id.startsWith('internal/'); | ||
| 225 | + this.exportKeys = internal ? [] : ObjectKeys(this.exports); | ||
| 226 | + } | ||
| 227 | + this.getESMFacade(); | ||
| 228 | + this.syncExports(); | ||
| 229 | + } | ||
| 230 | + return this.exports; | ||
| 214 | 231 | } | |
| 215 | - return nativeModuleRequire(request); | ||
| 216 | - } | ||
| 217 | 232 | ||
| 218 | - // This is exposed for public loaders | ||
| 219 | - NativeModule.prototype.compileForPublicLoader = function(needToSyncExports) { | ||
| 220 | - if (!this.canBeRequiredByUsers) { | ||
| 221 | - // No code because this is an assertion against bugs | ||
| 222 | - // eslint-disable-next-line no-restricted-syntax | ||
| 223 | - throw new Error(`Should not compile ${this.id} for public use`); | ||
| 233 | + getESMFacade() { | ||
| 234 | + if (this.module) return this.module; | ||
| 235 | + const { ModuleWrap } = internalBinding('module_wrap'); | ||
| 236 | + const url = `node:${this.id}`; | ||
| 237 | + const nativeModule = this; | ||
| 238 | + this.module = new ModuleWrap( | ||
| 239 | + url, undefined, [...this.exportKeys, 'default'], | ||
| 240 | + function() { | ||
| 241 | + nativeModule.syncExports(); | ||
| 242 | + this.setExport('default', nativeModule.exports); | ||
| 243 | + }); | ||
| 244 | + // Ensure immediate sync execution to capture exports now | ||
| 245 | + this.module.instantiate(); | ||
| 246 | + this.module.evaluate(-1, false); | ||
| 247 | + return this.module; | ||
| 224 | 248 | } | |
| 225 | - this.compile(); | ||
| 226 | - if (needToSyncExports) { | ||
| 227 | - if (!this.exportKeys) { | ||
| 228 | - // When using --expose-internals, we do not want to reflect the named | ||
| 229 | - // exports from core modules as this can trigger unnecessary getters. | ||
| 230 | - const internal = this.id.startsWith('internal/'); | ||
| 231 | - this.exportKeys = internal ? [] : ObjectKeys(this.exports); | ||
| 249 | + | ||
| 250 | + // Provide named exports for all builtin libraries so that the libraries | ||
| 251 | + // may be imported in a nicer way for ESM users. The default export is left | ||
| 252 | + // as the entire namespace (module.exports) and updates when this function is | ||
| 253 | + // called so that APMs and other behavior are supported. | ||
| 254 | + syncExports() { | ||
| 255 | + const names = this.exportKeys; | ||
| 256 | + if (this.module) { | ||
| 257 | + for (let i = 0; i < names.length; i++) { | ||
| 258 | + const exportName = names[i]; | ||
| 259 | + if (exportName === 'default') continue; | ||
| 260 | + this.module.setExport(exportName, | ||
| 261 | + getOwn(this.exports, exportName, this.exports)); | ||
| 262 | + } | ||
| 232 | 263 | } | |
| 233 | - this.getESMFacade(); | ||
| 234 | - this.syncExports(); | ||
| 235 | 264 | } | |
| 236 | - return this.exports; | ||
| 237 | - }; | ||
| 238 | 265 | ||
| 239 | - const getOwn = (target, property, receiver) => { | ||
| 240 | - return ObjectPrototypeHasOwnProperty(target, property) ? | ||
| 241 | - ReflectGet(target, property, receiver) : | ||
| 242 | - undefined; | ||
| 243 | - }; | ||
| 266 | + compileForInternalLoader() { | ||
| 267 | + if (this.loaded || this.loading) { | ||
| 268 | + return this.exports; | ||
| 269 | + } | ||
| 244 | 270 | ||
| 245 | - NativeModule.prototype.getURL = function() { | ||
| 246 | - return `node:${this.id}`; | ||
| 247 | - }; | ||
| 271 | + const id = this.id; | ||
| 272 | + this.loading = true; | ||
| 248 | 273 | ||
| 249 | - NativeModule.prototype.getESMFacade = function() { | ||
| 250 | - if (this.module) return this.module; | ||
| 251 | - const { ModuleWrap } = internalBinding('module_wrap'); | ||
| 252 | - const url = this.getURL(); | ||
| 253 | - const nativeModule = this; | ||
| 254 | - this.module = new ModuleWrap( | ||
| 255 | - url, undefined, [...this.exportKeys, 'default'], | ||
| 256 | - function() { | ||
| 257 | - nativeModule.syncExports(); | ||
| 258 | - this.setExport('default', nativeModule.exports); | ||
| 259 | - }); | ||
| 260 | - // Ensure immediate sync execution to capture exports now | ||
| 261 | - this.module.instantiate(); | ||
| 262 | - this.module.evaluate(-1, false); | ||
| 263 | - return this.module; | ||
| 264 | - }; | ||
| 274 | + try { | ||
| 275 | + const requireFn = this.id.startsWith('internal/deps/') ? | ||
| 276 | + requireWithFallbackInDeps : nativeModuleRequire; | ||
| 265 | 277 | ||
| 266 | - // Provide named exports for all builtin libraries so that the libraries | ||
| 267 | - // may be imported in a nicer way for ESM users. The default export is left | ||
| 268 | - // as the entire namespace (module.exports) and updates when this function is | ||
| 269 | - // called so that APMs and other behavior are supported. | ||
| 270 | - NativeModule.prototype.syncExports = function() { | ||
| 271 | - const names = this.exportKeys; | ||
| 272 | - if (this.module) { | ||
| 273 | - for (let i = 0; i < names.length; i++) { | ||
| 274 | - const exportName = names[i]; | ||
| 275 | - if (exportName === 'default') continue; | ||
| 276 | - this.module.setExport(exportName, | ||
| 277 | - getOwn(this.exports, exportName, this.exports)); | ||
| 278 | + const fn = compileFunction(id); | ||
| 279 | + fn(this.exports, requireFn, this, process, internalBinding, primordials); | ||
| 280 | + | ||
| 281 | + this.loaded = true; | ||
| 282 | + } finally { | ||
| 283 | + this.loading = false; | ||
| 278 | 284 | } | |
| 279 | - } | ||
| 280 | - }; | ||
| 281 | 285 | ||
| 282 | - NativeModule.prototype.compile = function() { | ||
| 283 | - if (this.loaded || this.loading) { | ||
| 286 | + moduleLoadList.push(`NativeModule ${id}`); | ||
| 284 | 287 | return this.exports; | |
| 285 | 288 | } | |
| 289 | + } | ||
| 286 | 290 | ||
| 287 | - const id = this.id; | ||
| 288 | - this.loading = true; | ||
| 291 | + // Think of this as module.exports in this file even though it is not | ||
| 292 | + // written in CommonJS style. | ||
| 293 | + const loaderExports = { | ||
| 294 | + internalBinding, | ||
| 295 | + NativeModule, | ||
| 296 | + require: nativeModuleRequire | ||
| 297 | + }; | ||
| 289 | 298 | ||
| 290 | - try { | ||
| 291 | - const requireFn = this.id.startsWith('internal/deps/') ? | ||
| 292 | - requireWithFallbackInDeps : nativeModuleRequire; | ||
| 299 | + function nativeModuleRequire(id) { | ||
| 300 | + if (id === loaderId) { | ||
| 301 | + return loaderExports; | ||
| 302 | + } | ||
| 293 | 303 | ||
| 294 | - const fn = compileFunction(id); | ||
| 295 | - fn(this.exports, requireFn, this, process, internalBinding, primordials); | ||
| 304 | + const mod = NativeModule.map.get(id); | ||
| 305 | + // Can't load the internal errors module from here, have to use a raw error. | ||
| 306 | + // eslint-disable-next-line no-restricted-syntax | ||
| 307 | + if (!mod) throw new TypeError(`Missing internal module '${id}'`); | ||
| 308 | + return mod.compileForInternalLoader(); | ||
| 309 | + } | ||
| 296 | 310 | ||
| 297 | - this.loaded = true; | ||
| 298 | - } finally { | ||
| 299 | - this.loading = false; | ||
| 311 | + // Allow internal modules from dependencies to require | ||
| 312 | + // other modules from dependencies by providing fallbacks. | ||
| 313 | + function requireWithFallbackInDeps(request) { | ||
| 314 | + if (!NativeModule.map.has(request)) { | ||
| 315 | + request = `internal/deps/${request}`; | ||
| 300 | 316 | } | |
| 317 | + return nativeModuleRequire(request); | ||
| 318 | + } | ||
| 301 | 319 | ||
| 302 | - moduleLoadList.push(`NativeModule ${id}`); | ||
| 303 | - return this.exports; | ||
| 304 | - }; | ||
| 305 | - | ||
| 306 | - // This will be passed to internal/bootstrap/node.js. | ||
| 320 | + // Pass the exports back to C++ land for C++ internals to use. | ||
| 307 | 321 | return loaderExports; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments