|
16 | 16 | #include <memory> |
17 | 17 |
|
18 | 18 | struct node_napi_env__ : public napi_env__ { |
19 | | - explicit node_napi_env__(v8::Local<v8::Context> context): |
20 | | - napi_env__(context) { |
| 19 | + explicit node_napi_env__(v8::Local<v8::Context> context, |
| 20 | + const std::string& module_filename): |
| 21 | + napi_env__(context), filename(module_filename) { |
21 | 22 | CHECK_NOT_NULL(node_env()); |
22 | 23 | } |
23 | 24 |
|
@@ -52,6 +53,10 @@ struct node_napi_env__ : public napi_env__ { |
52 | 53 | }); |
53 | 54 | }); |
54 | 55 | } |
| 56 | + |
| 57 | + const char* GetFilename() const { return filename.c_str(); } |
| 58 | + |
| 59 | + std::string filename; |
55 | 60 | }; |
56 | 61 |
|
57 | 62 | typedef node_napi_env__* node_napi_env; |
@@ -93,10 +98,11 @@ class BufferFinalizer : private Finalizer { |
93 | 98 | }; |
94 | 99 | }; |
95 | 100 |
|
96 | | -static inline napi_env NewEnv(v8::Local<v8::Context> context) { |
| 101 | +static inline napi_env |
| 102 | +NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) { |
97 | 103 | node_napi_env result; |
98 | 104 |
|
99 | | - result = new node_napi_env__(context); |
| 105 | + result = new node_napi_env__(context, module_filename); |
100 | 106 | // TODO(addaleax): There was previously code that tried to delete the |
101 | 107 | // napi_env when its v8::Context was garbage collected; |
102 | 108 | // However, as long as N-API addons using this napi_env are in place, |
@@ -579,16 +585,35 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports, |
579 | 585 | v8::Local<v8::Value> module, |
580 | 586 | v8::Local<v8::Context> context, |
581 | 587 | napi_addon_register_func init) { |
| 588 | + node::Environment* node_env = node::Environment::GetCurrent(context); |
| 589 | + std::string module_filename = ""; |
582 | 590 | if (init == nullptr) { |
583 | | - node::Environment* node_env = node::Environment::GetCurrent(context); |
584 | 591 | CHECK_NOT_NULL(node_env); |
585 | 592 | node_env->ThrowError( |
586 | 593 | "Module has no declared entry point."); |
587 | 594 | return; |
588 | 595 | } |
589 | 596 |
|
| 597 | + // We set `env->filename` from `module.filename` here, but we could just as |
| 598 | + // easily add a private property to `exports` in `process.dlopen`, which |
| 599 | + // receives the file name from JS, and retrieve *that* here. Thus, we are not |
| 600 | + // endorsing commonjs here by making use of `module.filename`. |
| 601 | + v8::Local<v8::Value> filename_js; |
| 602 | + v8::Local<v8::Object> modobj; |
| 603 | + if (module->ToObject(context).ToLocal(&modobj) && |
| 604 | + modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) && |
| 605 | + filename_js->IsString()) { |
| 606 | + node::Utf8Value filename(node_env->isolate(), filename_js); // Cast |
| 607 | + |
| 608 | + // Turn the absolute path into a URL. Currently the absolute path is always |
| 609 | + // a file system path. |
| 610 | + // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we |
| 611 | + // receive it as a URL already. |
| 612 | + module_filename = std::string("file://") + (*filename); |
| 613 | + } |
| 614 | + |
590 | 615 | // Create a new napi_env for this specific module. |
591 | | - napi_env env = v8impl::NewEnv(context); |
| 616 | + napi_env env = v8impl::NewEnv(context, module_filename); |
592 | 617 |
|
593 | 618 | napi_value _exports; |
594 | 619 | env->CallIntoModule([&](napi_env env) { |
@@ -1287,3 +1312,11 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) { |
1287 | 1312 | CHECK_NOT_NULL(func); |
1288 | 1313 | return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref(); |
1289 | 1314 | } |
| 1315 | + |
| 1316 | +napi_status node_api_get_module_file_name(napi_env env, const char** result) { |
| 1317 | + CHECK_ENV(env); |
| 1318 | + CHECK_ARG(env, result); |
| 1319 | + |
| 1320 | + *result = static_cast<node_napi_env>(env)->GetFilename(); |
| 1321 | + return napi_clear_last_error(env); |
| 1322 | +} |
0 commit comments