Skip to content

Commit 00927c3

Browse files
committed
util: add loadEnvFile programmatic API
1 parent 477d6d7 commit 00927c3

File tree

13 files changed

+235
-1
lines changed

13 files changed

+235
-1
lines changed

doc/api/util.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3305,6 +3305,29 @@ util.isUndefined(null);
33053305
// Returns: false
33063306
```
33073307
3308+
### `util.loadEnvFile(path)`
3309+
3310+
<!-- YAML
3311+
added: REPLACEME
3312+
-->
3313+
3314+
> Stability: 1.1 - Active Development
3315+
3316+
* `path` {string | undefined}
3317+
3318+
Loads the `.env` file into `process.env`. By default the path is resolved to
3319+
`path.resolve(process.cwd(), '.env')`. If file is not found, no error is thrown.
3320+
3321+
```cjs
3322+
const util = require('node:util');
3323+
util.loadEnvFile();
3324+
```
3325+
3326+
```mjs
3327+
import util from 'node:util';
3328+
util.loadEnvFile();
3329+
```
3330+
33083331
### `util.log(string)`
33093332
33103333
<!-- YAML

lib/util.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const { debuglog } = require('internal/util/debuglog');
6767
const {
6868
validateFunction,
6969
validateNumber,
70+
validateString,
7071
} = require('internal/validators');
7172
const { isBuffer } = require('buffer').Buffer;
7273
const types = require('internal/util/types');
@@ -371,6 +372,23 @@ function _exceptionWithHostPort(...args) {
371372
return new ExceptionWithHostPort(...args);
372373
}
373374

375+
let dotenv;
376+
377+
/**
378+
* Loads the .env file from the given path.
379+
* @param {string | undefined} path
380+
* @returns {void}
381+
*/
382+
function loadEnvFile(path) {
383+
dotenv ??= internalBinding('dotenv');
384+
if (path != null) {
385+
validateString(path, 'path');
386+
dotenv.load(path);
387+
} else {
388+
dotenv.load();
389+
}
390+
}
391+
374392
// Keep the `exports =` so that various functions can still be monkeypatched
375393
module.exports = {
376394
_errnoException,
@@ -465,6 +483,7 @@ module.exports = {
465483
return lazyAbortController().aborted;
466484
},
467485
types,
486+
loadEnvFile,
468487
};
469488

470489
defineLazyProperties(

src/base_object_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ namespace node {
1818
V(process_binding_data, process::BindingData) \
1919
V(timers_binding_data, timers::BindingData) \
2020
V(url_binding_data, url::BindingData) \
21-
V(modules_binding_data, modules::BindingData)
21+
V(modules_binding_data, modules::BindingData) \
22+
V(dotenv_binding_data, dotenv::BindingData)
2223

2324
#define UNSERIALIZABLE_BINDING_TYPES(V) \
2425
V(http2_binding_data, http2::BindingData) \

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
V(constants) \
3838
V(contextify) \
3939
V(credentials) \
40+
V(dotenv) \
4041
V(encoding_binding) \
4142
V(errors) \
4243
V(fs) \

src/node_binding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
4141
V(blob) \
4242
V(builtins) \
4343
V(contextify) \
44+
V(dotenv) \
4445
V(encoding_binding) \
4546
V(fs) \
4647
V(fs_dir) \

src/node_dotenv.cc

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
#include "node_dotenv.h"
22
#include "env-inl.h"
33
#include "node_file.h"
4+
#include "util.h"
45
#include "uv.h"
6+
#include "v8.h"
57

68
namespace node {
79

10+
using v8::Context;
11+
using v8::FunctionCallbackInfo;
12+
using v8::HandleScope;
13+
using v8::Isolate;
14+
using v8::Local;
815
using v8::NewStringType;
16+
using v8::Object;
17+
using v8::ObjectTemplate;
918
using v8::String;
19+
using v8::Value;
1020

1121
std::vector<std::string> Dotenv::GetPathFromArgs(
1222
const std::vector<std::string>& args) {
@@ -167,4 +177,79 @@ void Dotenv::ParseLine(const std::string_view line) {
167177
store_.insert_or_assign(std::string(key), value);
168178
}
169179

180+
namespace dotenv {
181+
182+
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
183+
// Do nothing
184+
}
185+
186+
BindingData::BindingData(Realm* realm,
187+
v8::Local<v8::Object> object,
188+
InternalFieldInfo* info)
189+
: SnapshotableObject(realm, object, type_int) {}
190+
191+
bool BindingData::PrepareForSerialization(v8::Local<v8::Context> context,
192+
v8::SnapshotCreator* creator) {
193+
return true;
194+
}
195+
196+
InternalFieldInfoBase* BindingData::Serialize(int index) {
197+
DCHECK_IS_SNAPSHOT_SLOT(index);
198+
InternalFieldInfo* info =
199+
InternalFieldInfoBase::New<InternalFieldInfo>(type());
200+
return info;
201+
}
202+
203+
void BindingData::Deserialize(v8::Local<v8::Context> context,
204+
v8::Local<v8::Object> holder,
205+
int index,
206+
InternalFieldInfoBase* info) {
207+
DCHECK_IS_SNAPSHOT_SLOT(index);
208+
HandleScope scope(context->GetIsolate());
209+
Realm* realm = Realm::GetCurrent(context);
210+
BindingData* binding = realm->AddBindingData<BindingData>(holder);
211+
CHECK_NOT_NULL(binding);
212+
}
213+
214+
void BindingData::Load(const FunctionCallbackInfo<Value>& args) {
215+
Environment* env = Environment::GetCurrent(args);
216+
std::string path = ".env";
217+
if (args.Length() == 1) {
218+
CHECK(args[0]->IsString());
219+
Utf8Value path_value(args.GetIsolate(), args[0]);
220+
path = path_value.ToString();
221+
}
222+
223+
Dotenv dotenv{};
224+
dotenv.ParsePath(path);
225+
dotenv.SetEnvironment(env);
226+
}
227+
228+
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
229+
Local<ObjectTemplate> target) {
230+
Isolate* isolate = isolate_data->isolate();
231+
SetMethod(isolate, target, "load", Load);
232+
}
233+
234+
void BindingData::CreatePerContextProperties(Local<Object> target,
235+
Local<Value> unused,
236+
Local<Context> context,
237+
void* priv) {
238+
Realm* realm = Realm::GetCurrent(context);
239+
realm->AddBindingData<BindingData>(target);
240+
}
241+
242+
void BindingData::RegisterExternalReferences(
243+
ExternalReferenceRegistry* registry) {
244+
registry->Register(Load);
245+
}
246+
247+
} // namespace dotenv
170248
} // namespace node
249+
250+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
251+
dotenv, node::dotenv::BindingData::CreatePerContextProperties)
252+
NODE_BINDING_PER_ISOLATE_INIT(
253+
dotenv, node::dotenv::BindingData::CreatePerIsolateProperties)
254+
NODE_BINDING_EXTERNAL_REFERENCE(
255+
dotenv, node::dotenv::BindingData::RegisterExternalReferences)

src/node_dotenv.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

6+
#include "node.h"
7+
#include "node_snapshotable.h"
68
#include "util-inl.h"
9+
#include "v8.h"
710

811
#include <map>
912

@@ -30,6 +33,35 @@ class Dotenv {
3033
std::map<std::string, std::string> store_;
3134
};
3235

36+
class ExternalReferenceRegistry;
37+
38+
namespace dotenv {
39+
class BindingData : public SnapshotableObject {
40+
public:
41+
using InternalFieldInfo = InternalFieldInfoBase;
42+
43+
BindingData(Realm* realm,
44+
v8::Local<v8::Object> obj,
45+
InternalFieldInfo* info = nullptr);
46+
SERIALIZABLE_OBJECT_METHODS()
47+
SET_BINDING_ID(dotenv_binding_data)
48+
49+
void MemoryInfo(MemoryTracker* tracker) const override;
50+
SET_SELF_SIZE(BindingData)
51+
SET_MEMORY_INFO_NAME(BindingData)
52+
53+
static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
54+
55+
static void CreatePerIsolateProperties(IsolateData* isolate_data,
56+
v8::Local<v8::ObjectTemplate> ctor);
57+
static void CreatePerContextProperties(v8::Local<v8::Object> target,
58+
v8::Local<v8::Value> unused,
59+
v8::Local<v8::Context> context,
60+
void* priv);
61+
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
62+
};
63+
} // namespace dotenv
64+
3365
} // namespace node
3466

3567
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

src/node_external_reference.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class ExternalReferenceRegistry {
101101
V(cares_wrap) \
102102
V(contextify) \
103103
V(credentials) \
104+
V(dotenv) \
104105
V(encoding_binding) \
105106
V(env_var) \
106107
V(errors) \

src/node_snapshotable.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "node_blob.h"
1515
#include "node_builtins.h"
1616
#include "node_contextify.h"
17+
#include "node_dotenv.h"
1718
#include "node_errors.h"
1819
#include "node_external_reference.h"
1920
#include "node_file.h"

test/fixtures/dotenv/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
BASIC=basic

0 commit comments

Comments
 (0)