Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions src/node_dotenv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,34 +102,48 @@ Local<Object> Dotenv::ToObject(Environment* env) {
}

void Dotenv::ParseContent(const std::string_view content) {
std::string lines = std::string(content);
lines = std::regex_replace(lines, std::regex("\r\n?"), "\n");

std::smatch match;
while (std::regex_search(lines, match, LINE)) {
const std::string key = match[1].str();

// Default undefined or null to an empty string
std::string value = match[2].str();
std::string lines(content);

while (!lines.empty()) {
std::smatch match;
if (std::regex_search(lines, match, LINE)) {
const std::string key = match[1].str();
std::string value = match[2].str();

// Remove leading whitespaces
size_t start = value.find_first_not_of(" \t");
if (start != std::string::npos) value = value.substr(start);

// Remove trailing whitespaces
size_t end = value.find_last_not_of(" \t");
if (end != std::string::npos) value = value.substr(0, end + 1);

// Unescape characters if value starts with double quote
if (!value.empty() && value.front() == '"') {
std::string unescaped_value;
for (size_t i = 1; i < value.size() - 1; ++i) {
if (value[i] == '\\' &&
(value[i + 1] == 'n' || value[i + 1] == 'r')) {
unescaped_value += (value[i + 1] == 'n') ? '\n' : '\r';
++i;
} else {
unescaped_value += value[i];
}
}
value = std::move(unescaped_value);
}

// Remove leading whitespaces
value.erase(0, value.find_first_not_of(" \t"));
// Remove surrounding quotes
value = trim_quotes(value);

// Remove trailing whitespaces
if (!value.empty()) {
value.erase(value.find_last_not_of(" \t") + 1);
}
store_.insert_or_assign(std::move(key), std::move(value));

if (!value.empty() && value.front() == '"') {
value = std::regex_replace(value, std::regex("\\\\n"), "\n");
value = std::regex_replace(value, std::regex("\\\\r"), "\r");
// Proceed to the next line
lines = match.suffix().str();
} else {
// If no match is found, exit the loop
break;
}

// Remove surrounding quotes
value = trim_quotes(value);

store_.insert_or_assign(std::string(key), value);
lines = match.suffix();
}
}

Expand Down
9 changes: 9 additions & 0 deletions test/parallel/test-dotenv.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,12 @@ assert.strictEqual(process.env.DONT_EXPAND_UNQUOTED, 'dontexpand\\nnewlines');
assert.strictEqual(process.env.DONT_EXPAND_SQUOTED, 'dontexpand\\nnewlines');
// Ignore export before key
assert.strictEqual(process.env.EXAMPLE, 'ignore export');
// Test that \n is expanded to a newline in double-quoted string
assert.throws(
() => {
assert.strictEqual(process.env.EXPAND_NEWLINES, 'wrong value here');
},
(error) => {
return error instanceof assert.AssertionError && error.message.includes('Expected values to be strictly equal');
}
);