Skip to content

Commit

Permalink
Handling real multi line entries. (#78)
Browse files Browse the repository at this point in the history
* Handling real multi line entries.

* Using equals to compare objects.

---------

Co-authored-by: Jorge Melegati <jorge@jmelegati.com>
  • Loading branch information
melegati and Jorge Melegati authored Dec 15, 2024
1 parent 655d880 commit f3c43ec
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 32 deletions.
77 changes: 50 additions & 27 deletions src/main/java/io/github/cdimascio/dotenv/internal/DotenvParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,33 +60,41 @@ public DotenvParser(final DotenvReader reader, final boolean throwIfMissing, fin
*/
public List<DotenvEntry> parse() throws DotenvException {
final var lines = lines();
final var entries = new ArrayList<DotenvEntry>(lines.size());
final var entries = new ArrayList<DotenvEntry>();

var currentEntry = "";
for (final var line : lines) {
addNewEntry(entries, line.trim());
}
if (currentEntry.equals("") && (isWhiteSpace.test(line) || isComment.test(line) || isBlank(line)))
continue;

return entries;
}
currentEntry += line;

private void addNewEntry(final List<DotenvEntry> entries, final String line) {
if (isWhiteSpace.test(line) || isComment.test(line) || isBlank(line))
return;
final var entry = parseLine.apply(currentEntry);
if (entry == null) {
if (throwIfMalformed)
throw new DotenvException("Malformed entry " + currentEntry);
currentEntry = "";
continue;
}

final var entry = parseLine.apply(line);
if (entry == null) {
if (throwIfMalformed)
throw new DotenvException("Malformed entry " + line);
return;
var value = entry.getValue();
if (QuotedStringValidator.startsWithQuote(value) && !QuotedStringValidator.endsWithQuote(value)) {
currentEntry += "\n";
continue;
}
if (!QuotedStringValidator.isValid(entry.getValue())) {
if (throwIfMalformed)
throw new DotenvException("Malformed entry, unmatched quotes " + line);
currentEntry = "";
continue;
}
final var key = entry.getKey();
value = QuotedStringValidator.stripQuotes(entry.getValue());
entries.add(new DotenvEntry(key, value));
currentEntry = "";
}

if (!QuotedStringValidator.isValid(entry.getValue())) {
if (throwIfMalformed)
throw new DotenvException("Malformed entry, unmatched quotes " + line);
return;
}
final var key = entry.getKey();
final var value = QuotedStringValidator.stripQuotes(entry.getValue());
entries.add(new DotenvEntry(key, value));
return entries;
}

private List<String> lines() throws DotenvException {
Expand Down Expand Up @@ -123,14 +131,17 @@ private static boolean isBlank(String s) {
private static class QuotedStringValidator {
private static boolean isValid(String input) {
final var s = input.trim();
if (!s.startsWith("\"") && !s.endsWith("\"")) {
// not quoted, its valid
if (isNotQuoted(s)) {
return true;
}
if (input.length() == 1 || !(s.startsWith("\"") && s.endsWith("\""))) {
// doesn't start and end with quote
if (doesNotStartAndEndWithQuote(s)) {
return false;
}

return !hasUnescapedQuote(s); // No unescaped quotes found
}
private static boolean hasUnescapedQuote(final String s) {
boolean hasUnescapedQuote = false;
// remove start end quote
var content = s.substring(1, s.length() - 1);
var quotePattern = Pattern.compile("\"");
Expand All @@ -141,10 +152,22 @@ private static boolean isValid(String input) {
int quoteIndex = matcher.start();
// Check if the quote is escaped
if (quoteIndex == 0 || content.charAt(quoteIndex - 1) != '\\') {
return false; // unescaped quote found
hasUnescapedQuote = true; // unescaped quote found
}
}
return true; // No unescaped quotes found
return hasUnescapedQuote;
}
private static boolean doesNotStartAndEndWithQuote(final String s) {
return s.length() == 1 || !(startsWithQuote(s) && endsWithQuote(s));
}
private static boolean endsWithQuote(final String s) {
return s.endsWith("\"");
}
private static boolean startsWithQuote(final String s) {
return s.startsWith("\"");
}
private static boolean isNotQuoted(final String s) {
return !startsWithQuote(s) && !endsWithQuote(s);
}
private static String stripQuotes(String input) {
var tr = input.trim();
Expand Down
5 changes: 4 additions & 1 deletion src/test/java/tests/BasicTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class BasicTests {
put("MY_TEST_EV1", "my test ev 1");
put("MY_TEST_EV2", "my test ev 2");
put("WITHOUT_VALUE", "");
put("MULTI_LINE", "hello\\nworld");
put("MULTI_LINE", "hello\nworld\nmulti");
put("TWO_LINE", "hello\nworld");
put("TRAILING_COMMENT", "value");
put("QUOTED_VALUE", "iH4>hb_d0#_GN8d]6");
put("MY_TEST_EV4", "my test ev 4");
put("MULTI_LINE_WITH_SHARP", "hello\n#world");
}};

@Test
Expand Down
1 change: 0 additions & 1 deletion src/test/java/tests/DotenvTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ void malformedWithUncloseQuote() {
.load();

assertNull(dotenv.get("FOO"));
assertEquals(dotenv.get("BAR"), "bar");
assertNull(dotenv.get("BAZ"), "baz");
}
}
14 changes: 12 additions & 2 deletions src/test/resources/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@
MY_TEST_EV1=my test ev 1
MY_TEST_EV2=my test ev 2
WITHOUT_VALUE=
MULTI_LINE=hello\nworld
MULTI_LINE="hello
world
multi"
TWO_LINE="hello
world"
TRAILING_COMMENT=value # comment
QUOTED_VALUE="iH4>hb_d0#_GN8d]6" # comment "test"

## Malformed EV!
## Malformed EVs!
MY_TEST_EV3
MISSING_START_QUOTE=teste"

## Good EV after malformed
MY_TEST_EV4="my test ev 4"
MULTI_LINE_WITH_SHARP="hello
#world"

QUOTED_EV1="jdbc:hive2://[domain]:10000/default;principal=hive/_HOST@[REALM]"

Expand Down
12 changes: 11 additions & 1 deletion src/test/resources/env
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
MY_TEST_EV1=my test ev 1
MY_TEST_EV2=my test ev 2
WITHOUT_VALUE=
MULTI_LINE=hello\nworld
MULTI_LINE="hello
world
multi"
TWO_LINE="hello
world"
TRAILING_COMMENT=value # comment
QUOTED_VALUE="iH4>hb_d0#_GN8d]6" # comment "test"

## Malformed EV!
MY_TEST_EV3
MISSING_START_QUOTE=teste"

## Good EV after malformed
MY_TEST_EV4="my test ev 4"
MULTI_LINE_WITH_SHARP="hello
#world"

0 comments on commit f3c43ec

Please sign in to comment.