diff --git a/src/node_dotenv.cc b/src/node_dotenv.cc index 049f5cfcb77b9c..fcad2f23f50557 100644 --- a/src/node_dotenv.cc +++ b/src/node_dotenv.cc @@ -105,15 +105,22 @@ Local Dotenv::ToObject(Environment* env) const { return result; } +// Removes space characters (spaces, tabs and newlines) from +// the start and end of a given input string std::string_view trim_spaces(std::string_view input) { if (input.empty()) return ""; - if (input.front() == ' ') { - input.remove_prefix(input.find_first_not_of(' ')); + + auto pos_start = input.find_first_not_of(" \t\n"); + if (pos_start == std::string_view::npos) { + return ""; } - if (!input.empty() && input.back() == ' ') { - input = input.substr(0, input.find_last_not_of(' ') + 1); + + auto pos_end = input.find_last_not_of(" \t\n"); + if (pos_end == std::string_view::npos) { + return input.substr(pos_start); } - return input; + + return input.substr(pos_start, pos_end - pos_start + 1); } void Dotenv::ParseContent(const std::string_view input) { @@ -147,6 +154,13 @@ void Dotenv::ParseContent(const std::string_view input) { key = content.substr(0, equal); content.remove_prefix(equal + 1); key = trim_spaces(key); + + // If the value is not present (e.g. KEY=) set is to an empty string + if (content.front() == '\n') { + store_.insert_or_assign(std::string(key), ""); + continue; + } + content = trim_spaces(content); if (key.empty()) { diff --git a/test/fixtures/dotenv/lines-with-only-spaces.env b/test/fixtures/dotenv/lines-with-only-spaces.env new file mode 100644 index 00000000000000..5eeb5f48f53ff1 --- /dev/null +++ b/test/fixtures/dotenv/lines-with-only-spaces.env @@ -0,0 +1,8 @@ + +EMPTY_LINE='value after an empty line' + +SPACES_LINE='value after a line with just some spaces' + +TABS_LINE='value after a line with just some tabs' + +SPACES_TABS_LINE='value after a line with just some spaces and tabs' diff --git a/test/parallel/test-dotenv-edge-cases.js b/test/parallel/test-dotenv-edge-cases.js index 926c8d0793ac8b..99f6687d677b7c 100644 --- a/test/parallel/test-dotenv-edge-cases.js +++ b/test/parallel/test-dotenv-edge-cases.js @@ -137,6 +137,25 @@ describe('.env supports edge cases', () => { assert.strictEqual(child.code, 0); }); + it('should handle lines that come after lines with only spaces (and tabs)', async () => { + // Ref: https://github.com/nodejs/node/issues/56686 + const code = ` + process.loadEnvFile('./lines-with-only-spaces.env'); + assert.strictEqual(process.env.EMPTY_LINE, 'value after an empty line'); + assert.strictEqual(process.env.SPACES_LINE, 'value after a line with just some spaces'); + assert.strictEqual(process.env.TABS_LINE, 'value after a line with just some tabs'); + assert.strictEqual(process.env.SPACES_TABS_LINE, 'value after a line with just some spaces and tabs'); + `.trim(); + const child = await common.spawnPromisified( + process.execPath, + [ '--eval', code ], + { cwd: fixtures.path('dotenv') }, + ); + assert.strictEqual(child.stdout, ''); + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + }); + it('should handle when --env-file is passed along with --', async () => { const child = await common.spawnPromisified( process.execPath,