From b3613b10b048a6cb557725afa8c764ae0b1d3dc3 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 1 Jan 2019 12:27:45 -0600
Subject: [PATCH 01/63] retain comments; formatting options
---
src/main/org/hjson/CommentStyle.java | 24 +++
src/main/org/hjson/CommentType.java | 26 +++
src/main/org/hjson/HjsonOptions.java | 85 +++++++-
src/main/org/hjson/HjsonParser.java | 225 ++++++++++++++++---
src/main/org/hjson/HjsonWriter.java | 218 ++++++++++++++++---
src/main/org/hjson/JsonArray.java | 310 ++++++++++++++++++++++++++-
src/main/org/hjson/JsonLiteral.java | 2 -
src/main/org/hjson/JsonNumber.java | 2 -
src/main/org/hjson/JsonObject.java | 256 +++++++++++++++++++---
src/main/org/hjson/JsonString.java | 3 -
src/main/org/hjson/JsonValue.java | 132 +++++++++++-
11 files changed, 1182 insertions(+), 101 deletions(-)
create mode 100644 src/main/org/hjson/CommentStyle.java
create mode 100644 src/main/org/hjson/CommentType.java
diff --git a/src/main/org/hjson/CommentStyle.java b/src/main/org/hjson/CommentStyle.java
new file mode 100644
index 0000000..cc48fea
--- /dev/null
+++ b/src/main/org/hjson/CommentStyle.java
@@ -0,0 +1,24 @@
+package org.hjson;
+
+/**
+ * This class represents the various comment styles that can be used when adding
+ * new comments to a {@link JsonValue}.
+ */
+public enum CommentStyle {
+ /**
+ * Hash style comments, indicated by placing a # symbol at the
+ * start of the comment, followed by the beginning of each new line.
+ */
+ HASH,
+ /**
+ * The C style line comment, indicated by placing a // at the
+ * start of the comment, followed by the beginning of each new line.
+ */
+ LINE,
+ /**
+ * A block style comment, indicated by placing a /* at the
+ * start of the comment, followed by a * / (with no spaces) at
+ * the very end of the comment.
+ */
+ BLOCK
+}
diff --git a/src/main/org/hjson/CommentType.java b/src/main/org/hjson/CommentType.java
new file mode 100644
index 0000000..de6d53f
--- /dev/null
+++ b/src/main/org/hjson/CommentType.java
@@ -0,0 +1,26 @@
+package org.hjson;
+
+/**
+ * This class represents the specific type of comment to be used in conjunction with a {@link JsonValue}.
+ * Comments can be placed by calling {@link JsonValue#setComment(CommentType, CommentStyle, String)}
+ * or another such variant.
+ */
+public enum CommentType {
+ /**
+ * Indicates that this comment precedes the value that it is paired with, to be placed one line
+ * before the value. In the case of parent or root objects, this type indicates that the comment
+ * is a header inside of the json file.
+ */
+ BOL,
+ /**
+ * Indicates that this comment follows the value that it is paired with, to be placed at the end
+ * of the line. In the case of parent or root objects, this type indicates that the comment is a
+ * footer inside of the json file.
+ */
+ EOL,
+ /**
+ * Indicates that this comment falls anywhere else in association with this value. This usually
+ * implies that the value is inside of an empty object or array.
+ */
+ INTERIOR
+}
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index b4e10a5..7a2c7bb 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -28,10 +28,19 @@ public class HjsonOptions {
private IHjsonDsfProvider[] dsf;
private boolean legacyRoot;
+ private boolean nlBraces;
+ private boolean allowCompact;
+ private boolean allowMultiVal;
+ private int indent, commentIndent;
public HjsonOptions() {
dsf=new IHjsonDsfProvider[0];
legacyRoot=true;
+ nlBraces=false;
+ allowCompact=true;
+ allowMultiVal=true;
+ indent=2;
+ commentIndent=0;
}
/**
@@ -46,7 +55,7 @@ public HjsonOptions() {
*
* @param value value
*/
- public void setDsfProviders(IHjsonDsfProvider[] value) { dsf=value.clone(); }
+ public HjsonOptions setDsfProviders(IHjsonDsfProvider... value) { dsf=value.clone(); return this; }
/**
* Detects whether objects without root braces are supported.
@@ -60,7 +69,7 @@ public HjsonOptions() {
*
* @param value value
*/
- public void setParseLegacyRoot(boolean value) { legacyRoot=value; }
+ public HjsonOptions setParseLegacyRoot(boolean value) { legacyRoot=value; return this; }
/**
* Detects whether root braces should be emitted.
@@ -78,6 +87,76 @@ public HjsonOptions() {
* @param value value
*/
@Deprecated
- public void setEmitRootBraces(boolean value) { }
+ public HjsonOptions setEmitRootBraces(boolean value) { return this; }
+
+ /**
+ * Detects whether braces and brackets should be placed on new lines.
+ *
+ * @return whether braces and brackets follow the K&R / Java syntax.
+ */
+ public boolean useNlBraces() { return nlBraces; }
+
+ /**
+ * Sets whether braces and brackets should be placed on new lines.
+ *
+ * @param value value
+ */
+ public HjsonOptions setNlBraces(boolean value) { nlBraces=value; return this; }
+
+ /**
+ * Detects whether more than one value is ever allowed on a single line.
+ *
+ * @return true if more than one value is allowed.
+ */
+ public boolean allowMultiVal() { return allowMultiVal; }
+
+ /**
+ * Sets whether more than one value is ever allowed to be placed on a single line.
+ *
+ * @param value value
+ */
+ public HjsonOptions setAllowMultiVal(boolean value) { allowMultiVal=value; return this; }
+
+ /**
+ * Detects whether objects an arrays are allowed to be displayed on a single line.
+ *
+ * @return true if objects and arrays can be displayed on a single line.
+ */
+ public boolean allowCompact() { return allowCompact; }
+
+ /**
+ * Sets whether objects and arrays can be displayed on a single line.
+ *
+ * @param value value
+ */
+ public HjsonOptions setAllowCompact(boolean value) { allowCompact=value; return this; }
+
+ /**
+ * Gets the number of spaces to be placed per-level on each new line.
+ *
+ * @return the number of spaces.
+ */
+ public int getIndent() { return indent; }
+
+ /**
+ * Sets the number of spaces to be placed per-level on each new line.
+ *
+ * @param value value
+ */
+ public HjsonOptions setIndent(int value) { indent=value; return this; }
+
+ /**
+ * Gets the number of spaces to be placed before comments on new lines.
+ *
+ * @return the number of spaces.
+ */
+ public int getCommentIndent() { return commentIndent; }
+
+ /**
+ * Sets the number of spaces to be placed before comments on new lines.
+ *
+ * @param value value
+ */
+ public HjsonOptions setCommentIndent(int value) { commentIndent=value; return this; }
}
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index fec6336..57433c2 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -70,17 +70,23 @@ void reset() {
index=lineOffset=current=0;
line=1;
peek=new StringBuilder();
- reader=new StringReader(buffer);
+ // Don't lose the final character.
+ reader=new StringReader(buffer + ' ');
capture=false;
captureBuffer=null;
}
JsonValue parse() throws IOException {
- // Braces for the root object are optional
-
read();
- skipWhiteSpace();
+ String header=readBetweenVals();
+ JsonValue value = tryParse();
+ value.setFullComment(CommentType.BOL, header);
+
+ return value;
+ }
+ JsonValue tryParse() throws IOException {
+ // Braces for the root object are optional
if (legacyRoot) {
switch (current) {
case '[':
@@ -94,10 +100,11 @@ JsonValue parse() throws IOException {
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
reset();
read();
- skipWhiteSpace();
+ System.out.println("101: " + readBetweenVals());
try { return checkTrailing(readValue()); }
catch (Exception exception2) { }
- throw exception; // throw original error
+ // throw original error
+ throw exception;
}
}
} else {
@@ -106,7 +113,7 @@ JsonValue parse() throws IOException {
}
JsonValue checkTrailing(JsonValue v) throws ParseException, IOException {
- skipWhiteSpace();
+ v.setFullComment(CommentType.EOL, readBetweenVals());
if (!isEndOfText()) throw error("Extra characters in input: "+current);
return v;
}
@@ -164,45 +171,161 @@ private JsonValue readTfnns() throws IOException {
private JsonArray readArray() throws IOException {
read();
JsonArray array=new JsonArray();
- skipWhiteSpace();
- if (readIf(']')) {
- return array;
- }
+ boolean compact=isContainerCompact();
+ array.setCompact(compact);
+ int sumLineLength=0;
+ int lineLength=1;
+ int numLines=0;
+
while (true) {
- skipWhiteSpace();
- array.add(readValue());
- skipWhiteSpace();
- if (readIf(',')) skipWhiteSpace(); // , is optional
- if (readIf(']')) break;
- else if (isEndOfText()) throw error("End of input while parsing an array (did you forget a closing ']'?)");
+ // Comment above / before value.
+ String bol=readBetweenVals();
+
+ // If readBetweenVals() brought us to the
+ // end, it must be time to stop.
+ if (readIf(']')) {
+ // Because we reached the end, we learned
+ // that this was an interior comment.
+ array.setFullComment(CommentType.INTERIOR, bol);
+ break;
+ } else if (isEndOfText()) {
+ throw error("End of input while parsing an array (did you forget a closing ']'?)");
+ }
+ // Value comes next.
+ JsonValue value=readValue();
+ value.setFullComment(CommentType.BOL, bol);
+
+ // Skip whitespace surrounding a comma.
+ skipToNL();
+ if (readIf(',')) { // , is optional
+ skipToNL();
+ }
+ // Make sure we back up all the way to a
+ // new line character or non-whitespace.
+ readIf('\r');
+
+ // If we hit a new line, whatever character
+ // comes next is either a value or BOL #.
+ if (current!='\n') {
+ // There was something else on this line.
+ // See if it was an EOL #.
+ String eol = readBetweenVals(true);
+
+ if (!eol.isEmpty()) { // This is an EOL #.
+ value.setFullComment(CommentType.EOL, eol);
+ } else { // There's another value on this line.
+ lineLength++;
+ }
+ } else {
+ sumLineLength+=lineLength;
+ lineLength=1;
+ // Tally the lines.
+ numLines++;
+ }
+ array.add(value);
+ }
+ if (sumLineLength>0) {
+ int avgLineLength=sumLineLength/numLines;
+ if (avgLineLength<1) avgLineLength=1;
+ array.setLineLength(avgLineLength);
+ } else if (compact) {
+ array.setLineLength(array.size());
}
return array;
}
private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
+ // Skip the opening brace.
if (!objectWithoutBraces) read();
JsonObject object=new JsonObject();
- skipWhiteSpace();
+ object.setCompact(isContainerCompact());
+ int sumLineLength=1;
+ int lineLength=1;
+ int numLines=0;
+
while (true) {
+ // Comment above / before name.
+ String bol=readBetweenVals();
+
+ // If readBetweenVals() brought us to the
+ // end, it must be time to stop.
if (objectWithoutBraces) {
- if (isEndOfText()) break;
+ if (isEndOfText()) {
+ // Because we reached the end, we learned
+ // that this was an interior comment.
+ object.setFullComment(CommentType.INTERIOR, bol);
+ break;
+ }
} else {
if (isEndOfText()) throw error("End of input while parsing an object (did you forget a closing '}'?)");
- if (readIf('}')) break;
+ if (readIf('}')) {
+ object.setFullComment(CommentType.INTERIOR, bol);
+ break;
+ }
}
+ // Name comes next.
String name=readName();
- skipWhiteSpace();
+
+ // Colon and potential surrounding spaces.
+ // Comments will be fully ignored, here.
+ readBetweenVals();
if (!readIf(':')) {
throw expected("':'");
}
- skipWhiteSpace();
- object.add(name, readValue());
- skipWhiteSpace();
- if (readIf(',')) skipWhiteSpace(); // , is optional
+ readBetweenVals();
+
+ // The value itself.
+ JsonValue value = readValue();
+
+ // Skip whitespace surrounding a comma.
+ skipToNL();
+ if (readIf(',')) { // , is optional
+ skipToNL();
+ }
+ // Make sure we back up all the way to a
+ // new line character or non-whitespace.
+ readIf('\r');
+
+ // If we hit a new line, whatever character
+ // comes next is either a key or BOL #.
+ if (current!='\n') {
+ // There was something else on this line.
+ // See if it was an EOL #.
+ String eol = readBetweenVals(true);
+
+ if (!eol.isEmpty()) { // This is an EOL #.
+ value.setFullComment(CommentType.EOL, eol);
+ } else { // There's another value on this line.
+ lineLength++;
+ }
+ } else {
+ sumLineLength+=lineLength;
+ lineLength=1;
+ // Tally the lines.
+ numLines++;
+ }
+ // Set comments and add.
+ value.setFullComment(CommentType.BOL, bol);
+ object.add(name, value);
+ }
+ if (sumLineLength>0) {
+ int avgLineLength=sumLineLength/numLines;
+ if (avgLineLength<1) avgLineLength=1;
+ object.setLineLength(avgLineLength);
}
return object;
}
+ private boolean isContainerCompact() throws IOException {
+ skipToNL();
+ readIf('\r');
+ // The object is compact if there is non-whitespace
+ // on the same line. If any further values are placed
+ // on subsequent lines, they will most likely look
+ // better this way, anyway.
+ return current!='\n';
+ }
+
private String readName() throws IOException {
if (current=='"' || current=='\'') return readStringInternal(false);
@@ -283,7 +406,7 @@ private JsonValue readString() throws IOException {
}
private String readStringInternal(boolean allowML) throws IOException {
- // callees make sure that (current=='"' || current=='\'')
+ // callers make sure that (current=='"' || current=='\'')
int exitCh = current;
read();
startCapture();
@@ -341,6 +464,7 @@ private void readEscape() throws IOException {
default:
throw expected("valid escape sequence");
}
+// capture=CaptureState.CAPTURE;
capture=true;
read();
}
@@ -406,23 +530,56 @@ private boolean readIf(char ch) throws IOException {
return true;
}
- private void skipWhiteSpace() throws IOException {
+ private String readBetweenVals() throws IOException {
+ return readBetweenVals(false);
+ }
+
+ private String readBetweenVals(boolean toEOL) throws IOException {
+ int indent=0;
+ startCapture();
while (!isEndOfText()) {
- while (isWhiteSpace()) read();
+ pauseCapture();
+ indent=skipWhiteSpace();
+ startCapture();
if (current=='#' || current=='/' && peek()=='/') {
do {
read();
} while (current>=0 && current!='\n');
+ if (toEOL) break;
+ else read();
}
else if (current=='/' && peek()=='*') {
read();
do {
read();
+ if (current=='\n') {
+ read();
+ skip(indent-1);
+ }
} while (current>=0 && !(current=='*' && peek()=='/'));
read(); read();
+ // Don't cut these values apart.
+ while (current=='\r' || current=='\n') {
+ read();
+ }
}
else break;
}
+ // trim() should be removed.
+ return endCapture().trim();
+ }
+
+ private int skipWhiteSpace() throws IOException {
+ int numSkipped=0;
+ while (isWhiteSpace()) {
+ read();
+ numSkipped++;
+ }
+ return numSkipped;
+ }
+
+ private void skipToNL() throws IOException {
+ while (current==' ' || current=='\t') read();
}
private int peek(int idx) throws IOException {
@@ -439,7 +596,6 @@ private int peek() throws IOException {
}
private boolean read() throws IOException {
-
if (current=='\n') {
line++;
lineOffset=index;
@@ -456,11 +612,18 @@ private boolean read() throws IOException {
if (current<0) return false;
index++;
- if (capture) captureBuffer.append((char)current);
+
+ if (capture) captureBuffer.append((char) current);
return true;
}
+ private void skip(int num) throws IOException {
+ pauseCapture();
+ for (int i=0; i0) nl(tw, level); else tw.write(separator); }
- tw.write('{');
-
- for (JsonObject.Member pair : obj) {
- nl(tw, level+1);
- tw.write(escapeName(pair.getName()));
- tw.write(":");
- save(pair.getValue(), tw, level+1, " ", false);
- }
-
- if (obj.size()>0) nl(tw, level);
- tw.write('}');
+ writeObject(obj, tw, level, separator, noIndent, forceQuotes);
break;
case ARRAY:
JsonArray arr=value.asArray();
- int n=arr.size();
- if (!noIndent) { if (n>0) nl(tw, level); else tw.write(separator); }
- tw.write('[');
- for (int i=0; i0) nl(tw, level);
- tw.write(']');
+ writeArray(arr, tw, level, separator, noIndent, forceQuotes);
break;
case BOOLEAN:
tw.write(separator);
tw.write(value.isTrue()?"true":"false");
break;
case STRING:
+ tw.write(separator);
+ if (forceQuotes) tw.write('"');
writeString(value.asString(), tw, level, separator);
+ if (forceQuotes) tw.write('"');
break;
default:
tw.write(separator);
+ if (forceQuotes) tw.write('"');
tw.write(value.toString());
+ if (forceQuotes) tw.write('"');
break;
}
+
+ // Write any following comments.
+ if (value.hasEOLComment()) {
+ writeEOLComment(tw, value, level);
+ }
+ }
+
+ void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean noIndent, boolean forceQuotes) throws IOException {
+ // Start the beginning of the container.
+ openContainer(tw, noIndent, level, separator, '{');
+
+ int index=0;
+ for (JsonObject.Member pair : obj) {
+ if (pair.getValue().hasBOLComment()) {
+ writeBOLComment(tw, pair.getValue(), level);
+ }
+
+ handleContainerLines(tw, obj.isCompact(), index, level, obj.getLineLength());
+ tw.write(escapeName(pair.getName(), forceQuoteObject(obj)));
+ tw.write(":");
+ boolean forceQuoteValue = forceQuoteValue(pair.getValue(), obj);
+ save(pair.getValue(), tw, level+1, " ", false, forceQuoteValue);
+ index++;
+ }
+ // Put interior comments at the bottom.
+ if (obj.hasInteriorComment()) {
+ writeInteriorComment(tw, obj, level);
+ }
+ // We've reached the end of the container. Close it off.
+ closeContainer(tw, obj.isCompact(), obj.size(), level, '}');
+ }
+
+ void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean noIndent, boolean forceQuotes) throws IOException {
+ // Start the beginning of the container.
+ openContainer(tw, noIndent, level, separator, '[');
+
+ int n=arr.size();
+ for (int i=0; i0) nl(tw, level);
+ tw.write(closeWith);
}
static String escapeName(String name) {
- if (name.length()==0 || needsEscapeName.matcher(name).find())
+ return escapeName(name, false);
+ }
+
+ static String escapeName(String name, boolean force) {
+ if (force || name.length()==0 || needsEscapeName.matcher(name).find())
return "\""+JsonWriter.escapeString(name)+"\"";
else
return name;
}
void writeString(String value, Writer tw, int level, String separator) throws IOException {
- if (value.length()==0) { tw.write(separator+"\"\""); return; }
+ if (value.length()==0) { tw.write("\"\""); return; }
char left=value.charAt(0), right=value.charAt(value.length()-1);
char left1=value.length()>1?value.charAt(1):'\0', left2=value.length()>2?value.charAt(2):'\0';
@@ -138,7 +269,7 @@ void writeString(String value, Writer tw, int level, String separator) throws IO
boolean noEscape=true;
for(char ch : valuec) { if (needsEscape(ch)) { noEscape=false; break; } }
- if (noEscape) { tw.write(separator+"\""+value+"\""); return; }
+ if (noEscape) { tw.write("\""+value+"\""); return; }
boolean noEscapeML=true, allWhite=true;
for(char ch : valuec) {
@@ -146,9 +277,9 @@ void writeString(String value, Writer tw, int level, String separator) throws IO
else if (!HjsonParser.isWhiteSpace(ch)) allWhite=false;
}
if (noEscapeML && !allWhite && !value.contains("'''")) writeMLString(value, tw, level, separator);
- else tw.write(separator+"\""+JsonWriter.escapeString(value)+"\"");
+ else tw.write("\""+JsonWriter.escapeString(value)+"\"");
}
- else tw.write(separator+value);
+ else tw.write(value);
}
void writeMLString(String value, Writer tw, int level, String separator) throws IOException {
@@ -173,6 +304,20 @@ void writeMLString(String value, Writer tw, int level, String separator) throws
}
}
+ void writeComment(String comment, Writer tw, int level) throws IOException {
+ String[] lines = comment.split("\r?\n");
+ // The first line is already indented. No nl() needed.
+ indentComment(tw);
+ tw.write(lines[0]);
+
+ // The rest of the lines are not.
+ for (int i=1; ip+1 && (text.charAt(p+1)=='/' || text.charAt(p+1)=='*'));
}
+ static boolean forceQuoteArray(JsonValue value, JsonArray array) {
+ return value.isString() && (array.isCompact() || array.getLineLength()>1 || value.hasEOLComment());
+ }
+
+ // Technically different methods.
+ static boolean forceQuoteValue(JsonValue value, JsonObject object) {
+ return value.isString() && (object.isCompact() || object.getLineLength()>1 || value.hasEOLComment());
+ }
+
+ static boolean forceQuoteObject(JsonObject object) {
+ return object.isCompact() || object.getLineLength() > 1;
+ }
+
static boolean needsQuotes(char c) {
switch (c) {
case '\t':
diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java
index 0623df0..46d69cb 100644
--- a/src/main/org/hjson/JsonArray.java
+++ b/src/main/org/hjson/JsonArray.java
@@ -22,8 +22,6 @@
******************************************************************************/
package org.hjson;
-import java.io.IOException;
-import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -66,12 +64,16 @@
public class JsonArray extends JsonValue implements Iterable {
private final List values;
+ private transient boolean compact;
+ private transient int lineLength;
/**
* Creates a new empty JsonArray.
*/
public JsonArray() {
values=new ArrayList();
+ compact=false;
+ lineLength=1;
}
/**
@@ -93,6 +95,8 @@ private JsonArray(JsonArray array, boolean unmodifiable) {
} else {
values=new ArrayList(array.values);
}
+ compact=array.compact;
+ lineLength=array.lineLength;
}
/**
@@ -124,6 +128,20 @@ public JsonArray add(int value) {
return this;
}
+ /**
+ * Variant of {@link #add(int)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(int value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the JSON representation of the specified long value to the end of this
* array.
@@ -137,6 +155,20 @@ public JsonArray add(long value) {
return this;
}
+ /**
+ * Variant of {@link #add(long)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(long value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the JSON representation of the specified float value to the end of this
* array.
@@ -150,6 +182,20 @@ public JsonArray add(float value) {
return this;
}
+ /**
+ * Variant of {@link #add(float)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(float value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the JSON representation of the specified double value to the end of this
* array.
@@ -163,6 +209,20 @@ public JsonArray add(double value) {
return this;
}
+ /**
+ * Variant of {@link #add(double)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(double value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the JSON representation of the specified boolean value to the end of this
* array.
@@ -176,6 +236,20 @@ public JsonArray add(boolean value) {
return this;
}
+ /**
+ * Variant of {@link #add(boolean)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(boolean value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the JSON representation of the specified string to the end of this array.
*
@@ -188,6 +262,20 @@ public JsonArray add(String value) {
return this;
}
+ /**
+ * Variant of {@link #add(String)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(String value, String comment) {
+ values.add(valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Appends the specified JSON value to the end of this array.
*
@@ -203,6 +291,20 @@ public JsonArray add(JsonValue value) {
return this;
}
+ /**
+ * Variant of {@link #add(JsonValue)} which appends a standard, BOL comment to the new value.
+ *
+ * @param value
+ * the value to add to the aray.
+ * @param comment
+ * the value to be used as this element's comment.
+ * @return the array itself, to enable method chaining.
+ */
+ public JsonArray add(JsonValue value, String comment) {
+ values.add(value.setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified int value.
@@ -221,6 +323,25 @@ public JsonArray set(int index, int value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, int)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, int value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified long value.
@@ -239,6 +360,25 @@ public JsonArray set(int index, long value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, long)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, long value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified float value.
@@ -257,6 +397,25 @@ public JsonArray set(int index, float value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, float)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, float value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified double value.
@@ -275,6 +434,25 @@ public JsonArray set(int index, double value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, double)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, double value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified boolean value.
@@ -293,6 +471,25 @@ public JsonArray set(int index, boolean value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, boolean)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, boolean value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the JSON representation of
* the specified string.
@@ -311,6 +508,25 @@ public JsonArray set(int index, String value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, String)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, String value, String comment) {
+ values.set(index, valueOf(value).setComment(comment));
+ return this;
+ }
+
/**
* Replaces the element at the specified position in this array with the specified JSON value.
*
@@ -331,6 +547,62 @@ public JsonArray set(int index, JsonValue value) {
return this;
}
+ /**
+ * Variant of {@link #set(int, JsonValue)} which appends a standard, BOL comment to the value.
+ *
+ * @param index
+ * the index of the array element to replace
+ * @param value
+ * the value to be stored at the specified array position
+ * @param comment
+ * the value to be used as the comment for this element.
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, i.e. index < 0 or
+ * index >= size
+ */
+ public JsonArray set(int index, JsonValue value, String comment) {
+ if (value==null) {
+ throw new NullPointerException("value is null");
+ }
+ values.set(index, value.setComment(comment));
+ return this;
+ }
+
+ /**
+ * Locates a member of this object according to the index and appends a standard, BOL
+ * comment.
+ *
+ * @param index
+ * the index of the member to be altered.
+ * @param comment
+ * the value to set as this member's comment.
+ * @return the array itself to enable chaining.
+ */
+ public JsonArray setComment(int index, String comment) {
+ values.get(index).setComment(comment);
+ return this;
+ }
+
+ /**
+ * Locates a member of this object according to the index and appends a new comment
+ * according to the input parameters.
+ *
+ * @param index
+ * The index of the member to be altered.
+ * @param type
+ * The where the comment should be placed relative to its value.
+ * @param style
+ * The style to use, i.e. #, //, etc.
+ * @param comment
+ * the value to set as this member's comment.
+ * @return the array itself to enable chaining.
+ */
+ public JsonArray setComment(int index, CommentType type, CommentStyle style, String comment) {
+ values.get(index).setComment(type, style, comment);
+ return this;
+ }
+
/**
* Removes the element at the specified index from this array.
*
@@ -389,6 +661,40 @@ public List values() {
return Collections.unmodifiableList(values);
}
+ /**
+ * Gets the number of elements to be displayed on a single line when this array is serialized.
+ *
+ * @return the number of elements per-line.
+ */
+ public int getLineLength() { return lineLength; }
+
+ /**
+ * Sets the number of elements to be displayed on a single line when this array is serialized.
+ * This does not check whether an incorrect comment syntax is used. As a result, you may wind
+ * up breaking your file when any element contains a single line comment.
+ *
+ * @param value
+ * the number of elements to be displayed per-line.
+ */
+ public JsonArray setLineLength(int value) { lineLength=value; return this; }
+
+ /**
+ * Detects whether this array is "compact" i.e. whether it should be displayed entirely on
+ * one line.
+ *
+ * @return whether this array is compact.
+ */
+ public boolean isCompact() { return compact; }
+
+ /**
+ * Sets whether this array should be "compact," i.e. whether it should be displayed entirely on
+ * one line.
+ *
+ * @param value
+ * whether this array should be compact.
+ */
+ public JsonArray setCompact(boolean value) { compact=value; return this; }
+
/**
* Returns an iterator over the values of this array in document order. The returned iterator
* cannot be used to modify this array.
diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java
index 0c5f11c..0c70417 100644
--- a/src/main/org/hjson/JsonLiteral.java
+++ b/src/main/org/hjson/JsonLiteral.java
@@ -22,8 +22,6 @@
******************************************************************************/
package org.hjson;
-import java.io.IOException;
-
@SuppressWarnings("serial") // use default serial UID
class JsonLiteral extends JsonValue {
diff --git a/src/main/org/hjson/JsonNumber.java b/src/main/org/hjson/JsonNumber.java
index 24b3251..46844a5 100644
--- a/src/main/org/hjson/JsonNumber.java
+++ b/src/main/org/hjson/JsonNumber.java
@@ -22,10 +22,8 @@
******************************************************************************/
package org.hjson;
-import java.io.IOException;
import java.math.BigDecimal;
-
@SuppressWarnings("serial") // use default serial UID
class JsonNumber extends JsonValue {
diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java
index 353f6c1..85aafb7 100644
--- a/src/main/org/hjson/JsonObject.java
+++ b/src/main/org/hjson/JsonObject.java
@@ -24,7 +24,6 @@
import java.io.IOException;
import java.io.ObjectInputStream;
-import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -32,7 +31,6 @@
import org.hjson.JsonObject.Member;
-
/**
* Represents a JSON object, a set of name/value pairs, where the names are strings and the values
* are JSON values.
@@ -77,6 +75,8 @@ public class JsonObject extends JsonValue implements Iterable {
private final List names;
private final List values;
private transient HashIndexTable table;
+ private transient boolean compact;
+ private transient int lineLength;
/**
* Creates a new empty JsonObject.
@@ -85,6 +85,8 @@ public JsonObject() {
names=new ArrayList();
values=new ArrayList();
table=new HashIndexTable();
+ compact=false;
+ lineLength=1;
}
/**
@@ -107,6 +109,8 @@ private JsonObject(JsonObject object, boolean unmodifiable) {
values=new ArrayList(object.values);
}
table=new HashIndexTable();
+ compact=object.compact;
+ lineLength=object.lineLength;
updateHashIndex();
}
@@ -146,8 +150,15 @@ public static JsonObject unmodifiableObject(JsonObject object) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, int value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, int)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, int value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -169,8 +180,15 @@ public JsonObject add(String name, int value) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, long value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, long)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, long value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -192,8 +210,15 @@ public JsonObject add(String name, long value) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, float value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, float)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, float value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -215,8 +240,15 @@ public JsonObject add(String name, float value) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, double value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, double)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, double value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -238,8 +270,15 @@ public JsonObject add(String name, double value) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, boolean value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, boolean)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, boolean value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -261,8 +300,15 @@ public JsonObject add(String name, boolean value) {
* @return the object itself, to enable method chaining
*/
public JsonObject add(String name, String value) {
- add(name, valueOf(value));
- return this;
+ return add(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #add(String, int)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, String value, String comment) {
+ return add(name, valueOf(value).setComment(comment));
}
/**
@@ -296,6 +342,18 @@ public JsonObject add(String name, JsonValue value) {
return this;
}
+ /**
+ * Variant of {@link #add(String, JsonValue)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject add(String name, JsonValue value, String comment) {
+ if (value==null) {
+ throw new NullPointerException("value is null");
+ }
+ value.setComment(comment);
+ return add(name, value);
+ }
+
/**
* Sets the value of the member with the specified name to the JSON representation of the
* specified int value. If this object does not contain a member with this name, a
@@ -314,8 +372,15 @@ public JsonObject add(String name, JsonValue value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, int value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #set(String, int)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, int value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -336,8 +401,14 @@ public JsonObject set(String name, int value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, long value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+ /**
+ * Variant of {@link #set(String, long)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, long value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -358,8 +429,15 @@ public JsonObject set(String name, long value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, float value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #set(String, float)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, float value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -380,8 +458,15 @@ public JsonObject set(String name, float value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, double value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #set(String, double)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, double value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -402,8 +487,15 @@ public JsonObject set(String name, double value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, boolean value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #set(String, boolean)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, boolean value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -424,8 +516,15 @@ public JsonObject set(String name, boolean value) {
* @return the object itself, to enable method chaining
*/
public JsonObject set(String name, String value) {
- set(name, valueOf(value));
- return this;
+ return set(name, valueOf(value));
+ }
+
+ /**
+ * Variant of {@link #set(String, String)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, String value, String comment) {
+ return set(name, valueOf(value).setComment(comment));
}
/**
@@ -462,6 +561,51 @@ public JsonObject set(String name, JsonValue value) {
return this;
}
+ /**
+ * Variant of {@link #set(String, JsonValue)} which appends a standard comment before the beginning of
+ * this value.
+ */
+ public JsonObject set(String name, JsonValue value, String comment) {
+ if (value==null) {
+ throw new NullPointerException("value is null");
+ }
+ return set(name, value.setComment(comment));
+ }
+
+ /**
+ * Locates a member of this object according to the key name and appends a standard, BOL
+ * comment.
+ *
+ * @param name
+ * the name of the member to be altered.
+ * @param comment
+ * the value to set as this member's comment.
+ * @return the object itself to enable chaining.
+ */
+ public JsonObject setComment(String name, String comment) {
+ get(name).setComment(comment);
+ return this;
+ }
+
+ /**
+ * Locates a member of this object according to the key name and appends a new comment
+ * according to the input parameters.
+ *
+ * @param name
+ * The name of the member to be altered.
+ * @param type
+ * The where the comment should be placed relative to its value.
+ * @param style
+ * The style to use, i.e. #, //, etc.
+ * @param comment
+ * the value to set as this member's comment.
+ * @return the object itself to enable chaining.
+ */
+ public JsonObject setComment(String name, CommentType type, CommentStyle style, String comment) {
+ get(name).setComment(type, style, comment);
+ return this;
+ }
+
/**
* Removes a member with the specified name from this object. If this object contains multiple
* members with the given name, only the last one is removed. If this object does not contain a
@@ -643,6 +787,66 @@ public List names() {
return Collections.unmodifiableList(names);
}
+ /**
+ * Gets the number of elements to be displayed on a single line when this array is serialized.
+ *
+ * @return the number of elements per-line.
+ */
+ public int getLineLength() { return lineLength; }
+
+ /**
+ * Sets the number of elements to be displayed on a single line when this array is serialized.
+ * This does not check whether an incorrect comment syntax is used. As a result, you may wind
+ * up breaking your file when any element contains a single line comment.
+ *
+ * @param value
+ * the number of elements to be displayed per-line.
+ */
+ public JsonObject setLineLength(int value) { lineLength=value; return this; }
+
+ /**
+ * Detects whether this object is "compact" i.e. whether it should be displayed entirely on
+ * one line.
+ *
+ * @return whether this object is compact.
+ */
+ public boolean isCompact() { return compact; }
+
+ /**
+ * Sets whether this object should be "compact," i.e. whether it should be displayed entirely on
+ * one line.
+ *
+ * @param value
+ * whether this object should be compact.
+ */
+ public JsonObject setCompact(boolean value) { compact=value; return this; }
+
+ /**
+ * Sorts all members of this object according to their keys, in alphabetical order.
+ *
+ * @return the object itself, to enable chaining.
+ */
+ public JsonObject sort() {
+ // Collect all members into an array.
+ List members=new ArrayList<>();
+ for (Member m : this) {
+ members.add(m);
+ }
+ // Sort the new array.
+ members.sort((m1, m2) -> m1.name.compareToIgnoreCase(m2.name));
+
+ // Clear the original values.
+ names.clear();
+ values.clear();
+
+ // Re-add the values, now in order.
+ for (Member m : members) {
+ add(m.name, m.value);
+ }
+
+ return this;
+ }
+
/**
* Returns an iterator over the members of this object in document order. The returned iterator
* cannot be used to modify this object.
diff --git a/src/main/org/hjson/JsonString.java b/src/main/org/hjson/JsonString.java
index 5aff6af..678c1e0 100644
--- a/src/main/org/hjson/JsonString.java
+++ b/src/main/org/hjson/JsonString.java
@@ -22,9 +22,6 @@
******************************************************************************/
package org.hjson;
-import java.io.IOException;
-
-
@SuppressWarnings("serial") // use default serial UID
class JsonString extends JsonValue {
diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java
index 856facb..c717a8a 100644
--- a/src/main/org/hjson/JsonValue.java
+++ b/src/main/org/hjson/JsonValue.java
@@ -22,7 +22,6 @@
******************************************************************************/
package org.hjson;
-import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
@@ -81,6 +80,11 @@ public abstract class JsonValue implements Serializable {
static String eol=System.getProperty("line.separator");
+ /**
+ * Comments that will be used by each type of value.
+ */
+ protected String bolComment="", eolComment="", intComment="";
+
/**
* Gets the newline charater(s).
*
@@ -271,7 +275,6 @@ public static JsonValue valueOfDsf(Object value) {
return new JsonDsf(value);
}
-
/**
* Gets the type of this JSON value.
*
@@ -354,6 +357,131 @@ public boolean isNull() {
return false;
}
+ /**
+ * Detects whether this value contains any comments.
+ *
+ * @return true if this value does contain comments.
+ */
+ public boolean hasComments() {
+ return hasBOLComment() || hasEOLComment() || hasInteriorComment();
+ }
+
+ /**
+ * Detects whether this value contains any beginning of line comments.
+ *
+ * @return true if this value does contain any BOL comments.
+ */
+ public boolean hasBOLComment() { return !bolComment.isEmpty(); }
+
+ /**
+ * Detects whether this value contains any end of line comments.
+ *
+ * @return true if this value does contain any EOL comments.
+ */
+ public boolean hasEOLComment() { return !eolComment.isEmpty(); }
+
+ /**
+ * Detects whether this value contains any interior comments, which may be present inside of
+ * object and array types with no association to any of their members.
+ *
+ * @return true if this value does contain any interior comments.
+ */
+ public boolean hasInteriorComment() { return !intComment.isEmpty(); }
+
+ /**
+ * Gets any comment that exists before this value.
+ *
+ * @return The full contents of this comment, including any comment indicators.
+ */
+ public String getBOLComment() { return bolComment; }
+
+ /**
+ * Gets any comment that exists after this value.
+ *
+ * @return The full contents of this comment, including any comment indicators.
+ */
+ public String getEOLComment() { return eolComment; }
+
+ /**
+ * Gets any non-BOL or EOL comment contained within this value.
+ *
+ * @return The full contents of this comment, including any comment indicators.
+ */
+ public String getInteriorComment() { return intComment; }
+
+ /**
+ * Adds a comment to be associated with this value.
+ * @param type Whether to place this comment before the line, after the line, or inside of the
+ * object or array, if applicable.
+ * @param style Whether to use #, //, or another such comment style.
+// * @param indent The number of spaces to indent before each line.
+ * @param comment The unformatted comment to be paired with this value.
+ */
+ public JsonValue setComment(CommentType type, CommentStyle style, String comment) {
+ StringBuilder formatted=new StringBuilder();
+ if (style.equals(CommentStyle.BLOCK)){
+ formatted.append("/*");
+ formatted.append(eol);
+ formatted.append(comment);
+ formatted.append(eol);
+ formatted.append("*/");
+ } else {
+ String[] lines=comment.split("\r?\n");
+ // Iterate through all lines in the comment.
+ for (int i=0; i0) formatted.append(eol);
+ // Add the indicator and extra space.
+ if (style.equals(CommentStyle.HASH)){
+ formatted.append("# ");
+ } else {
+ formatted.append("// ");
+ }
+ // Add the actual line from the comment.
+ formatted.append(lines[i]);
+ }
+ }
+ setFullComment(type, formatted.toString());
+ return this;
+ }
+
+ /**
+ * Shorthand for {@link #setComment(CommentType, CommentStyle, String)} which defaults to sending
+ * a beginning of line, single line comment, using the default indicator, #.
+ *
+ * @param comment The unformatted comment to be paired with this value.
+ */
+ public JsonValue setComment(String comment) {
+ return setComment(CommentType.BOL, CommentStyle.HASH, comment);
+ }
+
+ /**
+ * Shorthand for calling {@link #setComment(CommentType, CommentStyle, String)} which defaults to
+ * sending an end of line, single line comment, using the default indicator, #.
+ *
+ * @param comment The unformatted comment to be paired with this value.
+ */
+ public JsonValue setEOLComment(String comment) {
+ return setComment(CommentType.EOL, CommentStyle.HASH, comment);
+ }
+
+ /**
+ * Counterpart to {@link #setComment(CommentType, CommentStyle, String)} which receives
+ * the full, formatted comment to be stored by this value.
+ *
+ * @param type Whether to place this comment before the line, after the line, or inside of the
+ * object or array, if applicable.
+ * @param comment The fully-formatted comment to be paired with this value.
+ */
+ public JsonValue setFullComment(CommentType type, String comment) {
+ switch (type) {
+ case BOL: bolComment=comment; break;
+ case EOL: eolComment=comment; break;
+ case INTERIOR: intComment=comment; break;
+ }
+ return this;
+ }
+
/**
* Returns this JSON value as {@link JsonObject}, assuming that this value represents a JSON
* object. If this is not the case, an exception is thrown.
From 3ef838f4c222b4181131614dfffd151468ab0826 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 1 Jan 2019 12:30:07 -0600
Subject: [PATCH 02/63] remove debug line
---
src/main/org/hjson/HjsonParser.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 57433c2..948d650 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -100,7 +100,7 @@ JsonValue tryParse() throws IOException {
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
reset();
read();
- System.out.println("101: " + readBetweenVals());
+ readBetweenVals();
try { return checkTrailing(readValue()); }
catch (Exception exception2) { }
// throw original error
@@ -680,4 +680,4 @@ private boolean isHexDigit() {
private boolean isEndOfText() {
return current==-1;
}
-}
\ No newline at end of file
+}
From 66055ed218f0bef58ef7d02d7dd8c6342642b663 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 1 Jan 2019 12:35:11 -0600
Subject: [PATCH 03/63] remove commented lines
---
src/main/org/hjson/HjsonParser.java | 1 -
src/main/org/hjson/JsonValue.java | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 948d650..7a342c3 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -464,7 +464,6 @@ private void readEscape() throws IOException {
default:
throw expected("valid escape sequence");
}
-// capture=CaptureState.CAPTURE;
capture=true;
read();
}
diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java
index c717a8a..39feff4 100644
--- a/src/main/org/hjson/JsonValue.java
+++ b/src/main/org/hjson/JsonValue.java
@@ -414,7 +414,6 @@ public boolean hasComments() {
* @param type Whether to place this comment before the line, after the line, or inside of the
* object or array, if applicable.
* @param style Whether to use #, //, or another such comment style.
-// * @param indent The number of spaces to indent before each line.
* @param comment The unformatted comment to be paired with this value.
*/
public JsonValue setComment(CommentType type, CommentStyle style, String comment) {
From 5be309a09d7921d7bfbfd1c05ce81e4bdb19ac07 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 27 Jan 2019 11:28:01 -0600
Subject: [PATCH 04/63] consistency with hjson-js and potential bugs
---
src/main/org/hjson/HjsonOptions.java | 61 ++++++++++++++++++++--------
src/main/org/hjson/HjsonParser.java | 17 +++++---
src/main/org/hjson/HjsonWriter.java | 53 ++++++++++++------------
src/main/org/hjson/JsonArray.java | 18 ++++----
src/main/org/hjson/JsonObject.java | 39 ++++++++++--------
5 files changed, 112 insertions(+), 76 deletions(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index 7a2c7bb..8d6568d 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -28,19 +28,19 @@ public class HjsonOptions {
private IHjsonDsfProvider[] dsf;
private boolean legacyRoot;
- private boolean nlBraces;
- private boolean allowCompact;
+ private boolean bracesSameLine;
+ private boolean allowCondense;
private boolean allowMultiVal;
- private int indent, commentIndent;
+ private String space, commentSpace;
public HjsonOptions() {
dsf=new IHjsonDsfProvider[0];
legacyRoot=true;
- nlBraces=false;
- allowCompact=true;
+ bracesSameLine=true;
+ allowCondense=true;
allowMultiVal=true;
- indent=2;
- commentIndent=0;
+ space=" ";
+ commentSpace="";
}
/**
@@ -94,21 +94,21 @@ public HjsonOptions() {
*
* @return whether braces and brackets follow the K&R / Java syntax.
*/
- public boolean useNlBraces() { return nlBraces; }
+ public boolean bracesSameLine() { return bracesSameLine; }
/**
* Sets whether braces and brackets should be placed on new lines.
*
* @param value value
*/
- public HjsonOptions setNlBraces(boolean value) { nlBraces=value; return this; }
+ public HjsonOptions setBracesSameLine(boolean value) { bracesSameLine=value; return this; }
/**
* Detects whether more than one value is ever allowed on a single line.
*
* @return true if more than one value is allowed.
*/
- public boolean allowMultiVal() { return allowMultiVal; }
+ public boolean getAllowMultiVal() { return allowMultiVal; }
/**
* Sets whether more than one value is ever allowed to be placed on a single line.
@@ -122,41 +122,66 @@ public HjsonOptions() {
*
* @return true if objects and arrays can be displayed on a single line.
*/
- public boolean allowCompact() { return allowCompact; }
+ public boolean getAllowCondense() { return allowCondense; }
/**
* Sets whether objects and arrays can be displayed on a single line.
*
* @param value value
*/
- public HjsonOptions setAllowCompact(boolean value) { allowCompact=value; return this; }
+ public HjsonOptions setAllowCondense(boolean value) { allowCondense=value; return this; }
/**
- * Gets the number of spaces to be placed per-level on each new line.
+ * Gets the characters to be placed per-level on each new line.
*
* @return the number of spaces.
*/
- public int getIndent() { return indent; }
+ public String getSpace() { return space; }
+
+ /**
+ * Sets the characters to be placed per-level on each new line.
+ *
+ * @param value value
+ */
+ public HjsonOptions setSpace(String value) { space=value; return this; }
/**
* Sets the number of spaces to be placed per-level on each new line.
*
* @param value value
*/
- public HjsonOptions setIndent(int value) { indent=value; return this; }
+ public HjsonOptions setSpace(int value) { space=numSpaces(value); return this; }
/**
- * Gets the number of spaces to be placed before comments on new lines.
+ * Gets the characters to be placed before comments on new lines.
*
* @return the number of spaces.
*/
- public int getCommentIndent() { return commentIndent; }
+ public String getCommentSpace() { return commentSpace; }
+
+ /**
+ * Sets the characters to be placed before comments on new lines.
+ *
+ * @param value value
+ */
+ public HjsonOptions setCommentSpace(String value) { commentSpace=value; return this; }
/**
* Sets the number of spaces to be placed before comments on new lines.
*
* @param value value
*/
- public HjsonOptions setCommentIndent(int value) { commentIndent=value; return this; }
+ public HjsonOptions setCommentSpace(int value) { commentSpace=numSpaces(value); return this; }
+ /**
+ * Generates a String object based on the input number of spaces.
+ *
+ * @param value value
+ * @return a string containing the input number of spaces.
+ */
+ private String numSpaces(int value) {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i=0 && !(current=='*' && peek()=='/'));
read(); read();
@@ -623,6 +624,12 @@ private void skip(int num) throws IOException {
startCapture();
}
+ private void skipIfWhiteSpace(int num) throws IOException {
+ pauseCapture();
+ for (int i=0; i0) nl(tw, level);
tw.write(closeWith);
}
@@ -330,16 +327,16 @@ static boolean startsWithKeyword(String text) {
}
static boolean forceQuoteArray(JsonValue value, JsonArray array) {
- return value.isString() && (array.isCompact() || array.getLineLength()>1 || value.hasEOLComment());
+ return value.isString() && (array.isCondensed() || array.getLineLength()>1 || value.hasEOLComment());
}
// Technically different methods.
static boolean forceQuoteValue(JsonValue value, JsonObject object) {
- return value.isString() && (object.isCompact() || object.getLineLength()>1 || value.hasEOLComment());
+ return value.isString() && (object.isCondensed() || object.getLineLength()>1 || value.hasEOLComment());
}
static boolean forceQuoteObject(JsonObject object) {
- return object.isCompact() || object.getLineLength() > 1;
+ return object.isCondensed() || object.getLineLength() > 1;
}
static boolean needsQuotes(char c) {
diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java
index 46d69cb..f6055fa 100644
--- a/src/main/org/hjson/JsonArray.java
+++ b/src/main/org/hjson/JsonArray.java
@@ -64,7 +64,7 @@
public class JsonArray extends JsonValue implements Iterable {
private final List values;
- private transient boolean compact;
+ private transient boolean condensed;
private transient int lineLength;
/**
@@ -72,7 +72,7 @@ public class JsonArray extends JsonValue implements Iterable {
*/
public JsonArray() {
values=new ArrayList();
- compact=false;
+ condensed=false;
lineLength=1;
}
@@ -95,7 +95,7 @@ private JsonArray(JsonArray array, boolean unmodifiable) {
} else {
values=new ArrayList(array.values);
}
- compact=array.compact;
+ condensed=array.condensed;
lineLength=array.lineLength;
}
@@ -679,21 +679,21 @@ public List values() {
public JsonArray setLineLength(int value) { lineLength=value; return this; }
/**
- * Detects whether this array is "compact" i.e. whether it should be displayed entirely on
+ * Detects whether this array is "condensed" i.e. whether it should be displayed entirely on
* one line.
*
- * @return whether this array is compact.
+ * @return whether this array is condensed.
*/
- public boolean isCompact() { return compact; }
+ public boolean isCondensed() { return condensed; }
/**
- * Sets whether this array should be "compact," i.e. whether it should be displayed entirely on
+ * Sets whether this array should be "condensed," i.e. whether it should be displayed entirely on
* one line.
*
* @param value
- * whether this array should be compact.
+ * whether this array should be condensed.
*/
- public JsonArray setCompact(boolean value) { compact=value; return this; }
+ public JsonArray setCondensed(boolean value) { condensed=value; return this; }
/**
* Returns an iterator over the values of this array in document order. The returned iterator
diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java
index 85aafb7..c578639 100644
--- a/src/main/org/hjson/JsonObject.java
+++ b/src/main/org/hjson/JsonObject.java
@@ -24,10 +24,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
import org.hjson.JsonObject.Member;
@@ -75,7 +72,7 @@ public class JsonObject extends JsonValue implements Iterable {
private final List names;
private final List values;
private transient HashIndexTable table;
- private transient boolean compact;
+ private transient boolean condensed;
private transient int lineLength;
/**
@@ -85,7 +82,7 @@ public JsonObject() {
names=new ArrayList();
values=new ArrayList();
table=new HashIndexTable();
- compact=false;
+ condensed=false;
lineLength=1;
}
@@ -109,7 +106,7 @@ private JsonObject(JsonObject object, boolean unmodifiable) {
values=new ArrayList(object.values);
}
table=new HashIndexTable();
- compact=object.compact;
+ condensed=object.condensed;
lineLength=object.lineLength;
updateHashIndex();
}
@@ -805,21 +802,21 @@ public List names() {
public JsonObject setLineLength(int value) { lineLength=value; return this; }
/**
- * Detects whether this object is "compact" i.e. whether it should be displayed entirely on
+ * Detects whether this object is "condensed" i.e. whether it should be displayed entirely on
* one line.
*
- * @return whether this object is compact.
+ * @return whether this object is condensed.
*/
- public boolean isCompact() { return compact; }
+ public boolean isCondensed() { return condensed; }
/**
- * Sets whether this object should be "compact," i.e. whether it should be displayed entirely on
+ * Sets whether this object should be "condensed," i.e. whether it should be displayed entirely on
* one line.
*
* @param value
- * whether this object should be compact.
+ * whether this object should be condensed.
*/
- public JsonObject setCompact(boolean value) { compact=value; return this; }
+ public JsonObject setCondensed(boolean value) { condensed=value; return this; }
/**
* Sorts all members of this object according to their keys, in alphabetical order.
@@ -828,19 +825,22 @@ public List names() {
*/
public JsonObject sort() {
// Collect all members into an array.
- List members=new ArrayList<>();
+ List members=new ArrayList();
for (Member m : this) {
members.add(m);
}
+ // Get the underlying array so it can be sorted.
+ Member[] membersArray=members.toArray(new Member[members.size()]);
+
// Sort the new array.
- members.sort((m1, m2) -> m1.name.compareToIgnoreCase(m2.name));
+ Arrays.sort(membersArray, new MemberComparator());
// Clear the original values.
names.clear();
values.clear();
// Re-add the values, now in order.
- for (Member m : members) {
+ for (Member m : membersArray) {
add(m.name, m.value);
}
@@ -1033,4 +1033,11 @@ private int hashSlotfor (Object element) {
return element.hashCode() & hashTable.length-1;
}
}
+
+ public static class MemberComparator implements Comparator {
+ @Override
+ public int compare(Member m1, Member m2) {
+ return m1.name.compareToIgnoreCase(m2.name);
+ }
+ }
}
From c9501e34f796e01c1f8f0ed02cec081dacca983a Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 27 Jan 2019 11:47:11 -0600
Subject: [PATCH 05/63] update javadocs
---
src/main/org/hjson/HjsonOptions.java | 10 +++
src/main/org/hjson/JsonArray.java | 2 +
src/main/org/hjson/JsonObject.java | 114 +++++++++++++++++++++++++++
src/main/org/hjson/JsonValue.java | 6 +-
4 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index 8d6568d..46c503a 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -54,6 +54,7 @@ public HjsonOptions() {
* Sets the DSF providers.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setDsfProviders(IHjsonDsfProvider... value) { dsf=value.clone(); return this; }
@@ -68,6 +69,7 @@ public HjsonOptions() {
* Sets whether root braces should be emitted.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setParseLegacyRoot(boolean value) { legacyRoot=value; return this; }
@@ -85,6 +87,7 @@ public HjsonOptions() {
*
* @deprecated root braces are always emitted.
* @param value value
+ * @return this, to enable chaining
*/
@Deprecated
public HjsonOptions setEmitRootBraces(boolean value) { return this; }
@@ -100,6 +103,7 @@ public HjsonOptions() {
* Sets whether braces and brackets should be placed on new lines.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setBracesSameLine(boolean value) { bracesSameLine=value; return this; }
@@ -114,6 +118,7 @@ public HjsonOptions() {
* Sets whether more than one value is ever allowed to be placed on a single line.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setAllowMultiVal(boolean value) { allowMultiVal=value; return this; }
@@ -128,6 +133,7 @@ public HjsonOptions() {
* Sets whether objects and arrays can be displayed on a single line.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setAllowCondense(boolean value) { allowCondense=value; return this; }
@@ -142,6 +148,7 @@ public HjsonOptions() {
* Sets the characters to be placed per-level on each new line.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setSpace(String value) { space=value; return this; }
@@ -149,6 +156,7 @@ public HjsonOptions() {
* Sets the number of spaces to be placed per-level on each new line.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setSpace(int value) { space=numSpaces(value); return this; }
@@ -163,6 +171,7 @@ public HjsonOptions() {
* Sets the characters to be placed before comments on new lines.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setCommentSpace(String value) { commentSpace=value; return this; }
@@ -170,6 +179,7 @@ public HjsonOptions() {
* Sets the number of spaces to be placed before comments on new lines.
*
* @param value value
+ * @return this, to enable chaining
*/
public HjsonOptions setCommentSpace(int value) { commentSpace=numSpaces(value); return this; }
diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java
index f6055fa..ad49748 100644
--- a/src/main/org/hjson/JsonArray.java
+++ b/src/main/org/hjson/JsonArray.java
@@ -675,6 +675,7 @@ public List values() {
*
* @param value
* the number of elements to be displayed per-line.
+ * @return this, to enable chaining
*/
public JsonArray setLineLength(int value) { lineLength=value; return this; }
@@ -692,6 +693,7 @@ public List values() {
*
* @param value
* whether this array should be condensed.
+ * @return this, to enable chaining
*/
public JsonArray setCondensed(boolean value) { condensed=value; return this; }
diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java
index c578639..08b29eb 100644
--- a/src/main/org/hjson/JsonObject.java
+++ b/src/main/org/hjson/JsonObject.java
@@ -153,6 +153,14 @@ public JsonObject add(String name, int value) {
/**
* Variant of {@link #add(String, int)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, int value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -183,6 +191,14 @@ public JsonObject add(String name, long value) {
/**
* Variant of {@link #add(String, long)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, long value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -213,6 +229,14 @@ public JsonObject add(String name, float value) {
/**
* Variant of {@link #add(String, float)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, float value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -243,6 +267,14 @@ public JsonObject add(String name, double value) {
/**
* Variant of {@link #add(String, double)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, double value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -273,6 +305,14 @@ public JsonObject add(String name, boolean value) {
/**
* Variant of {@link #add(String, boolean)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, boolean value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -303,6 +343,14 @@ public JsonObject add(String name, String value) {
/**
* Variant of {@link #add(String, int)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, String value, String comment) {
return add(name, valueOf(value).setComment(comment));
@@ -342,6 +390,14 @@ public JsonObject add(String name, JsonValue value) {
/**
* Variant of {@link #add(String, JsonValue)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject add(String name, JsonValue value, String comment) {
if (value==null) {
@@ -375,6 +431,14 @@ public JsonObject set(String name, int value) {
/**
* Variant of {@link #set(String, int)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, int value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -403,6 +467,14 @@ public JsonObject set(String name, long value) {
/**
* Variant of {@link #set(String, long)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, long value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -432,6 +504,14 @@ public JsonObject set(String name, float value) {
/**
* Variant of {@link #set(String, float)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, float value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -461,6 +541,14 @@ public JsonObject set(String name, double value) {
/**
* Variant of {@link #set(String, double)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, double value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -490,6 +578,14 @@ public JsonObject set(String name, boolean value) {
/**
* Variant of {@link #set(String, boolean)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, boolean value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -519,6 +615,14 @@ public JsonObject set(String name, String value) {
/**
* Variant of {@link #set(String, String)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, String value, String comment) {
return set(name, valueOf(value).setComment(comment));
@@ -561,6 +665,14 @@ public JsonObject set(String name, JsonValue value) {
/**
* Variant of {@link #set(String, JsonValue)} which appends a standard comment before the beginning of
* this value.
+ *
+ * @param name
+ * the name of the member to add
+ * @param value
+ * the value of the member to add
+ * @param comment
+ * the string to be used as this value's comment
+ * @return the object itself, to enable method chaining
*/
public JsonObject set(String name, JsonValue value, String comment) {
if (value==null) {
@@ -798,6 +910,7 @@ public List names() {
*
* @param value
* the number of elements to be displayed per-line.
+ * @return the object itself, to enable method chaining
*/
public JsonObject setLineLength(int value) { lineLength=value; return this; }
@@ -815,6 +928,7 @@ public List names() {
*
* @param value
* whether this object should be condensed.
+ * @return the object itself, to enable method chaining
*/
public JsonObject setCondensed(boolean value) { condensed=value; return this; }
diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java
index 39feff4..95c0d34 100644
--- a/src/main/org/hjson/JsonValue.java
+++ b/src/main/org/hjson/JsonValue.java
@@ -413,8 +413,9 @@ public boolean hasComments() {
* Adds a comment to be associated with this value.
* @param type Whether to place this comment before the line, after the line, or inside of the
* object or array, if applicable.
- * @param style Whether to use #, //, or another such comment style.
+ * @param style Whether to use #, //, or another such comment style.
* @param comment The unformatted comment to be paired with this value.
+ * @return this, to enable chaining
*/
public JsonValue setComment(CommentType type, CommentStyle style, String comment) {
StringBuilder formatted=new StringBuilder();
@@ -449,6 +450,7 @@ public JsonValue setComment(CommentType type, CommentStyle style, String comment
* a beginning of line, single line comment, using the default indicator, #.
*
* @param comment The unformatted comment to be paired with this value.
+ * @return this, to enable chaining
*/
public JsonValue setComment(String comment) {
return setComment(CommentType.BOL, CommentStyle.HASH, comment);
@@ -459,6 +461,7 @@ public JsonValue setComment(String comment) {
* sending an end of line, single line comment, using the default indicator, #.
*
* @param comment The unformatted comment to be paired with this value.
+ * @return this, to enable chaining
*/
public JsonValue setEOLComment(String comment) {
return setComment(CommentType.EOL, CommentStyle.HASH, comment);
@@ -471,6 +474,7 @@ public JsonValue setEOLComment(String comment) {
* @param type Whether to place this comment before the line, after the line, or inside of the
* object or array, if applicable.
* @param comment The fully-formatted comment to be paired with this value.
+ * @return this, to enable chaining
*/
public JsonValue setFullComment(CommentType type, String comment) {
switch (type) {
From 4139b97c67da6f7b0673c2e778a5cb94c21d4986 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 27 Jan 2019 11:54:31 -0600
Subject: [PATCH 06/63] appease the Travis-CI gods
by fixing a non-bug
---
src/main/org/hjson/HjsonOptions.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index 46c503a..a1a0e8a 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -95,7 +95,7 @@ public HjsonOptions() {
/**
* Detects whether braces and brackets should be placed on new lines.
*
- * @return whether braces and brackets follow the K&R / Java syntax.
+ * @return whether braces and brackets follow the K&R / Java syntax.
*/
public boolean bracesSameLine() { return bracesSameLine; }
From 91654a24f44e25eb5a062c301e6e91fbb297ab13 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 27 Jan 2019 11:57:41 -0600
Subject: [PATCH 07/63] just playing around, at this point
---
src/main/org/hjson/HjsonOptions.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index a1a0e8a..f489894 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -95,7 +95,7 @@ public HjsonOptions() {
/**
* Detects whether braces and brackets should be placed on new lines.
*
- * @return whether braces and brackets follow the K&R / Java syntax.
+ * @return whether braces and brackets follow the KR / Java syntax.
*/
public boolean bracesSameLine() { return bracesSameLine; }
From 72e42920a45fbcb4ef5de51e3a6168ff1d164c20 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 27 Jan 2019 20:49:32 -0600
Subject: [PATCH 08/63] fix ML string comment bug
---
src/main/org/hjson/HjsonParser.java | 1 -
src/main/org/hjson/HjsonWriter.java | 12 +++++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 6612323..5fb8533 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -348,7 +348,6 @@ private String readName() throws IOException {
}
private String readMlString() throws IOException {
-
// Parse a multiline string value.
StringBuilder sb=new StringBuilder();
int triple=0;
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index 15b2d77..86a7f16 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -107,9 +107,7 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea
break;
case STRING:
tw.write(separator);
- if (forceQuotes) tw.write('"');
- writeString(value.asString(), tw, level, separator);
- if (forceQuotes) tw.write('"');
+ writeString(value.asString(), tw, level, forceQuotes, separator);
break;
default:
tw.write(separator);
@@ -238,7 +236,7 @@ static String escapeName(String name, boolean force) {
return name;
}
- void writeString(String value, Writer tw, int level, String separator) throws IOException {
+ void writeString(String value, Writer tw, int level, boolean forceQuotes, String separator) throws IOException {
if (value.length()==0) { tw.write("\"\""); return; }
char left=value.charAt(0), right=value.charAt(value.length()-1);
@@ -276,7 +274,11 @@ void writeString(String value, Writer tw, int level, String separator) throws IO
if (noEscapeML && !allWhite && !value.contains("'''")) writeMLString(value, tw, level, separator);
else tw.write("\""+JsonWriter.escapeString(value)+"\"");
}
- else tw.write(value);
+ else {
+ if (forceQuotes) tw.write('"');
+ tw.write(value);
+ if (forceQuotes) tw.write('"');
+ }
}
void writeMLString(String value, Writer tw, int level, String separator) throws IOException {
From 57424ee3b73e00b7e0f9de8820b52ad8834d224c Mon Sep 17 00:00:00 2001
From: Dakota Sullivan
Date: Fri, 8 Feb 2019 19:16:58 -0700
Subject: [PATCH 09/63] Gate new comments feature behind outputComments flag
---
src/main/org/hjson/HjsonOptions.java | 17 ++++++++++++++
src/main/org/hjson/HjsonWriter.java | 33 ++++++++++++++++++----------
src/main/org/hjson/JsonValue.java | 3 ++-
src/main/org/hjson/Stringify.java | 2 ++
4 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index f489894..13eb806 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -27,6 +27,7 @@
public class HjsonOptions {
private IHjsonDsfProvider[] dsf;
+ private boolean outputComments;
private boolean legacyRoot;
private boolean bracesSameLine;
private boolean allowCondense;
@@ -41,6 +42,7 @@ public HjsonOptions() {
allowMultiVal=true;
space=" ";
commentSpace="";
+ outputComments=false;
}
/**
@@ -194,4 +196,19 @@ private String numSpaces(int value) {
for (int i=0; ip+1 && (text.charAt(p+1)=='/' || text.charAt(p+1)=='*'));
}
- static boolean forceQuoteArray(JsonValue value, JsonArray array) {
- return value.isString() && (array.isCondensed() || array.getLineLength()>1 || value.hasEOLComment());
+ static boolean forceQuoteArray(JsonValue value, JsonArray array, boolean outputComments) {
+ return value.isString() && (array.isCondensed() || array.getLineLength()>1 || (outputComments && value.hasEOLComment()));
}
// Technically different methods.
- static boolean forceQuoteValue(JsonValue value, JsonObject object) {
- return value.isString() && (object.isCondensed() || object.getLineLength()>1 || value.hasEOLComment());
+ static boolean forceQuoteValue(JsonValue value, JsonObject object, boolean outputComments) {
+ return value.isString() && (object.isCondensed() || object.getLineLength()>1 || (outputComments && value.hasEOLComment()));
}
static boolean forceQuoteObject(JsonObject object) {
diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java
index 95c0d34..89cc5c3 100644
--- a/src/main/org/hjson/JsonValue.java
+++ b/src/main/org/hjson/JsonValue.java
@@ -632,7 +632,8 @@ public void writeTo(Writer writer, Stringify format) throws IOException {
switch (format) {
case PLAIN: new JsonWriter(false).save(this, buffer, 0); break;
case FORMATTED: new JsonWriter(true).save(this, buffer, 0); break;
- case HJSON: new HjsonWriter(null).save(this, buffer, 0, "", true); break;
+ case HJSON: new HjsonWriter(null, false).save(this, buffer, 0, "", true); break;
+ case HJSON_COMMENTS: new HjsonWriter(null, true).save(this, buffer, 0, "", true); break;
}
buffer.flush();
}
diff --git a/src/main/org/hjson/Stringify.java b/src/main/org/hjson/Stringify.java
index b7f7484..cc1e103 100644
--- a/src/main/org/hjson/Stringify.java
+++ b/src/main/org/hjson/Stringify.java
@@ -29,5 +29,7 @@ public enum Stringify {
FORMATTED,
/** Hjson. */
HJSON,
+ /** Hjson w/ comments */
+ HJSON_COMMENTS,
}
From f7fa38d3f7e69a7c92aceb1e3a960b96a785996f Mon Sep 17 00:00:00 2001
From: Dakota Sullivan
Date: Fri, 8 Feb 2019 19:26:20 -0700
Subject: [PATCH 10/63] Disable bracesSameLine by default
---
src/main/org/hjson/HjsonOptions.java | 2 +-
src/main/org/hjson/HjsonWriter.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java
index 13eb806..c983460 100644
--- a/src/main/org/hjson/HjsonOptions.java
+++ b/src/main/org/hjson/HjsonOptions.java
@@ -37,7 +37,7 @@ public class HjsonOptions {
public HjsonOptions() {
dsf=new IHjsonDsfProvider[0];
legacyRoot=true;
- bracesSameLine=true;
+ bracesSameLine=false;
allowCondense=true;
allowMultiVal=true;
space=" ";
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index 7b6789b..e4d5bc1 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -47,7 +47,7 @@ public HjsonWriter(HjsonOptions options) {
outputComments=options.getOutputComments();
} else {
dsfProviders=new IHjsonDsfProvider[0];
- bracesSameLine=true;
+ bracesSameLine=false;
allowCondense=true;
allowMultiVal=true;
space=" ";
From 1b5ec5f46f684643845d9963b6e2f817ebd22a4c Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Mon, 18 Feb 2019 22:01:00 -0600
Subject: [PATCH 11/63] fix line length differences between versions
---
src/main/org/hjson/HjsonParser.java | 2 +-
src/main/org/hjson/HjsonWriter.java | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 5fb8533..427cc45 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -239,7 +239,7 @@ private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
if (!objectWithoutBraces) read();
JsonObject object=new JsonObject();
object.setCondensed(isContainerCompact());
- int sumLineLength=1;
+ int sumLineLength=0;
int lineLength=1;
int numLines=0;
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index e4d5bc1..de00a00 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -104,11 +104,11 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea
switch (value.getType()) {
case OBJECT:
JsonObject obj=value.asObject();
- writeObject(obj, tw, level, separator, noIndent, forceQuotes);
+ writeObject(obj, tw, level, separator, noIndent);
break;
case ARRAY:
JsonArray arr=value.asArray();
- writeArray(arr, tw, level, separator, noIndent, forceQuotes);
+ writeArray(arr, tw, level, separator, noIndent);
break;
case BOOLEAN:
tw.write(separator);
@@ -132,7 +132,7 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea
}
}
- void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean noIndent, boolean forceQuotes) throws IOException {
+ void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean noIndent) throws IOException {
// Start the beginning of the container.
openContainer(tw, noIndent, level, separator, '{');
@@ -157,7 +157,7 @@ void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean
closeContainer(tw, obj.isCondensed(), obj.size(), level, '}');
}
- void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean noIndent, boolean forceQuotes) throws IOException {
+ void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean noIndent) throws IOException {
// Start the beginning of the container.
openContainer(tw, noIndent, level, separator, '[');
@@ -347,7 +347,7 @@ static boolean forceQuoteValue(JsonValue value, JsonObject object, boolean outpu
}
static boolean forceQuoteObject(JsonObject object) {
- return object.isCondensed() || object.getLineLength() > 1;
+ return object.isCondensed() || object.getLineLength()>1;
}
static boolean needsQuotes(char c) {
From e9d7404f4f37408d26091875f2c4222c2ea2d673 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 19 Feb 2019 17:59:47 -0600
Subject: [PATCH 12/63] adjust array BOL position
---
src/main/org/hjson/HjsonWriter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index de00a00..88b0fe8 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -165,7 +165,7 @@ void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean n
for (int i=0; i
Date: Sun, 24 Feb 2019 17:55:38 -0600
Subject: [PATCH 13/63] literals are no longer singletons
---
src/main/org/hjson/HjsonParser.java | 6 +++---
src/main/org/hjson/JsonLiteral.java | 16 ++++++++++++----
src/main/org/hjson/JsonParser.java | 6 +++---
src/main/org/hjson/JsonValue.java | 23 ++---------------------
4 files changed, 20 insertions(+), 31 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 427cc45..5f3e8a5 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -149,9 +149,9 @@ private JsonValue readTfnns() throws IOException {
case 'n':
case 't':
String svalue=value.toString().trim();
- if (svalue.equals("false")) return JsonValue.FALSE;
- else if (svalue.equals("null")) return JsonValue.NULL;
- else if (svalue.equals("true")) return JsonValue.TRUE;
+ if (svalue.equals("false")) return JsonLiteral.jsonFalse();
+ else if (svalue.equals("null")) return JsonLiteral.jsonNull();
+ else if (svalue.equals("true")) return JsonLiteral.jsonTrue();
break;
default:
if (first=='-' || first>='0' && first<='9') {
diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java
index 0c70417..e391a47 100644
--- a/src/main/org/hjson/JsonLiteral.java
+++ b/src/main/org/hjson/JsonLiteral.java
@@ -28,10 +28,6 @@ class JsonLiteral extends JsonValue {
enum Iv { T, F, N };
- static final JsonValue NULL=new JsonLiteral(Iv.N);
- static final JsonValue TRUE=new JsonLiteral(Iv.T);
- static final JsonValue FALSE=new JsonLiteral(Iv.F);
-
private final Iv value;
private JsonLiteral(Iv value) {
@@ -48,6 +44,18 @@ public String toString() {
}
}
+ public static JsonLiteral jsonNull() {
+ return new JsonLiteral(Iv.N);
+ }
+
+ public static JsonLiteral jsonTrue() {
+ return new JsonLiteral(Iv.T);
+ }
+
+ public static JsonLiteral jsonFalse() {
+ return new JsonLiteral(Iv.F);
+ }
+
@Override
public int hashCode() {
return value.hashCode();
diff --git a/src/main/org/hjson/JsonParser.java b/src/main/org/hjson/JsonParser.java
index bbf7501..702464a 100644
--- a/src/main/org/hjson/JsonParser.java
+++ b/src/main/org/hjson/JsonParser.java
@@ -162,7 +162,7 @@ private JsonValue readNull() throws IOException {
readRequiredChar('u');
readRequiredChar('l');
readRequiredChar('l');
- return JsonValue.NULL;
+ return JsonLiteral.jsonNull();
}
private JsonValue readTrue() throws IOException {
@@ -170,7 +170,7 @@ private JsonValue readTrue() throws IOException {
readRequiredChar('r');
readRequiredChar('u');
readRequiredChar('e');
- return JsonValue.TRUE;
+ return JsonLiteral.jsonTrue();
}
private JsonValue readFalse() throws IOException {
@@ -179,7 +179,7 @@ private JsonValue readFalse() throws IOException {
readRequiredChar('l');
readRequiredChar('s');
readRequiredChar('e');
- return JsonValue.FALSE;
+ return JsonLiteral.jsonFalse();
}
private void readRequiredChar(char ch) throws IOException {
diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java
index 89cc5c3..9cb815d 100644
--- a/src/main/org/hjson/JsonValue.java
+++ b/src/main/org/hjson/JsonValue.java
@@ -33,10 +33,6 @@
* a number, a string, or one of the literals
* true, false, and null.
*
- * The literals true, false, and null are
- * represented by the constants {@link #TRUE}, {@link #FALSE}, and {@link #NULL}.
- *
- *
* JSON objects and arrays are represented by the subtypes
* {@link JsonObject} and {@link JsonArray}. Instances of these types can be created using the
* public constructors of these classes.
@@ -63,21 +59,6 @@
@SuppressWarnings("serial") // use default serial UID
public abstract class JsonValue implements Serializable {
- /**
- * Represents the JSON literal true.
- */
- public static final JsonValue TRUE=JsonLiteral.TRUE;
-
- /**
- * Represents the JSON literal false.
- */
- public static final JsonValue FALSE=JsonLiteral.FALSE;
-
- /**
- * Represents the JSON literal null.
- */
- public static final JsonValue NULL=JsonLiteral.NULL;
-
static String eol=System.getProperty("line.separator");
/**
@@ -252,7 +233,7 @@ public static JsonValue valueOf(double value) {
* @return a JSON value that represents the given string
*/
public static JsonValue valueOf(String string) {
- return string==null ? NULL : new JsonString(string);
+ return string==null ? JsonLiteral.jsonNull() : new JsonString(string);
}
/**
@@ -262,7 +243,7 @@ public static JsonValue valueOf(String string) {
* @return a JSON value that represents the given value
*/
public static JsonValue valueOf(boolean value) {
- return value ? TRUE : FALSE;
+ return value ? JsonLiteral.jsonTrue() : JsonLiteral.jsonFalse();
}
/**
From 42b6b48afdd0e8d8925a1ede4b3810330d2e9897 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 24 Feb 2019 18:15:40 -0600
Subject: [PATCH 14/63] container formatting
---
src/main/org/hjson/HjsonWriter.java | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index 88b0fe8..f6a51ce 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -134,7 +134,7 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea
void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean noIndent) throws IOException {
// Start the beginning of the container.
- openContainer(tw, noIndent, level, separator, '{');
+ openContainer(tw, noIndent, obj.isCondensed(), level, separator, '{');
int index=0;
for (JsonObject.Member pair : obj) {
@@ -159,7 +159,7 @@ void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean
void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean noIndent) throws IOException {
// Start the beginning of the container.
- openContainer(tw, noIndent, level, separator, '[');
+ openContainer(tw, noIndent, arr.isCondensed(), level, separator, '[');
int n=arr.size();
for (int i=0; i0) nl(tw, level);
+ if (size>0) {
+ if (compact && allowCondense && allowMultiVal) tw.write(' ');
+ else nl(tw, level);
+ }
tw.write(closeWith);
}
From 90cd3cdabde90970b0fda704722c47ea39378e39 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 24 Feb 2019 20:10:38 -0600
Subject: [PATCH 15/63] allow array lines to begin with commas
---
src/main/org/hjson/HjsonParser.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 5f3e8a5..f7320de 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -191,6 +191,8 @@ private JsonArray readArray() throws IOException {
} else if (isEndOfText()) {
throw error("End of input while parsing an array (did you forget a closing ']'?)");
}
+ // Allow lines to begin with commas
+ readIf(',');
// Value comes next.
JsonValue value=readValue();
value.setFullComment(CommentType.BOL, bol);
From 2c126719a8649beae0090964c6f65373d8bbc678 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 24 Feb 2019 21:23:53 -0600
Subject: [PATCH 16/63] Important new formatting.
---
.gitignore | 1 +
src/main/org/hjson/HjsonParser.java | 15 +++++++++------
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index ee3c2c8..6f0fef2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,6 @@ gradle
gradlew
gradle.bat
build/
+out/
hjson.iml
.idea
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index f7320de..7240f2c 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -172,7 +172,6 @@ private JsonArray readArray() throws IOException {
read();
JsonArray array=new JsonArray();
boolean compact=isContainerCompact();
- array.setCondensed(compact);
int sumLineLength=0;
int lineLength=1;
int numLines=0;
@@ -191,8 +190,11 @@ private JsonArray readArray() throws IOException {
} else if (isEndOfText()) {
throw error("End of input while parsing an array (did you forget a closing ']'?)");
}
- // Allow lines to begin with commas
- readIf(',');
+ // Allow commas to exist after new lines.
+ if (readIf(',')) {
+ compact=false; // Can no longer be treated as compact.
+ continue;
+ }
// Value comes next.
JsonValue value=readValue();
value.setFullComment(CommentType.BOL, bol);
@@ -211,7 +213,7 @@ private JsonArray readArray() throws IOException {
if (current!='\n') {
// There was something else on this line.
// See if it was an EOL #.
- String eol = readBetweenVals(true);
+ String eol=readBetweenVals(true);
if (!eol.isEmpty()) { // This is an EOL #.
value.setFullComment(CommentType.EOL, eol);
@@ -233,6 +235,7 @@ private JsonArray readArray() throws IOException {
} else if (compact) {
array.setLineLength(array.size());
}
+ array.setCondensed(compact);
return array;
}
@@ -277,7 +280,7 @@ private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
readBetweenVals();
// The value itself.
- JsonValue value = readValue();
+ JsonValue value=readValue();
// Skip whitespace surrounding a comma.
skipToNL();
@@ -293,7 +296,7 @@ private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
if (current!='\n') {
// There was something else on this line.
// See if it was an EOL #.
- String eol = readBetweenVals(true);
+ String eol=readBetweenVals(true);
if (!eol.isEmpty()) { // This is an EOL #.
value.setFullComment(CommentType.EOL, eol);
From 799ba747e2250e496b9340e719ee329a19b6b638 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Sun, 24 Feb 2019 22:20:36 -0600
Subject: [PATCH 17/63] Fixed some ML spaces; Update tests
---
assets/mltabs_result.hjson | 2 +-
assets/pass1_result.hjson | 27 +++----------------
assets/pass1_result.json | 6 ++---
assets/pass1_test.json | 2 +-
assets/pass2_result.hjson | 40 +----------------------------
assets/strings_result.hjson | 22 +++-------------
src/main/org/hjson/HjsonParser.java | 14 +++++++++-
src/main/org/hjson/HjsonWriter.java | 6 ++---
8 files changed, 29 insertions(+), 90 deletions(-)
diff --git a/assets/mltabs_result.hjson b/assets/mltabs_result.hjson
index 4b11b84..72e3bc2 100644
--- a/assets/mltabs_result.hjson
+++ b/assets/mltabs_result.hjson
@@ -1,5 +1,5 @@
{
- foo:
+ foo:
'''
bar joe
oki doki
diff --git a/assets/pass1_result.hjson b/assets/pass1_result.hjson
index 2a3f4c9..df9f3b0 100644
--- a/assets/pass1_result.hjson
+++ b/assets/pass1_result.hjson
@@ -1,11 +1,6 @@
[
JSON Test Pattern pass1
- {
- "object with 1 member":
- [
- array with 1 element
- ]
- }
+ { "object with 1 member": [ "array with 1 element" ] }
{}
[]
-42
@@ -42,24 +37,10 @@
"# -- --> */": " "
" s p a c e d ":
[
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- ]
- compact:
- [
- 1
- 2
- 3
- 4
- 5
- 6
- 7
+ 1, 2, 3
+ 4, 5, 6
]
+ compact: [ 1, 2, 3, 4, 5, 6 ]
jsontext: '''{"object with 1 member":["array with 1 element"]}'''
quotes: " " %22 0x22 034 "
"/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?": A key can be any string
diff --git a/assets/pass1_result.json b/assets/pass1_result.json
index 69b354d..1925717 100644
--- a/assets/pass1_result.json
+++ b/assets/pass1_result.json
@@ -45,8 +45,7 @@
3,
4,
5,
- 6,
- 7
+ 6
],
"compact": [
1,
@@ -54,8 +53,7 @@
3,
4,
5,
- 6,
- 7
+ 6
],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "" \" %22 0x22 034 "",
diff --git a/assets/pass1_test.json b/assets/pass1_test.json
index 61cfd90..41846d9 100644
--- a/assets/pass1_test.json
+++ b/assets/pass1_test.json
@@ -39,7 +39,7 @@
,
-4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+4 , 5 , 6 ,],"compact":[1,2,3,4,5,6],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "" \u0022 %22 0x22 034 "",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
diff --git a/assets/pass2_result.hjson b/assets/pass2_result.hjson
index 5a9fd5e..17cce1d 100644
--- a/assets/pass2_result.hjson
+++ b/assets/pass2_result.hjson
@@ -1,39 +1 @@
-[
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- [
- Not too deep
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
- ]
-]
\ No newline at end of file
+[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ "Not too deep" ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ]
\ No newline at end of file
diff --git a/assets/strings_result.hjson b/assets/strings_result.hjson
index 6569fe7..73fb766 100644
--- a/assets/strings_result.hjson
+++ b/assets/strings_result.hjson
@@ -9,19 +9,19 @@
notml2: " \n"
notml3: "\n \n \n \n"
notml4: "\t\n"
- multiline1:
+ multiline1:
'''
first line
indented line
last line
'''
- multiline2:
+ multiline2:
'''
first line
indented line
last line
'''
- multiline3:
+ multiline3:
'''
first line
indented line
@@ -51,21 +51,7 @@
yes: true
no: false
null: null
- array:
- [
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
- -1
- 0.5
- ]
+ array: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1, 0.5 ]
}
special:
{
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 7240f2c..96276a1 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -191,7 +191,7 @@ private JsonArray readArray() throws IOException {
throw error("End of input while parsing an array (did you forget a closing ']'?)");
}
// Allow commas to exist after new lines.
- if (readIf(',')) {
+ if (array.size() > 0 && readIf(',')) {
compact=false; // Can no longer be treated as compact.
continue;
}
@@ -204,6 +204,12 @@ private JsonArray readArray() throws IOException {
if (readIf(',')) { // , is optional
skipToNL();
}
+ // Extra commas at this point should not get parsed as values.
+ // This might be unnecessary, but it is included here to be
+ // consistent with the original spec and unit testing.
+ if (readIf(',')) {
+ throw error("Extra comma detected. Unclear element");
+ }
// Make sure we back up all the way to a
// new line character or non-whitespace.
readIf('\r');
@@ -287,6 +293,12 @@ private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
if (readIf(',')) { // , is optional
skipToNL();
}
+ // Extra commas at this point should not get parsed as values.
+ // This might be unnecessary, but it is included here to be
+ // consistent with the original spec and unit testing.
+ if (readIf(',')) {
+ throw error("Extra comma detected. Unclear element");
+ }
// Make sure we back up all the way to a
// new line character or non-whitespace.
readIf('\r');
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index f6a51ce..44b913c 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -282,7 +282,7 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String
if (needsEscapeML(ch)) { noEscapeML=false; break; }
else if (!HjsonParser.isWhiteSpace(ch)) allWhite=false;
}
- if (noEscapeML && !allWhite && !value.contains("'''")) writeMLString(value, tw, level, separator);
+ if (noEscapeML && !allWhite && !value.contains("'''")) writeMLString(value, tw, level);
else tw.write("\""+JsonWriter.escapeString(value)+"\"");
}
else {
@@ -292,11 +292,11 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String
}
}
- void writeMLString(String value, Writer tw, int level, String separator) throws IOException {
+ void writeMLString(String value, Writer tw, int level) throws IOException {
String[] lines=value.replace("\r", "").split("\n", -1);
if (lines.length==1) {
- tw.write(separator+"'''");
+ tw.write("'''");
tw.write(lines[0]);
tw.write("'''");
}
From 27f5880e26335899bebf1d406d39bc886b4164a1 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Mon, 25 Feb 2019 21:39:27 -0600
Subject: [PATCH 18/63] better code reuse and clarity
---
assets/pass1_test.json | 2 +-
src/main/org/hjson/HjsonParser.java | 284 ++++++++++++++--------------
src/main/org/hjson/HjsonWriter.java | 1 -
3 files changed, 141 insertions(+), 146 deletions(-)
diff --git a/assets/pass1_test.json b/assets/pass1_test.json
index 41846d9..543bd9f 100644
--- a/assets/pass1_test.json
+++ b/assets/pass1_test.json
@@ -37,7 +37,7 @@
"# -- --> */": " ",
" s p a c e d " :[1,2 , 3
-,
+ ,
4 , 5 , 6 ,],"compact":[1,2,3,4,5,6],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 96276a1..11c9a2c 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -95,7 +95,7 @@ JsonValue tryParse() throws IOException {
default:
try {
// assume we have a root object without braces
- return checkTrailing(readObject(true));
+ return checkTrailing(readObject(false));
} catch (Exception exception) {
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
reset();
@@ -123,7 +123,7 @@ private JsonValue readValue() throws IOException {
case '\'':
case '"': return readString();
case '[': return readArray();
- case '{': return readObject(false);
+ case '{': return readObject(true);
default: return readTfnns();
}
}
@@ -143,7 +143,7 @@ private JsonValue readTfnns() throws IOException {
current=='}' || current==']' ||
current=='#' ||
current=='/' && (peek()=='/' || peek()=='*')
- ) {
+ ) {
switch (first) {
case 'f':
case 'n':
@@ -168,111 +168,21 @@ private JsonValue readTfnns() throws IOException {
}
}
- private JsonArray readArray() throws IOException {
- read();
- JsonArray array=new JsonArray();
- boolean compact=isContainerCompact();
- int sumLineLength=0;
- int lineLength=1;
- int numLines=0;
-
- while (true) {
- // Comment above / before value.
- String bol=readBetweenVals();
-
- // If readBetweenVals() brought us to the
- // end, it must be time to stop.
- if (readIf(']')) {
- // Because we reached the end, we learned
- // that this was an interior comment.
- array.setFullComment(CommentType.INTERIOR, bol);
- break;
- } else if (isEndOfText()) {
- throw error("End of input while parsing an array (did you forget a closing ']'?)");
- }
- // Allow commas to exist after new lines.
- if (array.size() > 0 && readIf(',')) {
- compact=false; // Can no longer be treated as compact.
- continue;
- }
- // Value comes next.
- JsonValue value=readValue();
- value.setFullComment(CommentType.BOL, bol);
-
- // Skip whitespace surrounding a comma.
- skipToNL();
- if (readIf(',')) { // , is optional
- skipToNL();
- }
- // Extra commas at this point should not get parsed as values.
- // This might be unnecessary, but it is included here to be
- // consistent with the original spec and unit testing.
- if (readIf(',')) {
- throw error("Extra comma detected. Unclear element");
- }
- // Make sure we back up all the way to a
- // new line character or non-whitespace.
- readIf('\r');
-
- // If we hit a new line, whatever character
- // comes next is either a value or BOL #.
- if (current!='\n') {
- // There was something else on this line.
- // See if it was an EOL #.
- String eol=readBetweenVals(true);
-
- if (!eol.isEmpty()) { // This is an EOL #.
- value.setFullComment(CommentType.EOL, eol);
- } else { // There's another value on this line.
- lineLength++;
- }
- } else {
- sumLineLength+=lineLength;
- lineLength=1;
- // Tally the lines.
- numLines++;
- }
- array.add(value);
- }
- if (sumLineLength>0) {
- int avgLineLength=sumLineLength/numLines;
- if (avgLineLength<1) avgLineLength=1;
- array.setLineLength(avgLineLength);
- } else if (compact) {
- array.setLineLength(array.size());
- }
- array.setCondensed(compact);
- return array;
- }
-
- private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
+ private JsonObject readObject(boolean expectCloser) throws IOException {
// Skip the opening brace.
- if (!objectWithoutBraces) read();
+ if (expectCloser) read();
JsonObject object=new JsonObject();
- object.setCondensed(isContainerCompact());
- int sumLineLength=0;
- int lineLength=1;
- int numLines=0;
+ ContainerData data=new ContainerData(isContainerCompact());
while (true) {
// Comment above / before name.
String bol=readBetweenVals();
- // If readBetweenVals() brought us to the
- // end, it must be time to stop.
- if (objectWithoutBraces) {
- if (isEndOfText()) {
- // Because we reached the end, we learned
- // that this was an interior comment.
- object.setFullComment(CommentType.INTERIOR, bol);
- break;
- }
- } else {
- if (isEndOfText()) throw error("End of input while parsing an object (did you forget a closing '}'?)");
- if (readIf('}')) {
- object.setFullComment(CommentType.INTERIOR, bol);
- break;
- }
+ if (checkEndOfContainer("object", '}', expectCloser)) {
+ // Because we reached the end, we learned
+ // that this was an interior comment.
+ object.setFullComment(CommentType.INTERIOR, bol);
+ break;
}
// Name comes next.
String name=readName();
@@ -288,49 +198,87 @@ private JsonObject readObject(boolean objectWithoutBraces) throws IOException {
// The value itself.
JsonValue value=readValue();
- // Skip whitespace surrounding a comma.
- skipToNL();
- if (readIf(',')) { // , is optional
- skipToNL();
- }
- // Extra commas at this point should not get parsed as values.
- // This might be unnecessary, but it is included here to be
- // consistent with the original spec and unit testing.
- if (readIf(',')) {
- throw error("Extra comma detected. Unclear element");
- }
- // Make sure we back up all the way to a
- // new line character or non-whitespace.
- readIf('\r');
-
- // If we hit a new line, whatever character
- // comes next is either a key or BOL #.
- if (current!='\n') {
- // There was something else on this line.
- // See if it was an EOL #.
- String eol=readBetweenVals(true);
-
- if (!eol.isEmpty()) { // This is an EOL #.
- value.setFullComment(CommentType.EOL, eol);
- } else { // There's another value on this line.
- lineLength++;
- }
- } else {
- sumLineLength+=lineLength;
- lineLength=1;
- // Tally the lines.
- numLines++;
- }
+ finishContainerElement(data, value);
// Set comments and add.
value.setFullComment(CommentType.BOL, bol);
object.add(name, value);
}
- if (sumLineLength>0) {
- int avgLineLength=sumLineLength/numLines;
- if (avgLineLength<1) avgLineLength=1;
- object.setLineLength(avgLineLength);
+ return data.into(object);
+ }
+
+ private JsonArray readArray() throws IOException {
+ read(); // Clear the opening bracket.
+ JsonArray array=new JsonArray();
+ ContainerData data=new ContainerData(isContainerCompact());
+
+ while (true) {
+ // Any comments above / before value.
+ String bol=readBetweenVals();
+
+ if (checkEndOfContainer("array", ']', true)) {
+ // Because we reached the end, we learned
+ // that this was an interior comment.
+ array.setFullComment(CommentType.INTERIOR, bol);
+ break;
+ }
+ // The value must be next.
+ JsonValue value=readValue();
+ value.setFullComment(CommentType.BOL, bol);
+
+ finishContainerElement(data, value);
+ // Successfully parsed a value.
+ array.add(value);
}
- return object;
+ return data.into(array);
+ }
+
+ private void finishContainerElement(ContainerData data, JsonValue value) throws IOException {
+ int delimiter, numCommas=0;
+ while ((delimiter=readNextDelimiter())==',') {
+ skipToNL();
+ numCommas++;
+ }
+ // We should now be at the eol.
+ if (delimiter=='\n') { // Reached eol.
+ data.nl(); // Update the data to reflect this.
+ // Check for a comma on the next line.
+ // Also skip empty lines.
+ while ((delimiter=readNextDelimiter())>0) {
+ if (delimiter==',') {
+ data.overrideCondensed(); // Can no longer be treated as condensed.
+ numCommas++;
+ }
+ }
+ } else { // Did not reach eol.
+ // There was something else on this line.
+ // See if it was an EOL #.
+ String eol=readBetweenVals(true);
+ if (!eol.isEmpty()) { // This is an EOL #.
+ value.setFullComment(CommentType.EOL, eol);
+ } else { // There's another value on this line.
+ data.incrLineLength();
+ }
+ }
+ if (numCommas>1) throw error("Extra comma detected. Unclear element");
+ }
+
+ private boolean checkEndOfContainer(String type, char closer, boolean expectCloser) throws IOException {
+ if (isEndOfText()) {
+ if (expectCloser) throw error("End of input while parsing an "+type+". Did you forget a closing'"+closer+"'?");
+ return true;
+ }
+ if (expectCloser) return readIf(closer);
+ return false;
+ }
+
+ private int readNextDelimiter() throws IOException {
+ skipToNL();
+ int delimiter=current;
+ if (delimiter=='\n' || delimiter==',') {
+ read();
+ return delimiter;
+ }
+ return -1;
}
private boolean isContainerCompact() throws IOException {
@@ -553,7 +501,7 @@ private String readBetweenVals(boolean toEOL) throws IOException {
startCapture();
while (!isEndOfText()) {
pauseCapture();
- int indent=skipWhiteSpace();
+ skipWhiteSpace();
startCapture();
if (current=='#' || current=='/' && peek()=='/') {
do {
@@ -563,6 +511,7 @@ private String readBetweenVals(boolean toEOL) throws IOException {
else read();
}
else if (current=='/' && peek()=='*') {
+ int commentOffset=index-lineOffset;
read();
do {
read();
@@ -570,7 +519,7 @@ else if (current=='/' && peek()=='*') {
read();
// Make sure that we still only skip whitespace.
// Spacing may be different on each line.
- skipIfWhiteSpace(indent-1);
+ skipIfWhiteSpace(commentOffset);
}
} while (current>=0 && !(current=='*' && peek()=='/'));
read(); read();
@@ -595,7 +544,7 @@ private int skipWhiteSpace() throws IOException {
}
private void skipToNL() throws IOException {
- while (current==' ' || current=='\t') read();
+ while (current==' ' || current=='\t' || current=='\r') read();
}
private int peek(int idx) throws IOException {
@@ -695,11 +644,58 @@ private boolean isWhiteSpace() {
private boolean isHexDigit() {
return current>='0' && current<='9'
- || current>='a' && current<='f'
- || current>='A' && current<='F';
+ || current>='a' && current<='f'
+ || current>='A' && current<='F';
}
private boolean isEndOfText() {
return current==-1;
}
+
+ private static class ContainerData {
+ private int lineLength=1;
+ private int sumLineLength=0;
+ private int numLines=0;
+ private boolean condensed;
+
+ private ContainerData(boolean condensed) {
+ this.condensed=condensed;
+ }
+
+ private void incrLineLength() {
+ lineLength++;
+ }
+
+ private void overrideCondensed() {
+ condensed=false;
+ }
+
+ private void nl() {
+ sumLineLength+=lineLength;
+ lineLength=1;
+ numLines++;
+ }
+
+ private int finalLineLength(int size) {
+ return sumLineLength>0 ? avgLineLength() : condensed ? size : 1;
+ }
+
+ private int avgLineLength() {
+ int avgLineLength=sumLineLength/numLines;
+ if (avgLineLength<=0) avgLineLength=1;
+ return avgLineLength;
+ }
+
+ private JsonArray into(JsonArray array) {
+ return array
+ .setLineLength(finalLineLength(array.size()))
+ .setCondensed(condensed);
+ }
+
+ private JsonObject into(JsonObject object) {
+ return object
+ .setLineLength(finalLineLength(object.size()))
+ .setCondensed(condensed);
+ }
+ }
}
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index 44b913c..871dc0e 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -198,7 +198,6 @@ void writeBOLComment(Writer tw, JsonValue value, int level) throws IOException {
void writeInteriorComment(Writer tw, JsonValue value, int level) throws IOException {
nl(tw, level+1);
writeComment(value.getInteriorComment(), tw, level+1);
- nl(tw, level);
}
void writeEOLComment(Writer tw, JsonValue value, int level) throws IOException {
From e1c724c40cf37a2aa3c4797db8d8e3e19f256b81 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 26 Feb 2019 19:10:41 -0600
Subject: [PATCH 19/63] add unit test for comments
---
assets/comments1_result.hjson | 74 +++++++++++++++++++
assets/comments1_result.json | 67 +++++++++++++++++
assets/comments1_test.hjson | 74 +++++++++++++++++++
...s_result.hjson => rmcomments_result.hjson} | 0
...nts_result.json => rmcomments_result.json} | 0
...ments_test.hjson => rmcomments_test.hjson} | 0
assets/testlist.txt | 3 +-
src/main/org/hjson/HjsonParser.java | 2 +-
src/test/org/hjson/test/Main.java | 3 +-
9 files changed, 220 insertions(+), 3 deletions(-)
create mode 100644 assets/comments1_result.hjson
create mode 100644 assets/comments1_result.json
create mode 100644 assets/comments1_test.hjson
rename assets/{comments_result.hjson => rmcomments_result.hjson} (100%)
rename assets/{comments_result.json => rmcomments_result.json} (100%)
rename assets/{comments_test.hjson => rmcomments_test.hjson} (100%)
diff --git a/assets/comments1_result.hjson b/assets/comments1_result.hjson
new file mode 100644
index 0000000..4d2efb1
--- /dev/null
+++ b/assets/comments1_result.hjson
@@ -0,0 +1,74 @@
+# Headers placed in this location will now be
+# correctly saved by hjson-java!
+{
+ # Comments can be placed above values.
+ numPenguins: 417 # And beside values.
+ // Multiple comment styles are supported.
+ anotherNum: 24
+ randString: "info" # Even with quotes and commas.
+ /*
+ There's a lot of info here.
+ Here's another line.
+ And another line.
+ */
+ complicatedObject:
+ {
+ apples: 12
+ bananas: 14
+ /*
+ a fancy
+ interior comment
+ for you
+ */
+ }
+ # Objects and arrays placed on a single line are
+ # considered "condensed" and will remain that way.
+ arrayOfNums: [ 1, 2, 3, 4, 5 ]
+ # Objects and arrays with multiple values per-
+ # line will continue to have multiple values
+ # per-line, based on the average line length.
+ multiLine:
+ [
+ 1, 2, 3
+ 4, 5, 6
+ ]
+ # These should get averaged to 2.
+ averageLines:
+ [
+ 1, 2
+ 3, 4
+ 5, 6
+ ]
+ # This works especially well for multi-dimensional
+ # arrays (i.e. matrices).
+ matrix:
+ [
+ [ 1, 2, 3 ]
+ [ 4, 5, 6 ]
+ [ 7, 8, 9 ]
+ /*
+ Another comment
+ goes here
+ */
+ ]
+ # Objects will do the same. Keys and values will
+ # be correctly quoted, when necessary.
+ multiLineObj:
+ {
+ "value1": 1, "value2": 2
+ "value3": "three", "value4": 4
+ }
+ # Unnecessary quotes will be removed.
+ unnecessaryQuotes:
+ {
+ numPenguins: 36
+ numPolarBears: twenty-four
+ }
+ # Just to verify that these still work.
+ multiLineString:
+ '''
+ test
+ and more test
+ and still more
+ '''
+}
\ No newline at end of file
diff --git a/assets/comments1_result.json b/assets/comments1_result.json
new file mode 100644
index 0000000..fd0054e
--- /dev/null
+++ b/assets/comments1_result.json
@@ -0,0 +1,67 @@
+{
+ "numPenguins": 417,
+ "anotherNum": 24,
+ "randString": "info",
+ "complicatedObject":
+ {
+ "apples": 12,
+ "bananas": 14
+ },
+ "arrayOfNums":
+ [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5
+ ],
+ "multiLine":
+ [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6
+ ],
+ "averageLines":
+ [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6
+ ],
+ "matrix":
+ [
+ [
+ 1,
+ 2,
+ 3
+ ],
+ [
+ 4,
+ 5,
+ 6
+ ],
+ [
+ 7,
+ 8,
+ 9
+ ]
+ ],
+ "multiLineObj":
+ {
+ "value1": 1,
+ "value2": 2,
+ "value3": "three",
+ "value4": 4
+ },
+ "unnecessaryQuotes":
+ {
+ "numPenguins": 36,
+ "numPolarBears": "twenty-four"
+ },
+ "multiLineString": "test\nand more test\nand still more"
+}
\ No newline at end of file
diff --git a/assets/comments1_test.hjson b/assets/comments1_test.hjson
new file mode 100644
index 0000000..9a032b4
--- /dev/null
+++ b/assets/comments1_test.hjson
@@ -0,0 +1,74 @@
+# Headers placed in this location will now be
+# correctly saved by hjson-java!
+{
+ # Comments can be placed above values.
+ numPenguins: 417 # And beside values.
+ // Multiple comment styles are supported.
+ anotherNum: 24
+ randString: "info", # Even with quotes and commas.
+ /*
+ There's a lot of info here.
+ Here's another line.
+ And another line.
+ */
+ complicatedObject:
+ {
+ apples: 12
+ bananas: 14
+ /*
+ a fancy
+ interior comment
+ for you
+ */
+ }
+ # Objects and arrays placed on a single line are
+ # considered "condensed" and will remain that way.
+ arrayOfNums: [ 1, 2, 3, 4, 5 ]
+ # Objects and arrays with multiple values per-
+ # line will continue to have multiple values
+ # per-line, based on the average line length.
+ multiLine:
+ [
+ 1, 2, 3
+ 4, 5, 6
+ ]
+ # These should get averaged to 2.
+ averageLines:
+ [
+ 1
+ 2, 3
+ 4, 5, 6
+ ]
+ # This works especially well for multi-dimensional
+ # arrays (i.e. matrices).
+ matrix:
+ [
+ [ 1, 2, 3 ]
+ [ 4, 5, 6 ]
+ [ 7, 8, 9 ]
+ /*
+ Another comment
+ goes here
+ */
+ ]
+ # Objects will do the same. Keys and values will
+ # be correctly quoted, when necessary.
+ multiLineObj:
+ {
+ "value1": 1, "value2": 2
+ "value3": "three", "value4": 4
+ }
+ # Unnecessary quotes will be removed.
+ unnecessaryQuotes:
+ {
+ "numPenguins": 36,
+ "numPolarBears": "twenty-four"
+ }
+ # Just to verify that these still work.
+ multiLineString:
+ '''
+ test
+ and more test
+ and still more
+ '''
+}
\ No newline at end of file
diff --git a/assets/comments_result.hjson b/assets/rmcomments_result.hjson
similarity index 100%
rename from assets/comments_result.hjson
rename to assets/rmcomments_result.hjson
diff --git a/assets/comments_result.json b/assets/rmcomments_result.json
similarity index 100%
rename from assets/comments_result.json
rename to assets/rmcomments_result.json
diff --git a/assets/comments_test.hjson b/assets/rmcomments_test.hjson
similarity index 100%
rename from assets/comments_test.hjson
rename to assets/rmcomments_test.hjson
diff --git a/assets/testlist.txt b/assets/testlist.txt
index 49adf34..3da776e 100644
--- a/assets/testlist.txt
+++ b/assets/testlist.txt
@@ -1,5 +1,5 @@
charset_test.hjson
-comments_test.hjson
+comments1_test.hjson
empty_test.hjson
failCharset1_test.hjson
failJSON02_test.json
@@ -72,6 +72,7 @@ pass2_test.json
pass3_test.json
pass4_test.json
passSingle_test.hjson
+rmcomments_test.hjson
stringify1_test.hjson
strings2_test.hjson
strings_test.hjson
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 11c9a2c..6bf3a9e 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -511,7 +511,7 @@ private String readBetweenVals(boolean toEOL) throws IOException {
else read();
}
else if (current=='/' && peek()=='*') {
- int commentOffset=index-lineOffset;
+ int commentOffset=index-lineOffset-1;
read();
do {
read();
diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java
index c06e8d2..e1185a1 100644
--- a/src/test/org/hjson/test/Main.java
+++ b/src/test/org/hjson/test/Main.java
@@ -31,6 +31,7 @@ private static boolean test(String name, String file, boolean inputCr, boolean o
int extIdx=file.lastIndexOf('.');
boolean isJson=extIdx>=0 && file.substring(extIdx).equals(".json");
boolean shouldFail=name.startsWith("fail");
+ boolean useComments=name.startsWith("comments");
JsonValue.setEol(outputCr?"\r\n":"\n");
String text=load(file, inputCr);
@@ -41,7 +42,7 @@ private static boolean test(String name, String file, boolean inputCr, boolean o
JsonValue data=JsonValue.readHjson(text, opt);
String data1=data.toString(Stringify.FORMATTED);
- String hjson1=data.toString(Stringify.HJSON);
+ String hjson1=data.toString(useComments ? Stringify.HJSON_COMMENTS : Stringify.HJSON);
if (!shouldFail) {
JsonValue result=JsonValue.readJSON(load(name+"_result.json", inputCr));
String data2=result.toString(Stringify.FORMATTED);
From acadc241fd5226496f305411e358e181aedaa66d Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Tue, 18 Jun 2019 18:29:56 -0500
Subject: [PATCH 20/63] Add JsonObject#has
---
src/main/org/hjson/JsonObject.java | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java
index 08b29eb..14c072c 100644
--- a/src/main/org/hjson/JsonObject.java
+++ b/src/main/org/hjson/JsonObject.java
@@ -737,6 +737,16 @@ public JsonObject remove(String name) {
return this;
}
+ /**
+ * Returns whether the input key is contained within this object.
+ *
+ * @param name The name of the key to search for.
+ * @ return Whether the key exists.
+ */
+ public boolean has(String name) {
+ return indexOf(name)!=-1;
+ }
+
/**
* Returns the value of the member with the specified name in this object. If this object contains
* multiple members with the given name, this method will return the last one.
From cc6e9e33c5f4c337c19ccdb0813af438b0efec48 Mon Sep 17 00:00:00 2001
From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com>
Date: Wed, 28 Aug 2019 19:19:06 -0500
Subject: [PATCH 21/63] Unsafe functions
---
src/main/org/hjson/HjsonParser.java | 18 +++++++++---------
src/main/org/hjson/HjsonWriter.java | 3 ++-
src/main/org/hjson/JsonArray.java | 13 +++++++++++++
src/main/org/hjson/JsonValue.java | 21 +++++++++++++++++++++
4 files changed, 45 insertions(+), 10 deletions(-)
diff --git a/src/main/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java
index 6bf3a9e..d76b21f 100644
--- a/src/main/org/hjson/HjsonParser.java
+++ b/src/main/org/hjson/HjsonParser.java
@@ -140,9 +140,9 @@ private JsonValue readTfnns() throws IOException {
read();
boolean isEol=current<0 || current=='\r' || current=='\n';
if (isEol || current==',' ||
- current=='}' || current==']' ||
- current=='#' ||
- current=='/' && (peek()=='/' || peek()=='*')
+ current=='}' || current==']' ||
+ current=='#' ||
+ current=='/' && (peek()=='/' || peek()=='*')
) {
switch (first) {
case 'f':
@@ -644,8 +644,8 @@ private boolean isWhiteSpace() {
private boolean isHexDigit() {
return current>='0' && current<='9'
- || current>='a' && current<='f'
- || current>='A' && current<='F';
+ || current>='a' && current<='f'
+ || current>='A' && current<='F';
}
private boolean isEndOfText() {
@@ -688,14 +688,14 @@ private int avgLineLength() {
private JsonArray into(JsonArray array) {
return array
- .setLineLength(finalLineLength(array.size()))
- .setCondensed(condensed);
+ .setLineLength(finalLineLength(array.size()))
+ .setCondensed(condensed);
}
private JsonObject into(JsonObject object) {
return object
- .setLineLength(finalLineLength(object.size()))
- .setCondensed(condensed);
+ .setLineLength(finalLineLength(object.size()))
+ .setCondensed(condensed);
}
}
}
diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java
index 871dc0e..d64891c 100644
--- a/src/main/org/hjson/HjsonWriter.java
+++ b/src/main/org/hjson/HjsonWriter.java
@@ -265,7 +265,8 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String
left=='/' && (left1=='*' || left1=='/') ||
JsonValue.isPunctuatorChar(left) ||
HjsonParser.tryParseNumber(value, true)!=null ||
- startsWithKeyword(value)) {
+ startsWithKeyword(value))
+ {
// If the String contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we first check if the String can be expressed in multiline
diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java
index ad49748..8d6a993 100644
--- a/src/main/org/hjson/JsonArray.java
+++ b/src/main/org/hjson/JsonArray.java
@@ -115,6 +115,19 @@ public static JsonArray unmodifiableArray(JsonArray array) {
return new JsonArray(array, true);
}
+ /**
+ * Unsafe. Returns a raw list of the objects contained within this array. For compatibiliity with
+ * other config wrappers.
+ * @return the array as a list of raw objects.
+ */
+ public List