11package io .avaje .config ;
22
3+ import static java .util .stream .Collectors .joining ;
4+
35import java .io .IOException ;
46import java .io .InputStream ;
57import java .io .InputStreamReader ;
68import java .io .LineNumberReader ;
79import java .io .Reader ;
810import java .io .UncheckedIOException ;
11+ import java .util .ArrayDeque ;
912import java .util .ArrayList ;
13+ import java .util .Deque ;
14+ import java .util .Iterator ;
1015import java .util .LinkedHashMap ;
1116import java .util .List ;
1217import java .util .Map ;
13- import java .util .Stack ;
1418import java .util .StringJoiner ;
1519
1620import org .jspecify .annotations .NullMarked ;
@@ -42,12 +46,13 @@ enum MultiLineTrim {
4246 enum State {
4347 RequireKey ,
4448 MultiLine ,
49+ List ,
4550 KeyOrValue ,
4651 RequireTopKey
4752 }
4853
4954 private final Map <String , String > keyValues = new LinkedHashMap <>();
50- private final Stack <Key > keyStack = new Stack <>();
55+ private final Deque <Key > keyStack = new ArrayDeque <>();
5156 private final List <String > multiLines = new ArrayList <>();
5257
5358 private State state = State .RequireKey ;
@@ -80,7 +85,7 @@ private void processLine(String line) {
8085 } else {
8186 currentLine ++;
8287 readIndent (line );
83- if (state == State .MultiLine ) {
88+ if (state == State .MultiLine || state == State . List ) {
8489 processMultiLine (line );
8590 } else {
8691 processNext (line );
@@ -92,6 +97,9 @@ private void checkFinalMultiLine() {
9297 if (state == State .MultiLine ) {
9398 addKeyVal (multiLineValue ());
9499 }
100+ if (state == State .List ) {
101+ addKeyVal (listValue ());
102+ }
95103 }
96104
97105 private void processMultiLine (String line ) {
@@ -112,18 +120,32 @@ private void processMultiLine(String line) {
112120 }
113121
114122 private void multiLineEnd (String line ) {
115- addKeyVal (multiLineValue ());
123+ if (state == State .MultiLine ) addKeyVal (multiLineValue ());
124+ else {
125+ addKeyVal (listValue ());
126+ }
116127 processNext (line );
117128 }
118129
130+ private String listValue () {
131+ if (multiLines .isEmpty ()) {
132+ return "" ;
133+ }
134+ multiLineTrimTrailing ();
135+ var result =
136+ multiLines .stream ().map (s -> s .trim ().substring (1 ).stripLeading ()).collect (joining ("," ));
137+ multiLineEnd ();
138+ return result ;
139+ }
140+
119141 private String multiLineValue () {
120142 if (multiLines .isEmpty ()) {
121143 return "" ;
122144 }
123145 if (multiLineTrim != MultiLineTrim .Keep ) {
124146 multiLineTrimTrailing ();
125147 }
126- String join = ( multiLineTrim == MultiLineTrim .Implicit ) ? " " : "\n " ;
148+ String join = multiLineTrim == MultiLineTrim .Implicit ? " " : "\n " ;
127149 StringBuilder sb = new StringBuilder ();
128150 int lastIndex = multiLines .size () - 1 ;
129151 for (int i = 0 ; i <= lastIndex ; i ++) {
@@ -184,6 +206,8 @@ private void processNext(String line) {
184206 if (trimmedValue .startsWith ("|" )) {
185207 multilineStart (multiLineTrimMode (trimmedValue ));
186208
209+ } else if (trimmedValue .startsWith ("-" )) {
210+ listStart (multiLineTrimMode (trimmedValue ));
187211 } else if (trimmedValue .isEmpty () || trimmedValue .startsWith ("#" )) {
188212 // empty or comment
189213 state = State .KeyOrValue ;
@@ -230,7 +254,11 @@ private void processNonKey(String line) {
230254 if (currentIndent <= keyIndent ) {
231255 throw new IllegalStateException ("Value not indented enough for key " + fullKey () + " at line: " + currentLine + " line[" + line + "]" );
232256 }
233- multilineStart (MultiLineTrim .Implicit );
257+ if (line .stripLeading ().charAt (0 ) == '-' ) {
258+ listStart (MultiLineTrim .Implicit );
259+ } else {
260+ multilineStart (MultiLineTrim .Implicit );
261+ }
234262 multiLineIndent = currentIndent ;
235263 multiLines .add (line );
236264 }
@@ -241,6 +269,12 @@ private void multilineStart(MultiLineTrim trim) {
241269 multiLineTrim = trim ;
242270 }
243271
272+ private void listStart (MultiLineTrim trim ) {
273+ state = State .List ;
274+ multiLineIndent = 0 ;
275+ multiLineTrim = trim ;
276+ }
277+
244278 private void multiLineEnd () {
245279 state = State .RequireKey ;
246280 multiLineIndent = 0 ;
@@ -281,8 +315,9 @@ private String unquoteValue(char quoteChar, String value) {
281315
282316 private String fullKey () {
283317 StringJoiner fullKey = new StringJoiner ("." );
284- for (Key next : keyStack ) {
285- fullKey .add (next .key ());
318+ Iterator <Key > it = keyStack .descendingIterator ();
319+ while (it .hasNext ()) {
320+ fullKey .add (it .next ().key ());
286321 }
287322 return fullKey .toString ();
288323 }
@@ -302,10 +337,7 @@ private String trimKey(String indentKey) {
302337 }
303338
304339 private String unquoteKey (String value ) {
305- if (value .startsWith ("'" ) && value .endsWith ("'" )) {
306- return value .substring (1 , value .length () - 1 );
307- }
308- if (value .startsWith ("\" " ) && value .endsWith ("\" " )) {
340+ if (value .startsWith ("'" ) && value .endsWith ("'" ) || value .startsWith ("\" " ) && value .endsWith ("\" " )) {
309341 return value .substring (1 , value .length () - 1 );
310342 }
311343 return value ;
0 commit comments