mirror of
https://github.com/lightbend/config.git
synced 2025-02-15 13:50:24 +08:00
allow omitting curly braces on root object
This commit is contained in:
parent
39de5aa444
commit
4051d07870
@ -265,7 +265,7 @@ final class Parser {
|
||||
if (Tokens.isValue(token)) {
|
||||
return Tokens.getValue(token);
|
||||
} else if (token == Tokens.OPEN_CURLY) {
|
||||
return parseObject();
|
||||
return parseObject(true);
|
||||
} else if (token == Tokens.OPEN_SQUARE) {
|
||||
return parseArray();
|
||||
} else {
|
||||
@ -379,8 +379,8 @@ final class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractConfigObject parseObject() {
|
||||
// invoked just after the OPEN_CURLY
|
||||
private AbstractConfigObject parseObject(boolean hadOpenCurly) {
|
||||
// invoked just after the OPEN_CURLY (or START, if !hadOpenCurly)
|
||||
Map<String, AbstractConfigValue> values = new HashMap<String, AbstractConfigValue>();
|
||||
ConfigOrigin objectOrigin = lineOrigin();
|
||||
boolean afterComma = false;
|
||||
@ -389,8 +389,13 @@ final class Parser {
|
||||
if (t == Tokens.CLOSE_CURLY) {
|
||||
if (afterComma) {
|
||||
throw parseError("expecting a field name after comma, got a close brace }");
|
||||
} else if (!hadOpenCurly) {
|
||||
throw parseError("unbalanced close brace '}' with no open brace");
|
||||
}
|
||||
break;
|
||||
} else if (t == Tokens.END && !hadOpenCurly) {
|
||||
putBack(t);
|
||||
break;
|
||||
} else if (flavor != SyntaxFlavor.JSON && isIncludeKeyword(t)) {
|
||||
parseInclude(values);
|
||||
|
||||
@ -405,7 +410,7 @@ final class Parser {
|
||||
&& afterKey == Tokens.OPEN_CURLY) {
|
||||
// can omit the ':' or '=' before an object value
|
||||
valueToken = afterKey;
|
||||
newValue = parseObject();
|
||||
newValue = parseObject(true);
|
||||
} else {
|
||||
if (!isKeyValueSeparatorToken(afterKey)) {
|
||||
throw parseError("Key may not be followed by token: "
|
||||
@ -458,13 +463,24 @@ final class Parser {
|
||||
|
||||
t = nextTokenIgnoringNewline();
|
||||
if (t == Tokens.CLOSE_CURLY) {
|
||||
if (!hadOpenCurly) {
|
||||
throw parseError("unbalanced close brace '}' with no open brace");
|
||||
}
|
||||
break;
|
||||
} else if (t == Tokens.COMMA) {
|
||||
// continue looping
|
||||
afterComma = true;
|
||||
} else {
|
||||
} else if (hadOpenCurly) {
|
||||
throw parseError("Expecting close brace } or a comma, got "
|
||||
+ t);
|
||||
} else {
|
||||
if (t == Tokens.END) {
|
||||
putBack(t);
|
||||
break;
|
||||
} else {
|
||||
throw parseError("Expecting end of input or a comma, got "
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SimpleConfigObject(objectOrigin,
|
||||
@ -487,7 +503,7 @@ final class Parser {
|
||||
} else if (Tokens.isValue(t)) {
|
||||
values.add(parseValue(t));
|
||||
} else if (t == Tokens.OPEN_CURLY) {
|
||||
values.add(parseObject());
|
||||
values.add(parseObject(true));
|
||||
} else if (t == Tokens.OPEN_SQUARE) {
|
||||
values.add(parseArray());
|
||||
} else {
|
||||
@ -515,7 +531,7 @@ final class Parser {
|
||||
if (Tokens.isValue(t)) {
|
||||
values.add(parseValue(t));
|
||||
} else if (t == Tokens.OPEN_CURLY) {
|
||||
values.add(parseObject());
|
||||
values.add(parseObject(true));
|
||||
} else if (t == Tokens.OPEN_SQUARE) {
|
||||
values.add(parseArray());
|
||||
} else {
|
||||
@ -537,14 +553,24 @@ final class Parser {
|
||||
t = nextTokenIgnoringNewline();
|
||||
AbstractConfigValue result = null;
|
||||
if (t == Tokens.OPEN_CURLY) {
|
||||
result = parseObject();
|
||||
result = parseObject(true);
|
||||
} else if (t == Tokens.OPEN_SQUARE) {
|
||||
result = parseArray();
|
||||
} else if (t == Tokens.END) {
|
||||
throw parseError("Empty document");
|
||||
} else {
|
||||
throw parseError("Document must have an object or array at root, unexpected token: "
|
||||
+ t);
|
||||
if (flavor == SyntaxFlavor.JSON) {
|
||||
if (t == Tokens.END) {
|
||||
throw parseError("Empty document");
|
||||
} else {
|
||||
throw parseError("Document must have an object or array at root, unexpected token: "
|
||||
+ t);
|
||||
}
|
||||
} else {
|
||||
// the root object can omit the surrounding braces.
|
||||
// this token should be the first field's key, or part
|
||||
// of it, so put it back.
|
||||
putBack(t);
|
||||
result = parseObject(false);
|
||||
}
|
||||
}
|
||||
|
||||
t = nextTokenIgnoringNewline();
|
||||
|
40
src/test/resources/equiv01/no-root-braces.conf
Normal file
40
src/test/resources/equiv01/no-root-braces.conf
Normal file
@ -0,0 +1,40 @@
|
||||
"ints" : {
|
||||
"fortyTwo" : 42,
|
||||
"fortyTwoAgain" : 42
|
||||
},
|
||||
|
||||
"floats" : {
|
||||
"fortyTwoPointOne" : 42.1,
|
||||
"fortyTwoPointOneAgain" : 42.1
|
||||
},
|
||||
|
||||
"strings" : {
|
||||
"abcd" : "abcd",
|
||||
"abcdAgain" : "abcd",
|
||||
"a" : "a",
|
||||
"b" : "b",
|
||||
"c" : "c",
|
||||
"d" : "d",
|
||||
"concatenated" : "null bar 42 baz true 3.14 hi"
|
||||
},
|
||||
|
||||
"arrays" : {
|
||||
"empty" : [],
|
||||
"1" : [ 1 ],
|
||||
"12" : [1, 2],
|
||||
"123" : [1, 2, 3],
|
||||
"ofString" : [ "a", "b", "c" ]
|
||||
},
|
||||
|
||||
"booleans" : {
|
||||
"true" : true,
|
||||
"trueAgain" : true,
|
||||
"false" : false,
|
||||
"falseAgain" : false
|
||||
},
|
||||
|
||||
"nulls" : {
|
||||
"null" : null,
|
||||
"nullAgain" : null
|
||||
}
|
||||
|
@ -87,6 +87,6 @@ class EquivalentsTest extends TestUtils {
|
||||
// it breaks every time you add a file, so you have to update it.
|
||||
assertEquals(2, dirCount)
|
||||
// this is the number of files not named original.*
|
||||
assertEquals(9, fileCount)
|
||||
assertEquals(10, fileCount)
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ abstract trait TestUtils {
|
||||
|
||||
// note: it's important to put {} or [] at the root if you
|
||||
// want to test "invalidity reasons" other than "wrong root"
|
||||
private val invalidJsonInvalidConf = List[ParseTest]("", // empty document
|
||||
private val invalidJsonInvalidConf = List[ParseTest](
|
||||
"{",
|
||||
"}",
|
||||
"[",
|
||||
@ -102,6 +102,10 @@ abstract trait TestUtils {
|
||||
"\"", // single quote by itself
|
||||
"{ \"foo\" : }", // no value in object
|
||||
"{ : 10 }", // no key in object
|
||||
" \"foo\" : ", // no value in object with no braces
|
||||
" : 10 ", // no key in object with no braces
|
||||
" \"foo\" : 10 } ", // close brace but no open
|
||||
" \"foo\" : 10 [ ", // no-braces object with trailing gunk
|
||||
"{ \"foo\" }", // no value or colon
|
||||
"{ \"a\" : [ }", // [ is not a valid value
|
||||
ParseTest(true, "{ \"foo\" : 10, }"), // extra trailing comma (lift fails to throw)
|
||||
@ -142,8 +146,7 @@ abstract trait TestUtils {
|
||||
"${ #comment }",
|
||||
"{ include \"bar\" : 10 }", // include with a value after it
|
||||
"{ include foo }", // include with unquoted string
|
||||
"{ include : { \"a\" : 1 } }", // include used as unquoted key
|
||||
"") // empty document again, just for clean formatting of this list ;-)
|
||||
"{ include : { \"a\" : 1 } }") // include used as unquoted key
|
||||
|
||||
// We'll automatically try each of these with whitespace modifications
|
||||
// so no need to add every possible whitespace variation
|
||||
@ -170,10 +173,11 @@ abstract trait TestUtils {
|
||||
"""{ "foo" : { "bar" : "baz", "woo" : "w00t" }, "baz" : { "bar" : "baz", "woo" : [1,2,3,4], "w00t" : true, "a" : false, "b" : 3.14, "c" : null } }""",
|
||||
"{}")
|
||||
|
||||
private val validConfInvalidJson = List[ParseTest](
|
||||
private val validConfInvalidJson = List[ParseTest]("", // empty document
|
||||
"""{ "foo" = 42 }""", // equals rather than colon
|
||||
"""{ foo { "bar" : 42 } }""", // omit the colon for object value
|
||||
"""{ foo baz { "bar" : 42 } }""", // omit the colon with unquoted key with spaces
|
||||
""" "foo" : 42 """, // omit braces on root object
|
||||
"""{ "foo" : bar }""", // no quotes on value
|
||||
"""{ "foo" : null bar 42 baz true 3.14 "hi" }""", // bunch of values to concat into a string
|
||||
"{ foo : \"bar\" }", // no quotes on key
|
||||
|
Loading…
Reference in New Issue
Block a user