mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Merge pull request #298 from fpringvaldsen/task/improve-indentation
Improve indentation
This commit is contained in:
commit
ea78c17381
@ -6,4 +6,9 @@ final class ConfigNodeArray extends ConfigNodeComplexValue {
|
|||||||
ConfigNodeArray(Collection<AbstractConfigNode> children) {
|
ConfigNodeArray(Collection<AbstractConfigNode> children) {
|
||||||
super(children);
|
super(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigNodeArray newNode(Collection<AbstractConfigNode> nodes) {
|
||||||
|
return new ConfigNodeArray(nodes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,4 +24,29 @@ abstract class ConfigNodeComplexValue extends AbstractConfigNodeValue {
|
|||||||
}
|
}
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ConfigNodeComplexValue indentText(AbstractConfigNode indentation) {
|
||||||
|
ArrayList<AbstractConfigNode> childrenCopy = new ArrayList<AbstractConfigNode>(children);
|
||||||
|
for (int i = 0; i < childrenCopy.size(); i++) {
|
||||||
|
AbstractConfigNode child = childrenCopy.get(i);
|
||||||
|
if (child instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) child).token())) {
|
||||||
|
childrenCopy.add(i + 1, indentation);
|
||||||
|
i++;
|
||||||
|
} else if (child instanceof ConfigNodeField) {
|
||||||
|
AbstractConfigNode value = ((ConfigNodeField) child).value();
|
||||||
|
if (value instanceof ConfigNodeComplexValue) {
|
||||||
|
childrenCopy.set(i, ((ConfigNodeField) child).replaceValue(((ConfigNodeComplexValue) value).indentText(indentation)));
|
||||||
|
}
|
||||||
|
} else if (child instanceof ConfigNodeComplexValue) {
|
||||||
|
childrenCopy.set(i, ((ConfigNodeComplexValue) child).indentText(indentation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newNode(childrenCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will just call into the object's constructor, but it's needed
|
||||||
|
// for use in the indentText() method so we can avoid a gross if/else statement
|
||||||
|
// checking the type of this
|
||||||
|
abstract ConfigNodeComplexValue newNode(Collection<AbstractConfigNode> nodes);
|
||||||
}
|
}
|
||||||
|
@ -6,4 +6,9 @@ final class ConfigNodeConcatenation extends ConfigNodeComplexValue {
|
|||||||
ConfigNodeConcatenation(Collection<AbstractConfigNode> children) {
|
ConfigNodeConcatenation(Collection<AbstractConfigNode> children) {
|
||||||
super(children);
|
super(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigNodeConcatenation newNode(Collection<AbstractConfigNode> nodes) {
|
||||||
|
return new ConfigNodeConcatenation(nodes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,30 @@
|
|||||||
package com.typesafe.config.impl;
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
final class ConfigNodeInclude extends ConfigNodeComplexValue {
|
final class ConfigNodeInclude extends AbstractConfigNode {
|
||||||
|
final private ArrayList<AbstractConfigNode> children;
|
||||||
final private ConfigIncludeKind kind;
|
final private ConfigIncludeKind kind;
|
||||||
|
|
||||||
ConfigNodeInclude(Collection<AbstractConfigNode> children, ConfigIncludeKind kind) {
|
ConfigNodeInclude(Collection<AbstractConfigNode> children, ConfigIncludeKind kind) {
|
||||||
super(children);
|
this.children = new ArrayList<AbstractConfigNode>(children);
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public Collection<AbstractConfigNode> children() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<Token> tokens() {
|
||||||
|
ArrayList<Token> tokens = new ArrayList();
|
||||||
|
for (AbstractConfigNode child : children) {
|
||||||
|
tokens.addAll(child.tokens());
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
protected ConfigIncludeKind kind() {
|
protected ConfigIncludeKind kind() {
|
||||||
return kind;
|
return kind;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,11 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
|
|||||||
super(children);
|
super(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigNodeObject newNode(Collection<AbstractConfigNode> nodes) {
|
||||||
|
return new ConfigNodeObject(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasValue(Path desiredPath) {
|
public boolean hasValue(Path desiredPath) {
|
||||||
for (AbstractConfigNode node : children) {
|
for (AbstractConfigNode node : children) {
|
||||||
if (node instanceof ConfigNodeField) {
|
if (node instanceof ConfigNodeField) {
|
||||||
@ -69,7 +74,15 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
|
|||||||
}
|
}
|
||||||
} else if (key.equals(desiredPath)) {
|
} else if (key.equals(desiredPath)) {
|
||||||
seenNonMatching = true;
|
seenNonMatching = true;
|
||||||
childrenCopy.set(i, node.replaceValue(value));
|
AbstractConfigNodeValue indentedValue;
|
||||||
|
AbstractConfigNode before = i - 1 > 0 ? childrenCopy.get(i - 1) : null;
|
||||||
|
if (value instanceof ConfigNodeComplexValue &&
|
||||||
|
before instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) before).token()))
|
||||||
|
indentedValue = ((ConfigNodeComplexValue) value).indentText(before);
|
||||||
|
else
|
||||||
|
indentedValue = value;
|
||||||
|
childrenCopy.set(i, node.replaceValue(indentedValue));
|
||||||
valueCopy = null;
|
valueCopy = null;
|
||||||
} else if (desiredPath.startsWith(key)) {
|
} else if (desiredPath.startsWith(key)) {
|
||||||
seenNonMatching = true;
|
seenNonMatching = true;
|
||||||
@ -105,9 +118,65 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<AbstractConfigNode> indentation() {
|
||||||
|
boolean seenNewLine = false;
|
||||||
|
ArrayList<AbstractConfigNode> indentation = new ArrayList<AbstractConfigNode>();
|
||||||
|
for (int i = 0; i < children.size(); i++) {
|
||||||
|
if (!seenNewLine) {
|
||||||
|
if (children.get(i) instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) children.get(i)).token())) {
|
||||||
|
seenNewLine = true;
|
||||||
|
indentation.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (children.get(i) instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) children.get(i)).token()) &&
|
||||||
|
i + 1 < children.size() && (children.get(i+1) instanceof ConfigNodeField ||
|
||||||
|
children.get(i+1) instanceof ConfigNodeInclude)) {
|
||||||
|
// Return the indentation of the first setting on its own line
|
||||||
|
indentation.add(children.get(i));
|
||||||
|
return indentation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (indentation.isEmpty()) {
|
||||||
|
indentation.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||||
|
return indentation;
|
||||||
|
} else {
|
||||||
|
// Calculate the indentation of the ending curly-brace to get the indentation of the root object
|
||||||
|
AbstractConfigNode last = children.get(children.size() - 1);
|
||||||
|
if (last instanceof ConfigNodeSingleToken && ((ConfigNodeSingleToken) last).token() == Tokens.CLOSE_CURLY) {
|
||||||
|
AbstractConfigNode beforeLast = children.get(children.size() - 2);
|
||||||
|
if (beforeLast instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) beforeLast).token())) {
|
||||||
|
String indent = ((ConfigNodeSingleToken) beforeLast).token().tokenText();
|
||||||
|
indent += " ";
|
||||||
|
indentation.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, indent)));
|
||||||
|
return indentation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The object has no curly braces and is at the root level, so don't indent
|
||||||
|
return indentation;
|
||||||
|
}
|
||||||
|
|
||||||
protected ConfigNodeObject addValueOnPath(ConfigNodePath desiredPath, AbstractConfigNodeValue value, ConfigSyntax flavor) {
|
protected ConfigNodeObject addValueOnPath(ConfigNodePath desiredPath, AbstractConfigNodeValue value, ConfigSyntax flavor) {
|
||||||
Path path = desiredPath.value();
|
Path path = desiredPath.value();
|
||||||
ArrayList<AbstractConfigNode> childrenCopy = new ArrayList<AbstractConfigNode>(super.children);
|
ArrayList<AbstractConfigNode> childrenCopy = new ArrayList<AbstractConfigNode>(super.children);
|
||||||
|
ArrayList<AbstractConfigNode> indentation = new ArrayList<AbstractConfigNode>(indentation());
|
||||||
|
|
||||||
|
// If the value we're inserting is a complex value, we'll need to indent it for insertion
|
||||||
|
AbstractConfigNodeValue indentedValue;
|
||||||
|
if (value instanceof ConfigNodeComplexValue) {
|
||||||
|
indentedValue = ((ConfigNodeComplexValue) value).indentText(indentation.get(indentation.size() - 1));
|
||||||
|
} else {
|
||||||
|
indentedValue = value;
|
||||||
|
}
|
||||||
|
boolean sameLine = !(indentation.get(0) instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) indentation.get(0)).token()));
|
||||||
|
|
||||||
|
// If the path is of length greater than one, see if the value needs to be added further down
|
||||||
if (path.length() > 1) {
|
if (path.length() > 1) {
|
||||||
for (int i = super.children.size() - 1; i >= 0; i--) {
|
for (int i = super.children.size() - 1; i >= 0; i--) {
|
||||||
if (!(super.children.get(i) instanceof ConfigNodeField)) {
|
if (!(super.children.get(i) instanceof ConfigNodeField)) {
|
||||||
@ -123,44 +192,79 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, construct the new setting
|
||||||
boolean startsWithBrace = super.children.get(0) instanceof ConfigNodeSingleToken &&
|
boolean startsWithBrace = super.children.get(0) instanceof ConfigNodeSingleToken &&
|
||||||
((ConfigNodeSingleToken) super.children.get(0)).token() == Tokens.OPEN_CURLY;
|
((ConfigNodeSingleToken) super.children.get(0)).token() == Tokens.OPEN_CURLY;
|
||||||
ArrayList<AbstractConfigNode> newNodes = new ArrayList<AbstractConfigNode>();
|
ArrayList<AbstractConfigNode> newNodes = new ArrayList<AbstractConfigNode>();
|
||||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
|
newNodes.addAll(indentation);
|
||||||
newNodes.add(desiredPath.first());
|
newNodes.add(desiredPath.first());
|
||||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||||
newNodes.add(new ConfigNodeSingleToken(Tokens.COLON));
|
newNodes.add(new ConfigNodeSingleToken(Tokens.COLON));
|
||||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||||
|
|
||||||
if (path.length() == 1) {
|
if (path.length() == 1) {
|
||||||
newNodes.add(value);
|
newNodes.add(indentedValue);
|
||||||
} else {
|
} else {
|
||||||
|
// If the path is of length greater than one add the required new objects along the path
|
||||||
ArrayList<AbstractConfigNode> newObjectNodes = new ArrayList<AbstractConfigNode>();
|
ArrayList<AbstractConfigNode> newObjectNodes = new ArrayList<AbstractConfigNode>();
|
||||||
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.OPEN_CURLY));
|
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.OPEN_CURLY));
|
||||||
|
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||||
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.CLOSE_CURLY));
|
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.CLOSE_CURLY));
|
||||||
ConfigNodeObject newObject = new ConfigNodeObject(newObjectNodes);
|
ConfigNodeObject newObject = new ConfigNodeObject(newObjectNodes);
|
||||||
newNodes.add(newObject.addValueOnPath(desiredPath.subPath(1), value, flavor));
|
newNodes.add(newObject.addValueOnPath(desiredPath.subPath(1), indentedValue, flavor));
|
||||||
}
|
}
|
||||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
|
|
||||||
|
|
||||||
// Combine these two cases so that we only have to iterate once
|
// Combine these two cases so that we only have to iterate once
|
||||||
if (flavor == ConfigSyntax.JSON || startsWithBrace) {
|
if (flavor == ConfigSyntax.JSON || startsWithBrace || sameLine) {
|
||||||
for (int i = childrenCopy.size() - 1; i >= 0; i--) {
|
for (int i = childrenCopy.size() - 1; i >= 0; i--) {
|
||||||
|
|
||||||
// Valid JSON requires all key-value pairs except the last one to be succeeded by a comma,
|
// If we are in JSON or are adding a setting on the same line, we need to add a comma to the
|
||||||
// so we'll need to add a comma when adding a value
|
// last setting
|
||||||
if (flavor == ConfigSyntax.JSON && childrenCopy.get(i) instanceof ConfigNodeField) {
|
if ((flavor == ConfigSyntax.JSON || sameLine) && childrenCopy.get(i) instanceof ConfigNodeField) {
|
||||||
|
if (i+1 >= childrenCopy.size() ||
|
||||||
|
!(childrenCopy.get(i+1) instanceof ConfigNodeSingleToken
|
||||||
|
&& ((ConfigNodeSingleToken) childrenCopy.get(i+1)).token() == Tokens.COMMA))
|
||||||
childrenCopy.add(i+1, new ConfigNodeSingleToken(Tokens.COMMA));
|
childrenCopy.add(i+1, new ConfigNodeSingleToken(Tokens.COMMA));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the value into the copy of the children map, keeping any whitespace/newlines
|
||||||
|
// before the close curly brace
|
||||||
if (startsWithBrace && childrenCopy.get(i) instanceof ConfigNodeSingleToken &&
|
if (startsWithBrace && childrenCopy.get(i) instanceof ConfigNodeSingleToken &&
|
||||||
((ConfigNodeSingleToken) childrenCopy.get(i)).token == Tokens.CLOSE_CURLY) {
|
((ConfigNodeSingleToken) childrenCopy.get(i)).token == Tokens.CLOSE_CURLY) {
|
||||||
childrenCopy.add(i, new ConfigNodeField(newNodes));
|
AbstractConfigNode previous = childrenCopy.get(i - 1);
|
||||||
|
if (previous instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) previous).token())) {
|
||||||
|
childrenCopy.add(i - 1, new ConfigNodeField(newNodes));
|
||||||
|
i--;
|
||||||
|
} else if (previous instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) previous).token())) {
|
||||||
|
AbstractConfigNode beforePrevious = childrenCopy.get(i - 2);
|
||||||
|
if (sameLine) {
|
||||||
|
childrenCopy.add(i - 1, new ConfigNodeField(newNodes));
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
else if (beforePrevious instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) beforePrevious).token())) {
|
||||||
|
childrenCopy.add(i - 2, new ConfigNodeField(newNodes));
|
||||||
|
i -= 2;
|
||||||
|
} else {
|
||||||
|
childrenCopy.add(i, new ConfigNodeField(newNodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
childrenCopy.add(i, new ConfigNodeField(newNodes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!startsWithBrace) {
|
if (!startsWithBrace) {
|
||||||
childrenCopy.add(new ConfigNodeField(newNodes));
|
if (childrenCopy.get(childrenCopy.size() - 1) instanceof ConfigNodeSingleToken &&
|
||||||
|
Tokens.isNewline(((ConfigNodeSingleToken) childrenCopy.get(childrenCopy.size() - 1)).token()))
|
||||||
|
childrenCopy.add(childrenCopy.size() - 1, new ConfigNodeField(newNodes));
|
||||||
|
else
|
||||||
|
childrenCopy.add(new ConfigNodeField(newNodes));
|
||||||
}
|
}
|
||||||
return new ConfigNodeObject(childrenCopy);
|
return new ConfigNodeObject(childrenCopy);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@ final class ConfigNodeRoot extends ConfigNodeComplexValue {
|
|||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConfigNodeRoot newNode(Collection<AbstractConfigNode> nodes) {
|
||||||
|
throw new ConfigException.BugOrBroken("Tried to indent the root object");
|
||||||
|
}
|
||||||
|
|
||||||
protected ConfigNodeComplexValue value() {
|
protected ConfigNodeComplexValue value() {
|
||||||
for (AbstractConfigNode node : children) {
|
for (AbstractConfigNode node : children) {
|
||||||
if (node instanceof ConfigNodeComplexValue) {
|
if (node instanceof ConfigNodeComplexValue) {
|
||||||
|
@ -270,7 +270,6 @@ final class ConfigParser {
|
|||||||
valueNode = ((ConfigNodeField) node).value();
|
valueNode = ((ConfigNodeField) node).value();
|
||||||
|
|
||||||
// comments from the key token go to the value token
|
// comments from the key token go to the value token
|
||||||
//newValue = parseValue(valueToken.prepend(keyToken.comments));
|
|
||||||
newValue = parseValue(valueNode, comments);
|
newValue = parseValue(valueNode, comments);
|
||||||
|
|
||||||
if (((ConfigNodeField) node).separator() == Tokens.PLUS_EQUALS) {
|
if (((ConfigNodeField) node).separator() == Tokens.PLUS_EQUALS) {
|
||||||
|
@ -148,14 +148,14 @@ class ConfigDocumentTest extends TestUtils {
|
|||||||
|
|
||||||
origText = "{a.b.c: d}"
|
origText = "{a.b.c: d}"
|
||||||
configDoc = ConfigDocumentFactory.parseString(origText)
|
configDoc = ConfigDocumentFactory.parseString(origText)
|
||||||
assertEquals("{\na : 2\n}", configDoc.setValue("a", "2").render())
|
assertEquals("{ a : 2}", configDoc.setValue("a", "2").render())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def configDocumentSetNewValueBraceRoot {
|
def configDocumentSetNewValueBraceRoot {
|
||||||
val origText = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n}"
|
val origText = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n}"
|
||||||
val finalTextConf = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n\n\"e\" : \"f\"\n}"
|
val finalTextConf = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n\t\"e\" : \"f\"\n}"
|
||||||
val finalTextJson = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\",\n\n\"e\" : \"f\"\n}"
|
val finalTextJson = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\",\n\t\"e\" : \"f\"\n}"
|
||||||
configDocumentReplaceConfTest(origText, finalTextConf, "\"f\"", "\"e\"")
|
configDocumentReplaceConfTest(origText, finalTextConf, "\"f\"", "\"e\"")
|
||||||
configDocumentReplaceJsonTest(origText, finalTextJson, "\"f\"", "\"e\"")
|
configDocumentReplaceJsonTest(origText, finalTextJson, "\"f\"", "\"e\"")
|
||||||
}
|
}
|
||||||
@ -163,21 +163,21 @@ class ConfigDocumentTest extends TestUtils {
|
|||||||
@Test
|
@Test
|
||||||
def configDocumentSetNewValueNoBraces {
|
def configDocumentSetNewValueNoBraces {
|
||||||
val origText = "\"a\":\"b\",\n\"c\":\"d\"\n"
|
val origText = "\"a\":\"b\",\n\"c\":\"d\"\n"
|
||||||
val finalText = "\"a\":\"b\",\n\"c\":\"d\"\n\n\"e\" : \"f\"\n"
|
val finalText = "\"a\":\"b\",\n\"c\":\"d\"\n\"e\" : \"f\"\n"
|
||||||
configDocumentReplaceConfTest(origText, finalText, "\"f\"", "\"e\"")
|
configDocumentReplaceConfTest(origText, finalText, "\"f\"", "\"e\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def configDocumentSetNewValueMultiLevelConf {
|
def configDocumentSetNewValueMultiLevelConf {
|
||||||
val origText = "a:b\nc:d"
|
val origText = "a:b\nc:d"
|
||||||
val finalText = "a:b\nc:d\ne : {\nf : {\ng : 12\n}\n}\n"
|
val finalText = "a:b\nc:d\ne : { f : { g : 12 } }"
|
||||||
configDocumentReplaceConfTest(origText, finalText, "12", "e.f.g")
|
configDocumentReplaceConfTest(origText, finalText, "12", "e.f.g")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def configDocumentSetNewValueMultiLevelJson {
|
def configDocumentSetNewValueMultiLevelJson {
|
||||||
val origText = "{\"a\":\"b\",\n\"c\":\"d\"}"
|
val origText = "{\"a\":\"b\",\n\"c\":\"d\"}"
|
||||||
val finalText = "{\"a\":\"b\",\n\"c\":\"d\",\n\"e\" : {\n\"f\" : {\n\"g\" : 12\n}\n}\n}"
|
val finalText = "{\"a\":\"b\",\n\"c\":\"d\",\n\"e\" : { \"f\" : { \"g\" : 12 } }}"
|
||||||
configDocumentReplaceJsonTest(origText, finalText, "12", "e.f.g")
|
configDocumentReplaceJsonTest(origText, finalText, "12", "e.f.g")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,4 +325,122 @@ class ConfigDocumentTest extends TestUtils {
|
|||||||
assertEquals(configDocumentFile.render(), configDocument.render())
|
assertEquals(configDocumentFile.render(), configDocument.render())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationSingleLineObject {
|
||||||
|
// Proper insertion for single-line objects
|
||||||
|
var origText = "a { b: c }"
|
||||||
|
var configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b: c, d : e }", configDocument.setValue("a.d", "e").render())
|
||||||
|
|
||||||
|
origText = "a { b: c }, d: e"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b: c }, d: e, f : g", configDocument.setValue("f", "g").render())
|
||||||
|
|
||||||
|
origText = "a { b: c }, d: e,"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b: c }, d: e, f : g", configDocument.setValue("f", "g").render())
|
||||||
|
|
||||||
|
assertEquals("a { b: c }, d: e, f : { g : { h : i } }", configDocument.setValue("f.g.h", "i").render())
|
||||||
|
|
||||||
|
origText = "{a { b: c }, d: e}"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("{a { b: c }, d: e, f : g}", configDocument.setValue("f", "g").render())
|
||||||
|
|
||||||
|
assertEquals("{a { b: c }, d: e, f : { g : { h : i } }}", configDocument.setValue("f.g.h", "i").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationMultiLineObject {
|
||||||
|
var origText = "a {\n b: c\n}"
|
||||||
|
var configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a {\n b: c\n e : f\n}", configDocument.setValue("a.e", "f").render())
|
||||||
|
|
||||||
|
assertEquals("a {\n b: c\n d : { e : { f : g } }\n}", configDocument.setValue("a.d.e.f", "g").render())
|
||||||
|
|
||||||
|
origText = "a {\n b: c\n}\n"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a {\n b: c\n}\nd : e\n", configDocument.setValue("d", "e").render())
|
||||||
|
|
||||||
|
assertEquals("a {\n b: c\n}\nd : { e : { f : g } }\n", configDocument.setValue("d.e.f", "g").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationNested {
|
||||||
|
var origText = "a { b { c { d: e } } }"
|
||||||
|
var configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b { c { d: e, f : g } } }", configDocument.setValue("a.b.c.f", "g").render())
|
||||||
|
|
||||||
|
origText = "a {\n b {\n c {\n d: e\n }\n }\n}"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a {\n b {\n c {\n d: e\n f : g\n }\n }\n}", configDocument.setValue("a.b.c.f", "g").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationEmptyObject {
|
||||||
|
var origText = "a { }"
|
||||||
|
var configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b : c }", configDocument.setValue("a.b", "c").render())
|
||||||
|
|
||||||
|
origText = "a {\n b {\n }\n}"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a {\n b {\n c : d\n }\n}", configDocument.setValue("a.b.c", "d").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationMultiLineValue {
|
||||||
|
val origText = "a {\n b {\n c {\n d: e\n }\n }\n}"
|
||||||
|
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a {\n b {\n c {\n d: e\n f : {\n g: h\n i: j\n k: {\n l: m\n }\n }\n }\n }\n}",
|
||||||
|
configDocument.setValue("a.b.c.f", "{\n g: h\n i: j\n k: {\n l: m\n }\n}").render())
|
||||||
|
|
||||||
|
assertEquals("a {\n b {\n c {\n d: e\n f : 12 13 [1,\n 2,\n 3,\n {\n a:b\n }]\n }\n }\n}",
|
||||||
|
configDocument.setValue("a.b.c.f", "12 13 [1,\n2,\n3,\n{\n a:b\n}]").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationMultiLineValueSingleLineObject {
|
||||||
|
// Weird indentation occurs when adding a multi-line value to a single-line object
|
||||||
|
val origText = "a { b { } }"
|
||||||
|
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
assertEquals("a { b { c : {\n c:d\n } } }", configDocument.setValue("a.b.c", "{\n c:d\n}").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationSingleLineObjectContainingMultiLineValue {
|
||||||
|
val origText = "a { b {\n c: d\n} }"
|
||||||
|
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
|
||||||
|
assertEquals("a { b {\n c: d\n}, e : f }", configDocument.setValue("a.e", "f").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationReplacingWithMultiLineValue {
|
||||||
|
var origText = "a {\n b {\n c : 22\n }\n}"
|
||||||
|
var configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
|
||||||
|
assertEquals("a {\n b {\n c : {\n d:e\n }\n }\n}", configDocument.setValue("a.b.c", "{\n d:e\n}").render())
|
||||||
|
|
||||||
|
origText = "a {\n b {\n f : 10\n c : 22\n }\n}"
|
||||||
|
configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
|
||||||
|
assertEquals("a {\n b {\n f : 10\n c : {\n d:e\n }\n }\n}", configDocument.setValue("a.b.c", "{\n d:e\n}").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationValueWithIncludeTest {
|
||||||
|
val origText = "a {\n b {\n c : 22\n }\n}"
|
||||||
|
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
|
||||||
|
assertEquals("a {\n b {\n c : 22\n d : {\n include \"foo\"\n e:f\n }\n }\n}",
|
||||||
|
configDocument.setValue("a.b.d", "{\n include \"foo\"\n e:f\n}").render())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def configDocumentIndentationBadedOnIncludeNode {
|
||||||
|
val origText = "a : b\n include \"foo\"\n"
|
||||||
|
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||||
|
|
||||||
|
assertEquals("a : b\n include \"foo\"\n c : d\n", configDocument.setValue("c", "d").render())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class ConfigNodeTest extends TestUtils {
|
|||||||
val node = configNodeObject(List(nodeKeyValuePair(configNodeKey("bar"), nodeInt(15))))
|
val node = configNodeObject(List(nodeKeyValuePair(configNodeKey("bar"), nodeInt(15))))
|
||||||
assertEquals("bar : 15", node.render())
|
assertEquals("bar : 15", node.render())
|
||||||
val newNode = node.setValueOnPath("foo", value)
|
val newNode = node.setValueOnPath("foo", value)
|
||||||
val finalText = "bar : 15\nfoo : " + value.render() + "\n"
|
val finalText = "bar : 15, foo : " + value.render()
|
||||||
assertEquals(finalText, newNode.render())
|
assertEquals(finalText, newNode.render())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,24 +195,24 @@ class ConfigNodeTest extends TestUtils {
|
|||||||
// Test that all features of node replacement in a map work in a complex map containing nested maps
|
// Test that all features of node replacement in a map work in a complex map containing nested maps
|
||||||
val origText = "foo : bar\nbaz : {\n\t\"abc.def\" : 123\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
|
val origText = "foo : bar\nbaz : {\n\t\"abc.def\" : 123\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
|
||||||
"def : \"this is a string\"\n\t\tghi : ${\"a.b\"}\n\t}\n}\nbaz.abc.ghi : 52\nbaz.abc.ghi : 53\n}"
|
"def : \"this is a string\"\n\t\tghi : ${\"a.b\"}\n\t}\n}\nbaz.abc.ghi : 52\nbaz.abc.ghi : 53\n}"
|
||||||
val lowestLevelMap = configNodeObject(List(nodeOpenBrace, nodeLine(6),
|
val lowestLevelMap = configNodeObject(List(nodeOpenBrace, nodeLine(6), nodeWhitespace("\t\t"),
|
||||||
nodeKeyValuePair(nodeWhitespace("\t\t"), configNodeKey("def"), configNodeSimpleValue(tokenString("this is a string")), nodeLine(7)),
|
nodeKeyValuePair(configNodeKey("def"), configNodeSimpleValue(tokenString("this is a string"))), nodeLine(7),
|
||||||
nodeKeyValuePair(nodeWhitespace("\t\t"), configNodeKey("ghi"), configNodeSimpleValue(tokenKeySubstitution("a.b")), nodeLine(8)),
|
nodeWhitespace("\t\t"), nodeKeyValuePair(configNodeKey("ghi"), configNodeSimpleValue(tokenKeySubstitution("a.b"))), nodeLine(8),
|
||||||
nodeWhitespace("\t"), nodeCloseBrace))
|
nodeWhitespace("\t"), nodeCloseBrace))
|
||||||
val higherLevelMap = configNodeObject(List(nodeOpenBrace, nodeLine(2),
|
val higherLevelMap = configNodeObject(List(nodeOpenBrace, nodeLine(2),
|
||||||
nodeKeyValuePair(nodeWhitespace("\t"), configNodeKey("\"abc.def\""), configNodeSimpleValue(tokenInt(123)), nodeLine(3)),
|
nodeWhitespace("\t"), nodeKeyValuePair(configNodeKey("\"abc.def\""), configNodeSimpleValue(tokenInt(123))), nodeLine(3),
|
||||||
nodeWhitespace("\t"), configNodeBasic(tokenCommentDoubleSlash("This is a comment about the below setting")),
|
nodeWhitespace("\t"), configNodeBasic(tokenCommentDoubleSlash("This is a comment about the below setting")),
|
||||||
nodeLine(4), nodeLine(5),
|
nodeLine(4), nodeLine(5),
|
||||||
nodeKeyValuePair(nodeWhitespace("\t"), configNodeKey("abc"), lowestLevelMap, nodeLine(9)), nodeWhitespace(""),
|
nodeWhitespace("\t"), nodeKeyValuePair(configNodeKey("abc"), lowestLevelMap), nodeLine(9), nodeWhitespace(""),
|
||||||
nodeCloseBrace))
|
nodeCloseBrace))
|
||||||
val origNode = configNodeObject(List(nodeKeyValuePair(configNodeKey("foo"), configNodeSimpleValue(tokenUnquoted("bar")), nodeLine(1)),
|
val origNode = configNodeObject(List(nodeKeyValuePair(configNodeKey("foo"), configNodeSimpleValue(tokenUnquoted("bar")), nodeLine(1)),
|
||||||
nodeKeyValuePair(configNodeKey("baz"), higherLevelMap, nodeLine(10)),
|
nodeKeyValuePair(configNodeKey("baz"), higherLevelMap), nodeLine(10),
|
||||||
nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(52)), nodeLine(11)),
|
nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(52))), nodeLine(11),
|
||||||
nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(53)), nodeLine(12)),
|
nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(53))), nodeLine(12),
|
||||||
nodeCloseBrace))
|
nodeCloseBrace))
|
||||||
assertEquals(origText, origNode.render())
|
assertEquals(origText, origNode.render())
|
||||||
val finalText = "foo : bar\nbaz : {\n\t\"abc.def\" : true\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
|
val finalText = "foo : bar\nbaz : {\n\t\"abc.def\" : true\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
|
||||||
"def : false\n\n\"this.does.not.exist@@@+$#\" : {\nend : doesnotexist\n}\n}\n}\nbaz.abc.ghi : randomunquotedString\n}"
|
"def : false\n\t\t\n\t\t\"this.does.not.exist@@@+$#\" : { end : doesnotexist }\n\t}\n}\n\nbaz.abc.ghi : randomunquotedString\n}"
|
||||||
|
|
||||||
//Can replace settings in nested maps
|
//Can replace settings in nested maps
|
||||||
// Paths with quotes in the name are treated as a single Path, rather than multiple sub-paths
|
// Paths with quotes in the name are treated as a single Path, rather than multiple sub-paths
|
||||||
|
Loading…
Reference in New Issue
Block a user