Skip to content

Commit f3c43ec

Browse files
melegatiJorge Melegati
and
Jorge Melegati
authoredDec 15, 2024··
Handling real multi line entries. (#78)
* Handling real multi line entries. * Using equals to compare objects. --------- Co-authored-by: Jorge Melegati <jorge@jmelegati.com>
1 parent 655d880 commit f3c43ec

File tree

5 files changed

+77
-32
lines changed

5 files changed

+77
-32
lines changed
 

‎src/main/java/io/github/cdimascio/dotenv/internal/DotenvParser.java

+50-27
Original file line numberDiff line numberDiff line change
@@ -60,33 +60,41 @@ public DotenvParser(final DotenvReader reader, final boolean throwIfMissing, fin
6060
*/
6161
public List<DotenvEntry> parse() throws DotenvException {
6262
final var lines = lines();
63-
final var entries = new ArrayList<DotenvEntry>(lines.size());
63+
final var entries = new ArrayList<DotenvEntry>();
64+
65+
var currentEntry = "";
6466
for (final var line : lines) {
65-
addNewEntry(entries, line.trim());
66-
}
67+
if (currentEntry.equals("") && (isWhiteSpace.test(line) || isComment.test(line) || isBlank(line)))
68+
continue;
6769

68-
return entries;
69-
}
70+
currentEntry += line;
7071

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

75-
final var entry = parseLine.apply(line);
76-
if (entry == null) {
77-
if (throwIfMalformed)
78-
throw new DotenvException("Malformed entry " + line);
79-
return;
80+
var value = entry.getValue();
81+
if (QuotedStringValidator.startsWithQuote(value) && !QuotedStringValidator.endsWithQuote(value)) {
82+
currentEntry += "\n";
83+
continue;
84+
}
85+
if (!QuotedStringValidator.isValid(entry.getValue())) {
86+
if (throwIfMalformed)
87+
throw new DotenvException("Malformed entry, unmatched quotes " + line);
88+
currentEntry = "";
89+
continue;
90+
}
91+
final var key = entry.getKey();
92+
value = QuotedStringValidator.stripQuotes(entry.getValue());
93+
entries.add(new DotenvEntry(key, value));
94+
currentEntry = "";
8095
}
8196

82-
if (!QuotedStringValidator.isValid(entry.getValue())) {
83-
if (throwIfMalformed)
84-
throw new DotenvException("Malformed entry, unmatched quotes " + line);
85-
return;
86-
}
87-
final var key = entry.getKey();
88-
final var value = QuotedStringValidator.stripQuotes(entry.getValue());
89-
entries.add(new DotenvEntry(key, value));
97+
return entries;
9098
}
9199

92100
private List<String> lines() throws DotenvException {
@@ -123,14 +131,17 @@ private static boolean isBlank(String s) {
123131
private static class QuotedStringValidator {
124132
private static boolean isValid(String input) {
125133
final var s = input.trim();
126-
if (!s.startsWith("\"") && !s.endsWith("\"")) {
127-
// not quoted, its valid
134+
if (isNotQuoted(s)) {
128135
return true;
129136
}
130-
if (input.length() == 1 || !(s.startsWith("\"") && s.endsWith("\""))) {
131-
// doesn't start and end with quote
137+
if (doesNotStartAndEndWithQuote(s)) {
132138
return false;
133139
}
140+
141+
return !hasUnescapedQuote(s); // No unescaped quotes found
142+
}
143+
private static boolean hasUnescapedQuote(final String s) {
144+
boolean hasUnescapedQuote = false;
134145
// remove start end quote
135146
var content = s.substring(1, s.length() - 1);
136147
var quotePattern = Pattern.compile("\"");
@@ -141,10 +152,22 @@ private static boolean isValid(String input) {
141152
int quoteIndex = matcher.start();
142153
// Check if the quote is escaped
143154
if (quoteIndex == 0 || content.charAt(quoteIndex - 1) != '\\') {
144-
return false; // unescaped quote found
155+
hasUnescapedQuote = true; // unescaped quote found
145156
}
146157
}
147-
return true; // No unescaped quotes found
158+
return hasUnescapedQuote;
159+
}
160+
private static boolean doesNotStartAndEndWithQuote(final String s) {
161+
return s.length() == 1 || !(startsWithQuote(s) && endsWithQuote(s));
162+
}
163+
private static boolean endsWithQuote(final String s) {
164+
return s.endsWith("\"");
165+
}
166+
private static boolean startsWithQuote(final String s) {
167+
return s.startsWith("\"");
168+
}
169+
private static boolean isNotQuoted(final String s) {
170+
return !startsWithQuote(s) && !endsWithQuote(s);
148171
}
149172
private static String stripQuotes(String input) {
150173
var tr = input.trim();

‎src/test/java/tests/BasicTests.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ class BasicTests {
1414
put("MY_TEST_EV1", "my test ev 1");
1515
put("MY_TEST_EV2", "my test ev 2");
1616
put("WITHOUT_VALUE", "");
17-
put("MULTI_LINE", "hello\\nworld");
17+
put("MULTI_LINE", "hello\nworld\nmulti");
18+
put("TWO_LINE", "hello\nworld");
1819
put("TRAILING_COMMENT", "value");
1920
put("QUOTED_VALUE", "iH4>hb_d0#_GN8d]6");
21+
put("MY_TEST_EV4", "my test ev 4");
22+
put("MULTI_LINE_WITH_SHARP", "hello\n#world");
2023
}};
2124

2225
@Test

‎src/test/java/tests/DotenvTests.java

-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ void malformedWithUncloseQuote() {
110110
.load();
111111

112112
assertNull(dotenv.get("FOO"));
113-
assertEquals(dotenv.get("BAR"), "bar");
114113
assertNull(dotenv.get("BAZ"), "baz");
115114
}
116115
}

‎src/test/resources/.env

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22
MY_TEST_EV1=my test ev 1
33
MY_TEST_EV2=my test ev 2
44
WITHOUT_VALUE=
5-
MULTI_LINE=hello\nworld
5+
MULTI_LINE="hello
6+
world
7+
multi"
8+
TWO_LINE="hello
9+
world"
610
TRAILING_COMMENT=value # comment
711
QUOTED_VALUE="iH4>hb_d0#_GN8d]6" # comment "test"
812

9-
## Malformed EV!
13+
## Malformed EVs!
1014
MY_TEST_EV3
15+
MISSING_START_QUOTE=teste"
16+
17+
## Good EV after malformed
18+
MY_TEST_EV4="my test ev 4"
19+
MULTI_LINE_WITH_SHARP="hello
20+
#world"
1121

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

‎src/test/resources/env

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@
22
MY_TEST_EV1=my test ev 1
33
MY_TEST_EV2=my test ev 2
44
WITHOUT_VALUE=
5-
MULTI_LINE=hello\nworld
5+
MULTI_LINE="hello
6+
world
7+
multi"
8+
TWO_LINE="hello
9+
world"
610
TRAILING_COMMENT=value # comment
711
QUOTED_VALUE="iH4>hb_d0#_GN8d]6" # comment "test"
812

913
## Malformed EV!
1014
MY_TEST_EV3
15+
MISSING_START_QUOTE=teste"
16+
17+
## Good EV after malformed
18+
MY_TEST_EV4="my test ev 4"
19+
MULTI_LINE_WITH_SHARP="hello
20+
#world"

0 commit comments

Comments
 (0)
Please sign in to comment.