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 asRawList() { + final List array=new ArrayList<>(); + for (JsonValue value : this) { + array.add(value.asRaw()); + } + return array; + } + /** * Appends the JSON representation of the specified int value to the end of this * array. diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 9cb815d..3433f4b 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -27,6 +27,7 @@ import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; +import java.util.List; /** * Represents a JSON value. This can be a JSON object, an array, @@ -584,6 +585,26 @@ public boolean asBoolean() { public Object asDsf() { throw new UnsupportedOperationException("Not a DSF"); } + + /** + * Unsafe. Returns the raw form of this JSON value. For compatibility with other config wrappers. + * @param the type of object to be returned. + * @return the raw object. + * @throws ClassCastException when the type returned does not match the original value. + */ + @SuppressWarnings("unchecked") + public T asRaw() { + switch (getType()) { + case STRING : return (T) asString(); + case NUMBER : return (T) Double.valueOf(asDouble()); + case OBJECT : return (T) asObject(); + case ARRAY : return (T) asArray().asRawList(); + case BOOLEAN : return (T) Boolean.valueOf(asBoolean()); + case DSF : return (T) asDsf(); + default : return null; + } + } + /** * Writes the JSON representation of this value to the given writer in its minimal form, without * any additional whitespace. From 23ae01e37ea4896d4bc5e70c1decb46a61ad4d97 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Wed, 28 Aug 2019 20:04:41 -0500 Subject: [PATCH 22/63] More unsafe functions --- src/main/org/hjson/JsonObject.java | 10 --------- src/main/org/hjson/JsonValue.java | 33 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 14c072c..08b29eb 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -737,16 +737,6 @@ 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. diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 3433f4b..bff5634 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -27,7 +27,10 @@ import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; +import java.nio.file.Path; import java.util.List; +import java.util.Map; +import java.util.Set; /** * Represents a JSON value. This can be a JSON object, an array, @@ -257,6 +260,36 @@ public static JsonValue valueOfDsf(Object value) { return new JsonDsf(value); } + /** + * Returns a JsonValue from an Object of unknown type. + * @return a new JsonValue. + */ + @SuppressWarnings("unchecked") + public static JsonValue valueOf(Object value) { + if (value instanceof Number) { + return new JsonNumber((Double) value); + } else if (value instanceof String) { + return new JsonString((String) value); + } else if (value instanceof Boolean) { + return (Boolean) value ? JsonLiteral.jsonTrue() : JsonLiteral.jsonFalse(); + } else if (value instanceof List) { + JsonArray array=new JsonArray(); + for (Object o : (List) value) { + array.add(valueOf(o)); + } + return array; + } else if (value instanceof Map) { + Set entries=((Map)value).entrySet(); + JsonObject object=new JsonObject(); + for (Map.Entry entry : entries) { + object.set(entry.getKey().toString(), valueOf(entry.getValue())); + } + return object; + } else { + return null; + } + } + /** * Gets the type of this JSON value. * From f5aa8d7e0744e0ae3295872107865dbfa59d7a44 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Wed, 28 Aug 2019 20:08:29 -0500 Subject: [PATCH 23/63] Better yet --- src/main/org/hjson/JsonValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index bff5634..5131762 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -286,7 +286,7 @@ public static JsonValue valueOf(Object value) { } return object; } else { - return null; + throw new UnsupportedOperationException("Unable to determine type."); } } From fb208725b9a60413d3fcbeebc7f6f3e9d27ed0d4 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Wed, 28 Aug 2019 21:13:21 -0500 Subject: [PATCH 24/63] Fix missing 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..0001761 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -128,6 +128,16 @@ public static JsonObject unmodifiableObject(JsonObject object) { return new JsonObject(object, true); } + /** + * 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; + } + /** * Appends a new member to the end of this object, with the specified name and the JSON * representation of the specified int value. From 62ea94b5827a8f6510f08ba595959b3e7ee2c693 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Thu, 29 Aug 2019 20:30:31 -0500 Subject: [PATCH 25/63] Fix raw cast error --- src/main/org/hjson/JsonValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 5131762..7e7958c 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -267,7 +267,7 @@ public static JsonValue valueOfDsf(Object value) { @SuppressWarnings("unchecked") public static JsonValue valueOf(Object value) { if (value instanceof Number) { - return new JsonNumber((Double) value); + return new JsonNumber((double) value); } else if (value instanceof String) { return new JsonString((String) value); } else if (value instanceof Boolean) { From f379e8db6500ad45ff6d266eb70af605b51d9187 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Thu, 29 Aug 2019 20:39:51 -0500 Subject: [PATCH 26/63] Revert "Fix raw cast error" This reverts commit 62ea94b5827a8f6510f08ba595959b3e7ee2c693. --- src/main/org/hjson/JsonValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 7e7958c..5131762 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -267,7 +267,7 @@ public static JsonValue valueOfDsf(Object value) { @SuppressWarnings("unchecked") public static JsonValue valueOf(Object value) { if (value instanceof Number) { - return new JsonNumber((double) value); + return new JsonNumber((Double) value); } else if (value instanceof String) { return new JsonString((String) value); } else if (value instanceof Boolean) { From e09198661d272794c1bdad399096fd6d63a6851b Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Thu, 29 Aug 2019 20:41:16 -0500 Subject: [PATCH 27/63] Fix raw cast error --- src/main/org/hjson/JsonValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 5131762..ad972dc 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -267,7 +267,7 @@ public static JsonValue valueOfDsf(Object value) { @SuppressWarnings("unchecked") public static JsonValue valueOf(Object value) { if (value instanceof Number) { - return new JsonNumber((Double) value); + return new JsonNumber(((Number) value).doubleValue()); } else if (value instanceof String) { return new JsonString((String) value); } else if (value instanceof Boolean) { From ae16c844c87f3fba58aebcc89673e39c7ebdb641 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Sat, 20 Jun 2020 13:11:01 -0500 Subject: [PATCH 28/63] Temporary Project Structure Planning full rewrite --- build.gradle | 10 +------ {assets => src/assets}/charset_result.hjson | 0 {assets => src/assets}/charset_result.json | 0 {assets => src/assets}/charset_test.hjson | 0 {assets => src/assets}/comments1_result.hjson | 0 {assets => src/assets}/comments1_result.json | 0 {assets => src/assets}/comments1_test.hjson | 0 {assets => src/assets}/empty_result.hjson | 0 {assets => src/assets}/empty_result.json | 0 {assets => src/assets}/empty_test.hjson | 0 .../assets}/failCharset1_test.hjson | 0 {assets => src/assets}/failJSON02_test.json | 0 {assets => src/assets}/failJSON05_test.json | 0 {assets => src/assets}/failJSON06_test.json | 0 {assets => src/assets}/failJSON07_test.json | 0 {assets => src/assets}/failJSON08_test.json | 0 {assets => src/assets}/failJSON10_test.json | 0 {assets => src/assets}/failJSON11_test.json | 0 {assets => src/assets}/failJSON12_test.json | 0 {assets => src/assets}/failJSON13_test.json | 0 {assets => src/assets}/failJSON14_test.json | 0 {assets => src/assets}/failJSON15_test.json | 0 {assets => src/assets}/failJSON16_test.json | 0 {assets => src/assets}/failJSON17_test.json | 0 {assets => src/assets}/failJSON19_test.json | 0 {assets => src/assets}/failJSON20_test.json | 0 {assets => src/assets}/failJSON21_test.json | 0 {assets => src/assets}/failJSON22_test.json | 0 {assets => src/assets}/failJSON23_test.json | 0 {assets => src/assets}/failJSON26_test.json | 0 {assets => src/assets}/failJSON28_test.json | 0 {assets => src/assets}/failJSON29_test.json | 0 {assets => src/assets}/failJSON30_test.json | 0 {assets => src/assets}/failJSON31_test.json | 0 {assets => src/assets}/failJSON32_test.json | 0 {assets => src/assets}/failJSON33_test.json | 0 {assets => src/assets}/failJSON34_test.json | 0 {assets => src/assets}/failKey1_test.hjson | 0 {assets => src/assets}/failKey2_test.hjson | 0 {assets => src/assets}/failKey3_test.hjson | 0 {assets => src/assets}/failKey4_test.hjson | 0 {assets => src/assets}/failKey5_test.hjson | 0 {assets => src/assets}/failMLStr1_test.hjson | 0 {assets => src/assets}/failObj1_test.hjson | 0 {assets => src/assets}/failObj2_test.hjson | 0 {assets => src/assets}/failObj3_test.hjson | 0 {assets => src/assets}/failStr1a_test.hjson | 0 {assets => src/assets}/failStr1b_test.hjson | 0 {assets => src/assets}/failStr1c_test.hjson | 0 {assets => src/assets}/failStr1d_test.hjson | 0 {assets => src/assets}/failStr2a_test.hjson | 0 {assets => src/assets}/failStr2b_test.hjson | 0 {assets => src/assets}/failStr2c_test.hjson | 0 {assets => src/assets}/failStr2d_test.hjson | 0 {assets => src/assets}/failStr3a_test.hjson | 0 {assets => src/assets}/failStr3b_test.hjson | 0 {assets => src/assets}/failStr3c_test.hjson | 0 {assets => src/assets}/failStr3d_test.hjson | 0 {assets => src/assets}/failStr4a_test.hjson | 0 {assets => src/assets}/failStr4b_test.hjson | 0 {assets => src/assets}/failStr4c_test.hjson | 0 {assets => src/assets}/failStr4d_test.hjson | 0 {assets => src/assets}/failStr5a_test.hjson | 0 {assets => src/assets}/failStr5b_test.hjson | 0 {assets => src/assets}/failStr5c_test.hjson | 0 {assets => src/assets}/failStr5d_test.hjson | 0 {assets => src/assets}/failStr6a_test.hjson | 0 {assets => src/assets}/failStr6b_test.hjson | 0 {assets => src/assets}/failStr6c_test.hjson | 0 {assets => src/assets}/failStr6d_test.hjson | 0 {assets => src/assets}/failStr7a_test.hjson | 0 {assets => src/assets}/failStr8a_test.hjson | 0 {assets => src/assets}/kan_result.hjson | 0 {assets => src/assets}/kan_result.json | 0 {assets => src/assets}/kan_test.hjson | 0 {assets => src/assets}/keys_result.hjson | 0 {assets => src/assets}/keys_result.json | 0 {assets => src/assets}/keys_test.hjson | 0 {assets => src/assets}/mltabs_result.hjson | 0 {assets => src/assets}/mltabs_result.json | 0 {assets => src/assets}/mltabs_test.json | 0 {assets => src/assets}/oa_result.hjson | 0 {assets => src/assets}/oa_result.json | 0 {assets => src/assets}/oa_test.hjson | 0 {assets => src/assets}/pass1_result.hjson | 0 {assets => src/assets}/pass1_result.json | 0 {assets => src/assets}/pass1_test.json | 0 {assets => src/assets}/pass2_result.hjson | 0 {assets => src/assets}/pass2_result.json | 0 {assets => src/assets}/pass2_test.json | 0 {assets => src/assets}/pass3_result.hjson | 0 {assets => src/assets}/pass3_result.json | 0 {assets => src/assets}/pass3_test.json | 0 {assets => src/assets}/pass4_result.hjson | 0 {assets => src/assets}/pass4_result.json | 0 {assets => src/assets}/pass4_test.json | 0 .../assets}/passSingle_result.hjson | 0 {assets => src/assets}/passSingle_result.json | 0 {assets => src/assets}/passSingle_test.hjson | 0 .../assets}/rmcomments_result.hjson | 0 {assets => src/assets}/rmcomments_result.json | 0 {assets => src/assets}/rmcomments_test.hjson | 0 .../assets}/stringify1_result.hjson | 0 {assets => src/assets}/stringify1_result.json | 0 {assets => src/assets}/stringify1_test.hjson | 0 {assets => src/assets}/strings2_result.hjson | 0 {assets => src/assets}/strings2_result.json | 0 {assets => src/assets}/strings2_test.hjson | 0 {assets => src/assets}/strings_result.hjson | 0 {assets => src/assets}/strings_result.json | 0 {assets => src/assets}/strings_test.hjson | 0 {assets => src/assets}/testlist.txt | 0 {assets => src/assets}/trail_result.hjson | 0 {assets => src/assets}/trail_result.json | 0 {assets => src/assets}/trail_test.hjson | 0 src/{main => }/org/hjson/CommentStyle.java | 0 src/{main => }/org/hjson/CommentType.java | 0 src/{main => }/org/hjson/HjsonDsf.java | 0 src/{main => }/org/hjson/HjsonOptions.java | 10 +++---- src/{main => }/org/hjson/HjsonParser.java | 0 src/{main => }/org/hjson/HjsonWriter.java | 26 +++++++++++++------ .../org/hjson/IHjsonDsfProvider.java | 0 src/{main => }/org/hjson/JsonArray.java | 0 src/{main => }/org/hjson/JsonDsf.java | 0 src/{main => }/org/hjson/JsonLiteral.java | 0 src/{main => }/org/hjson/JsonNumber.java | 0 src/{main => }/org/hjson/JsonObject.java | 0 src/{main => }/org/hjson/JsonParser.java | 0 src/{main => }/org/hjson/JsonString.java | 0 src/{main => }/org/hjson/JsonType.java | 0 src/{main => }/org/hjson/JsonValue.java | 0 src/{main => }/org/hjson/JsonWriter.java | 0 src/{main => }/org/hjson/ParseException.java | 0 src/{main => }/org/hjson/Stringify.java | 0 src/{main => }/org/hjson/WritingBuffer.java | 0 src/test/org/hjson/test/Main.java | 10 ++++--- 136 files changed, 29 insertions(+), 27 deletions(-) rename {assets => src/assets}/charset_result.hjson (100%) rename {assets => src/assets}/charset_result.json (100%) rename {assets => src/assets}/charset_test.hjson (100%) rename {assets => src/assets}/comments1_result.hjson (100%) rename {assets => src/assets}/comments1_result.json (100%) rename {assets => src/assets}/comments1_test.hjson (100%) rename {assets => src/assets}/empty_result.hjson (100%) rename {assets => src/assets}/empty_result.json (100%) rename {assets => src/assets}/empty_test.hjson (100%) rename {assets => src/assets}/failCharset1_test.hjson (100%) rename {assets => src/assets}/failJSON02_test.json (100%) rename {assets => src/assets}/failJSON05_test.json (100%) rename {assets => src/assets}/failJSON06_test.json (100%) rename {assets => src/assets}/failJSON07_test.json (100%) rename {assets => src/assets}/failJSON08_test.json (100%) rename {assets => src/assets}/failJSON10_test.json (100%) rename {assets => src/assets}/failJSON11_test.json (100%) rename {assets => src/assets}/failJSON12_test.json (100%) rename {assets => src/assets}/failJSON13_test.json (100%) rename {assets => src/assets}/failJSON14_test.json (100%) rename {assets => src/assets}/failJSON15_test.json (100%) rename {assets => src/assets}/failJSON16_test.json (100%) rename {assets => src/assets}/failJSON17_test.json (100%) rename {assets => src/assets}/failJSON19_test.json (100%) rename {assets => src/assets}/failJSON20_test.json (100%) rename {assets => src/assets}/failJSON21_test.json (100%) rename {assets => src/assets}/failJSON22_test.json (100%) rename {assets => src/assets}/failJSON23_test.json (100%) rename {assets => src/assets}/failJSON26_test.json (100%) rename {assets => src/assets}/failJSON28_test.json (100%) rename {assets => src/assets}/failJSON29_test.json (100%) rename {assets => src/assets}/failJSON30_test.json (100%) rename {assets => src/assets}/failJSON31_test.json (100%) rename {assets => src/assets}/failJSON32_test.json (100%) rename {assets => src/assets}/failJSON33_test.json (100%) rename {assets => src/assets}/failJSON34_test.json (100%) rename {assets => src/assets}/failKey1_test.hjson (100%) rename {assets => src/assets}/failKey2_test.hjson (100%) rename {assets => src/assets}/failKey3_test.hjson (100%) rename {assets => src/assets}/failKey4_test.hjson (100%) rename {assets => src/assets}/failKey5_test.hjson (100%) rename {assets => src/assets}/failMLStr1_test.hjson (100%) rename {assets => src/assets}/failObj1_test.hjson (100%) rename {assets => src/assets}/failObj2_test.hjson (100%) rename {assets => src/assets}/failObj3_test.hjson (100%) rename {assets => src/assets}/failStr1a_test.hjson (100%) rename {assets => src/assets}/failStr1b_test.hjson (100%) rename {assets => src/assets}/failStr1c_test.hjson (100%) rename {assets => src/assets}/failStr1d_test.hjson (100%) rename {assets => src/assets}/failStr2a_test.hjson (100%) rename {assets => src/assets}/failStr2b_test.hjson (100%) rename {assets => src/assets}/failStr2c_test.hjson (100%) rename {assets => src/assets}/failStr2d_test.hjson (100%) rename {assets => src/assets}/failStr3a_test.hjson (100%) rename {assets => src/assets}/failStr3b_test.hjson (100%) rename {assets => src/assets}/failStr3c_test.hjson (100%) rename {assets => src/assets}/failStr3d_test.hjson (100%) rename {assets => src/assets}/failStr4a_test.hjson (100%) rename {assets => src/assets}/failStr4b_test.hjson (100%) rename {assets => src/assets}/failStr4c_test.hjson (100%) rename {assets => src/assets}/failStr4d_test.hjson (100%) rename {assets => src/assets}/failStr5a_test.hjson (100%) rename {assets => src/assets}/failStr5b_test.hjson (100%) rename {assets => src/assets}/failStr5c_test.hjson (100%) rename {assets => src/assets}/failStr5d_test.hjson (100%) rename {assets => src/assets}/failStr6a_test.hjson (100%) rename {assets => src/assets}/failStr6b_test.hjson (100%) rename {assets => src/assets}/failStr6c_test.hjson (100%) rename {assets => src/assets}/failStr6d_test.hjson (100%) rename {assets => src/assets}/failStr7a_test.hjson (100%) rename {assets => src/assets}/failStr8a_test.hjson (100%) rename {assets => src/assets}/kan_result.hjson (100%) rename {assets => src/assets}/kan_result.json (100%) rename {assets => src/assets}/kan_test.hjson (100%) rename {assets => src/assets}/keys_result.hjson (100%) rename {assets => src/assets}/keys_result.json (100%) rename {assets => src/assets}/keys_test.hjson (100%) rename {assets => src/assets}/mltabs_result.hjson (100%) rename {assets => src/assets}/mltabs_result.json (100%) rename {assets => src/assets}/mltabs_test.json (100%) rename {assets => src/assets}/oa_result.hjson (100%) rename {assets => src/assets}/oa_result.json (100%) rename {assets => src/assets}/oa_test.hjson (100%) rename {assets => src/assets}/pass1_result.hjson (100%) rename {assets => src/assets}/pass1_result.json (100%) rename {assets => src/assets}/pass1_test.json (100%) rename {assets => src/assets}/pass2_result.hjson (100%) rename {assets => src/assets}/pass2_result.json (100%) rename {assets => src/assets}/pass2_test.json (100%) rename {assets => src/assets}/pass3_result.hjson (100%) rename {assets => src/assets}/pass3_result.json (100%) rename {assets => src/assets}/pass3_test.json (100%) rename {assets => src/assets}/pass4_result.hjson (100%) rename {assets => src/assets}/pass4_result.json (100%) rename {assets => src/assets}/pass4_test.json (100%) rename {assets => src/assets}/passSingle_result.hjson (100%) rename {assets => src/assets}/passSingle_result.json (100%) rename {assets => src/assets}/passSingle_test.hjson (100%) rename {assets => src/assets}/rmcomments_result.hjson (100%) rename {assets => src/assets}/rmcomments_result.json (100%) rename {assets => src/assets}/rmcomments_test.hjson (100%) rename {assets => src/assets}/stringify1_result.hjson (100%) rename {assets => src/assets}/stringify1_result.json (100%) rename {assets => src/assets}/stringify1_test.hjson (100%) rename {assets => src/assets}/strings2_result.hjson (100%) rename {assets => src/assets}/strings2_result.json (100%) rename {assets => src/assets}/strings2_test.hjson (100%) rename {assets => src/assets}/strings_result.hjson (100%) rename {assets => src/assets}/strings_result.json (100%) rename {assets => src/assets}/strings_test.hjson (100%) rename {assets => src/assets}/testlist.txt (100%) rename {assets => src/assets}/trail_result.hjson (100%) rename {assets => src/assets}/trail_result.json (100%) rename {assets => src/assets}/trail_test.hjson (100%) rename src/{main => }/org/hjson/CommentStyle.java (100%) rename src/{main => }/org/hjson/CommentType.java (100%) rename src/{main => }/org/hjson/HjsonDsf.java (100%) rename src/{main => }/org/hjson/HjsonOptions.java (96%) rename src/{main => }/org/hjson/HjsonParser.java (100%) rename src/{main => }/org/hjson/HjsonWriter.java (93%) rename src/{main => }/org/hjson/IHjsonDsfProvider.java (100%) rename src/{main => }/org/hjson/JsonArray.java (100%) rename src/{main => }/org/hjson/JsonDsf.java (100%) rename src/{main => }/org/hjson/JsonLiteral.java (100%) rename src/{main => }/org/hjson/JsonNumber.java (100%) rename src/{main => }/org/hjson/JsonObject.java (100%) rename src/{main => }/org/hjson/JsonParser.java (100%) rename src/{main => }/org/hjson/JsonString.java (100%) rename src/{main => }/org/hjson/JsonType.java (100%) rename src/{main => }/org/hjson/JsonValue.java (100%) rename src/{main => }/org/hjson/JsonWriter.java (100%) rename src/{main => }/org/hjson/ParseException.java (100%) rename src/{main => }/org/hjson/Stringify.java (100%) rename src/{main => }/org/hjson/WritingBuffer.java (100%) diff --git a/build.gradle b/build.gradle index 0de0cc3..7813d86 100644 --- a/build.gradle +++ b/build.gradle @@ -13,14 +13,6 @@ sourceSets { srcDir 'src/main' } } - test { - java { - srcDir 'src/test' - } - resources { - srcDir 'assets' - } - } } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -48,7 +40,7 @@ artifacts { } task(testSuite, dependsOn: ['classes','testClasses'], type: JavaExec) { - main = 'org.hjson.test.Main' + main = 'test.org.hjson.test.Main' classpath = files(sourceSets.main.runtimeClasspath, sourceSets.test.runtimeClasspath) } diff --git a/assets/charset_result.hjson b/src/assets/charset_result.hjson similarity index 100% rename from assets/charset_result.hjson rename to src/assets/charset_result.hjson diff --git a/assets/charset_result.json b/src/assets/charset_result.json similarity index 100% rename from assets/charset_result.json rename to src/assets/charset_result.json diff --git a/assets/charset_test.hjson b/src/assets/charset_test.hjson similarity index 100% rename from assets/charset_test.hjson rename to src/assets/charset_test.hjson diff --git a/assets/comments1_result.hjson b/src/assets/comments1_result.hjson similarity index 100% rename from assets/comments1_result.hjson rename to src/assets/comments1_result.hjson diff --git a/assets/comments1_result.json b/src/assets/comments1_result.json similarity index 100% rename from assets/comments1_result.json rename to src/assets/comments1_result.json diff --git a/assets/comments1_test.hjson b/src/assets/comments1_test.hjson similarity index 100% rename from assets/comments1_test.hjson rename to src/assets/comments1_test.hjson diff --git a/assets/empty_result.hjson b/src/assets/empty_result.hjson similarity index 100% rename from assets/empty_result.hjson rename to src/assets/empty_result.hjson diff --git a/assets/empty_result.json b/src/assets/empty_result.json similarity index 100% rename from assets/empty_result.json rename to src/assets/empty_result.json diff --git a/assets/empty_test.hjson b/src/assets/empty_test.hjson similarity index 100% rename from assets/empty_test.hjson rename to src/assets/empty_test.hjson diff --git a/assets/failCharset1_test.hjson b/src/assets/failCharset1_test.hjson similarity index 100% rename from assets/failCharset1_test.hjson rename to src/assets/failCharset1_test.hjson diff --git a/assets/failJSON02_test.json b/src/assets/failJSON02_test.json similarity index 100% rename from assets/failJSON02_test.json rename to src/assets/failJSON02_test.json diff --git a/assets/failJSON05_test.json b/src/assets/failJSON05_test.json similarity index 100% rename from assets/failJSON05_test.json rename to src/assets/failJSON05_test.json diff --git a/assets/failJSON06_test.json b/src/assets/failJSON06_test.json similarity index 100% rename from assets/failJSON06_test.json rename to src/assets/failJSON06_test.json diff --git a/assets/failJSON07_test.json b/src/assets/failJSON07_test.json similarity index 100% rename from assets/failJSON07_test.json rename to src/assets/failJSON07_test.json diff --git a/assets/failJSON08_test.json b/src/assets/failJSON08_test.json similarity index 100% rename from assets/failJSON08_test.json rename to src/assets/failJSON08_test.json diff --git a/assets/failJSON10_test.json b/src/assets/failJSON10_test.json similarity index 100% rename from assets/failJSON10_test.json rename to src/assets/failJSON10_test.json diff --git a/assets/failJSON11_test.json b/src/assets/failJSON11_test.json similarity index 100% rename from assets/failJSON11_test.json rename to src/assets/failJSON11_test.json diff --git a/assets/failJSON12_test.json b/src/assets/failJSON12_test.json similarity index 100% rename from assets/failJSON12_test.json rename to src/assets/failJSON12_test.json diff --git a/assets/failJSON13_test.json b/src/assets/failJSON13_test.json similarity index 100% rename from assets/failJSON13_test.json rename to src/assets/failJSON13_test.json diff --git a/assets/failJSON14_test.json b/src/assets/failJSON14_test.json similarity index 100% rename from assets/failJSON14_test.json rename to src/assets/failJSON14_test.json diff --git a/assets/failJSON15_test.json b/src/assets/failJSON15_test.json similarity index 100% rename from assets/failJSON15_test.json rename to src/assets/failJSON15_test.json diff --git a/assets/failJSON16_test.json b/src/assets/failJSON16_test.json similarity index 100% rename from assets/failJSON16_test.json rename to src/assets/failJSON16_test.json diff --git a/assets/failJSON17_test.json b/src/assets/failJSON17_test.json similarity index 100% rename from assets/failJSON17_test.json rename to src/assets/failJSON17_test.json diff --git a/assets/failJSON19_test.json b/src/assets/failJSON19_test.json similarity index 100% rename from assets/failJSON19_test.json rename to src/assets/failJSON19_test.json diff --git a/assets/failJSON20_test.json b/src/assets/failJSON20_test.json similarity index 100% rename from assets/failJSON20_test.json rename to src/assets/failJSON20_test.json diff --git a/assets/failJSON21_test.json b/src/assets/failJSON21_test.json similarity index 100% rename from assets/failJSON21_test.json rename to src/assets/failJSON21_test.json diff --git a/assets/failJSON22_test.json b/src/assets/failJSON22_test.json similarity index 100% rename from assets/failJSON22_test.json rename to src/assets/failJSON22_test.json diff --git a/assets/failJSON23_test.json b/src/assets/failJSON23_test.json similarity index 100% rename from assets/failJSON23_test.json rename to src/assets/failJSON23_test.json diff --git a/assets/failJSON26_test.json b/src/assets/failJSON26_test.json similarity index 100% rename from assets/failJSON26_test.json rename to src/assets/failJSON26_test.json diff --git a/assets/failJSON28_test.json b/src/assets/failJSON28_test.json similarity index 100% rename from assets/failJSON28_test.json rename to src/assets/failJSON28_test.json diff --git a/assets/failJSON29_test.json b/src/assets/failJSON29_test.json similarity index 100% rename from assets/failJSON29_test.json rename to src/assets/failJSON29_test.json diff --git a/assets/failJSON30_test.json b/src/assets/failJSON30_test.json similarity index 100% rename from assets/failJSON30_test.json rename to src/assets/failJSON30_test.json diff --git a/assets/failJSON31_test.json b/src/assets/failJSON31_test.json similarity index 100% rename from assets/failJSON31_test.json rename to src/assets/failJSON31_test.json diff --git a/assets/failJSON32_test.json b/src/assets/failJSON32_test.json similarity index 100% rename from assets/failJSON32_test.json rename to src/assets/failJSON32_test.json diff --git a/assets/failJSON33_test.json b/src/assets/failJSON33_test.json similarity index 100% rename from assets/failJSON33_test.json rename to src/assets/failJSON33_test.json diff --git a/assets/failJSON34_test.json b/src/assets/failJSON34_test.json similarity index 100% rename from assets/failJSON34_test.json rename to src/assets/failJSON34_test.json diff --git a/assets/failKey1_test.hjson b/src/assets/failKey1_test.hjson similarity index 100% rename from assets/failKey1_test.hjson rename to src/assets/failKey1_test.hjson diff --git a/assets/failKey2_test.hjson b/src/assets/failKey2_test.hjson similarity index 100% rename from assets/failKey2_test.hjson rename to src/assets/failKey2_test.hjson diff --git a/assets/failKey3_test.hjson b/src/assets/failKey3_test.hjson similarity index 100% rename from assets/failKey3_test.hjson rename to src/assets/failKey3_test.hjson diff --git a/assets/failKey4_test.hjson b/src/assets/failKey4_test.hjson similarity index 100% rename from assets/failKey4_test.hjson rename to src/assets/failKey4_test.hjson diff --git a/assets/failKey5_test.hjson b/src/assets/failKey5_test.hjson similarity index 100% rename from assets/failKey5_test.hjson rename to src/assets/failKey5_test.hjson diff --git a/assets/failMLStr1_test.hjson b/src/assets/failMLStr1_test.hjson similarity index 100% rename from assets/failMLStr1_test.hjson rename to src/assets/failMLStr1_test.hjson diff --git a/assets/failObj1_test.hjson b/src/assets/failObj1_test.hjson similarity index 100% rename from assets/failObj1_test.hjson rename to src/assets/failObj1_test.hjson diff --git a/assets/failObj2_test.hjson b/src/assets/failObj2_test.hjson similarity index 100% rename from assets/failObj2_test.hjson rename to src/assets/failObj2_test.hjson diff --git a/assets/failObj3_test.hjson b/src/assets/failObj3_test.hjson similarity index 100% rename from assets/failObj3_test.hjson rename to src/assets/failObj3_test.hjson diff --git a/assets/failStr1a_test.hjson b/src/assets/failStr1a_test.hjson similarity index 100% rename from assets/failStr1a_test.hjson rename to src/assets/failStr1a_test.hjson diff --git a/assets/failStr1b_test.hjson b/src/assets/failStr1b_test.hjson similarity index 100% rename from assets/failStr1b_test.hjson rename to src/assets/failStr1b_test.hjson diff --git a/assets/failStr1c_test.hjson b/src/assets/failStr1c_test.hjson similarity index 100% rename from assets/failStr1c_test.hjson rename to src/assets/failStr1c_test.hjson diff --git a/assets/failStr1d_test.hjson b/src/assets/failStr1d_test.hjson similarity index 100% rename from assets/failStr1d_test.hjson rename to src/assets/failStr1d_test.hjson diff --git a/assets/failStr2a_test.hjson b/src/assets/failStr2a_test.hjson similarity index 100% rename from assets/failStr2a_test.hjson rename to src/assets/failStr2a_test.hjson diff --git a/assets/failStr2b_test.hjson b/src/assets/failStr2b_test.hjson similarity index 100% rename from assets/failStr2b_test.hjson rename to src/assets/failStr2b_test.hjson diff --git a/assets/failStr2c_test.hjson b/src/assets/failStr2c_test.hjson similarity index 100% rename from assets/failStr2c_test.hjson rename to src/assets/failStr2c_test.hjson diff --git a/assets/failStr2d_test.hjson b/src/assets/failStr2d_test.hjson similarity index 100% rename from assets/failStr2d_test.hjson rename to src/assets/failStr2d_test.hjson diff --git a/assets/failStr3a_test.hjson b/src/assets/failStr3a_test.hjson similarity index 100% rename from assets/failStr3a_test.hjson rename to src/assets/failStr3a_test.hjson diff --git a/assets/failStr3b_test.hjson b/src/assets/failStr3b_test.hjson similarity index 100% rename from assets/failStr3b_test.hjson rename to src/assets/failStr3b_test.hjson diff --git a/assets/failStr3c_test.hjson b/src/assets/failStr3c_test.hjson similarity index 100% rename from assets/failStr3c_test.hjson rename to src/assets/failStr3c_test.hjson diff --git a/assets/failStr3d_test.hjson b/src/assets/failStr3d_test.hjson similarity index 100% rename from assets/failStr3d_test.hjson rename to src/assets/failStr3d_test.hjson diff --git a/assets/failStr4a_test.hjson b/src/assets/failStr4a_test.hjson similarity index 100% rename from assets/failStr4a_test.hjson rename to src/assets/failStr4a_test.hjson diff --git a/assets/failStr4b_test.hjson b/src/assets/failStr4b_test.hjson similarity index 100% rename from assets/failStr4b_test.hjson rename to src/assets/failStr4b_test.hjson diff --git a/assets/failStr4c_test.hjson b/src/assets/failStr4c_test.hjson similarity index 100% rename from assets/failStr4c_test.hjson rename to src/assets/failStr4c_test.hjson diff --git a/assets/failStr4d_test.hjson b/src/assets/failStr4d_test.hjson similarity index 100% rename from assets/failStr4d_test.hjson rename to src/assets/failStr4d_test.hjson diff --git a/assets/failStr5a_test.hjson b/src/assets/failStr5a_test.hjson similarity index 100% rename from assets/failStr5a_test.hjson rename to src/assets/failStr5a_test.hjson diff --git a/assets/failStr5b_test.hjson b/src/assets/failStr5b_test.hjson similarity index 100% rename from assets/failStr5b_test.hjson rename to src/assets/failStr5b_test.hjson diff --git a/assets/failStr5c_test.hjson b/src/assets/failStr5c_test.hjson similarity index 100% rename from assets/failStr5c_test.hjson rename to src/assets/failStr5c_test.hjson diff --git a/assets/failStr5d_test.hjson b/src/assets/failStr5d_test.hjson similarity index 100% rename from assets/failStr5d_test.hjson rename to src/assets/failStr5d_test.hjson diff --git a/assets/failStr6a_test.hjson b/src/assets/failStr6a_test.hjson similarity index 100% rename from assets/failStr6a_test.hjson rename to src/assets/failStr6a_test.hjson diff --git a/assets/failStr6b_test.hjson b/src/assets/failStr6b_test.hjson similarity index 100% rename from assets/failStr6b_test.hjson rename to src/assets/failStr6b_test.hjson diff --git a/assets/failStr6c_test.hjson b/src/assets/failStr6c_test.hjson similarity index 100% rename from assets/failStr6c_test.hjson rename to src/assets/failStr6c_test.hjson diff --git a/assets/failStr6d_test.hjson b/src/assets/failStr6d_test.hjson similarity index 100% rename from assets/failStr6d_test.hjson rename to src/assets/failStr6d_test.hjson diff --git a/assets/failStr7a_test.hjson b/src/assets/failStr7a_test.hjson similarity index 100% rename from assets/failStr7a_test.hjson rename to src/assets/failStr7a_test.hjson diff --git a/assets/failStr8a_test.hjson b/src/assets/failStr8a_test.hjson similarity index 100% rename from assets/failStr8a_test.hjson rename to src/assets/failStr8a_test.hjson diff --git a/assets/kan_result.hjson b/src/assets/kan_result.hjson similarity index 100% rename from assets/kan_result.hjson rename to src/assets/kan_result.hjson diff --git a/assets/kan_result.json b/src/assets/kan_result.json similarity index 100% rename from assets/kan_result.json rename to src/assets/kan_result.json diff --git a/assets/kan_test.hjson b/src/assets/kan_test.hjson similarity index 100% rename from assets/kan_test.hjson rename to src/assets/kan_test.hjson diff --git a/assets/keys_result.hjson b/src/assets/keys_result.hjson similarity index 100% rename from assets/keys_result.hjson rename to src/assets/keys_result.hjson diff --git a/assets/keys_result.json b/src/assets/keys_result.json similarity index 100% rename from assets/keys_result.json rename to src/assets/keys_result.json diff --git a/assets/keys_test.hjson b/src/assets/keys_test.hjson similarity index 100% rename from assets/keys_test.hjson rename to src/assets/keys_test.hjson diff --git a/assets/mltabs_result.hjson b/src/assets/mltabs_result.hjson similarity index 100% rename from assets/mltabs_result.hjson rename to src/assets/mltabs_result.hjson diff --git a/assets/mltabs_result.json b/src/assets/mltabs_result.json similarity index 100% rename from assets/mltabs_result.json rename to src/assets/mltabs_result.json diff --git a/assets/mltabs_test.json b/src/assets/mltabs_test.json similarity index 100% rename from assets/mltabs_test.json rename to src/assets/mltabs_test.json diff --git a/assets/oa_result.hjson b/src/assets/oa_result.hjson similarity index 100% rename from assets/oa_result.hjson rename to src/assets/oa_result.hjson diff --git a/assets/oa_result.json b/src/assets/oa_result.json similarity index 100% rename from assets/oa_result.json rename to src/assets/oa_result.json diff --git a/assets/oa_test.hjson b/src/assets/oa_test.hjson similarity index 100% rename from assets/oa_test.hjson rename to src/assets/oa_test.hjson diff --git a/assets/pass1_result.hjson b/src/assets/pass1_result.hjson similarity index 100% rename from assets/pass1_result.hjson rename to src/assets/pass1_result.hjson diff --git a/assets/pass1_result.json b/src/assets/pass1_result.json similarity index 100% rename from assets/pass1_result.json rename to src/assets/pass1_result.json diff --git a/assets/pass1_test.json b/src/assets/pass1_test.json similarity index 100% rename from assets/pass1_test.json rename to src/assets/pass1_test.json diff --git a/assets/pass2_result.hjson b/src/assets/pass2_result.hjson similarity index 100% rename from assets/pass2_result.hjson rename to src/assets/pass2_result.hjson diff --git a/assets/pass2_result.json b/src/assets/pass2_result.json similarity index 100% rename from assets/pass2_result.json rename to src/assets/pass2_result.json diff --git a/assets/pass2_test.json b/src/assets/pass2_test.json similarity index 100% rename from assets/pass2_test.json rename to src/assets/pass2_test.json diff --git a/assets/pass3_result.hjson b/src/assets/pass3_result.hjson similarity index 100% rename from assets/pass3_result.hjson rename to src/assets/pass3_result.hjson diff --git a/assets/pass3_result.json b/src/assets/pass3_result.json similarity index 100% rename from assets/pass3_result.json rename to src/assets/pass3_result.json diff --git a/assets/pass3_test.json b/src/assets/pass3_test.json similarity index 100% rename from assets/pass3_test.json rename to src/assets/pass3_test.json diff --git a/assets/pass4_result.hjson b/src/assets/pass4_result.hjson similarity index 100% rename from assets/pass4_result.hjson rename to src/assets/pass4_result.hjson diff --git a/assets/pass4_result.json b/src/assets/pass4_result.json similarity index 100% rename from assets/pass4_result.json rename to src/assets/pass4_result.json diff --git a/assets/pass4_test.json b/src/assets/pass4_test.json similarity index 100% rename from assets/pass4_test.json rename to src/assets/pass4_test.json diff --git a/assets/passSingle_result.hjson b/src/assets/passSingle_result.hjson similarity index 100% rename from assets/passSingle_result.hjson rename to src/assets/passSingle_result.hjson diff --git a/assets/passSingle_result.json b/src/assets/passSingle_result.json similarity index 100% rename from assets/passSingle_result.json rename to src/assets/passSingle_result.json diff --git a/assets/passSingle_test.hjson b/src/assets/passSingle_test.hjson similarity index 100% rename from assets/passSingle_test.hjson rename to src/assets/passSingle_test.hjson diff --git a/assets/rmcomments_result.hjson b/src/assets/rmcomments_result.hjson similarity index 100% rename from assets/rmcomments_result.hjson rename to src/assets/rmcomments_result.hjson diff --git a/assets/rmcomments_result.json b/src/assets/rmcomments_result.json similarity index 100% rename from assets/rmcomments_result.json rename to src/assets/rmcomments_result.json diff --git a/assets/rmcomments_test.hjson b/src/assets/rmcomments_test.hjson similarity index 100% rename from assets/rmcomments_test.hjson rename to src/assets/rmcomments_test.hjson diff --git a/assets/stringify1_result.hjson b/src/assets/stringify1_result.hjson similarity index 100% rename from assets/stringify1_result.hjson rename to src/assets/stringify1_result.hjson diff --git a/assets/stringify1_result.json b/src/assets/stringify1_result.json similarity index 100% rename from assets/stringify1_result.json rename to src/assets/stringify1_result.json diff --git a/assets/stringify1_test.hjson b/src/assets/stringify1_test.hjson similarity index 100% rename from assets/stringify1_test.hjson rename to src/assets/stringify1_test.hjson diff --git a/assets/strings2_result.hjson b/src/assets/strings2_result.hjson similarity index 100% rename from assets/strings2_result.hjson rename to src/assets/strings2_result.hjson diff --git a/assets/strings2_result.json b/src/assets/strings2_result.json similarity index 100% rename from assets/strings2_result.json rename to src/assets/strings2_result.json diff --git a/assets/strings2_test.hjson b/src/assets/strings2_test.hjson similarity index 100% rename from assets/strings2_test.hjson rename to src/assets/strings2_test.hjson diff --git a/assets/strings_result.hjson b/src/assets/strings_result.hjson similarity index 100% rename from assets/strings_result.hjson rename to src/assets/strings_result.hjson diff --git a/assets/strings_result.json b/src/assets/strings_result.json similarity index 100% rename from assets/strings_result.json rename to src/assets/strings_result.json diff --git a/assets/strings_test.hjson b/src/assets/strings_test.hjson similarity index 100% rename from assets/strings_test.hjson rename to src/assets/strings_test.hjson diff --git a/assets/testlist.txt b/src/assets/testlist.txt similarity index 100% rename from assets/testlist.txt rename to src/assets/testlist.txt diff --git a/assets/trail_result.hjson b/src/assets/trail_result.hjson similarity index 100% rename from assets/trail_result.hjson rename to src/assets/trail_result.hjson diff --git a/assets/trail_result.json b/src/assets/trail_result.json similarity index 100% rename from assets/trail_result.json rename to src/assets/trail_result.json diff --git a/assets/trail_test.hjson b/src/assets/trail_test.hjson similarity index 100% rename from assets/trail_test.hjson rename to src/assets/trail_test.hjson diff --git a/src/main/org/hjson/CommentStyle.java b/src/org/hjson/CommentStyle.java similarity index 100% rename from src/main/org/hjson/CommentStyle.java rename to src/org/hjson/CommentStyle.java diff --git a/src/main/org/hjson/CommentType.java b/src/org/hjson/CommentType.java similarity index 100% rename from src/main/org/hjson/CommentType.java rename to src/org/hjson/CommentType.java diff --git a/src/main/org/hjson/HjsonDsf.java b/src/org/hjson/HjsonDsf.java similarity index 100% rename from src/main/org/hjson/HjsonDsf.java rename to src/org/hjson/HjsonDsf.java diff --git a/src/main/org/hjson/HjsonOptions.java b/src/org/hjson/HjsonOptions.java similarity index 96% rename from src/main/org/hjson/HjsonOptions.java rename to src/org/hjson/HjsonOptions.java index c983460..052baf0 100644 --- a/src/main/org/hjson/HjsonOptions.java +++ b/src/org/hjson/HjsonOptions.java @@ -32,6 +32,7 @@ public class HjsonOptions { private boolean bracesSameLine; private boolean allowCondense; private boolean allowMultiVal; + private boolean emitRootBraces; private String space, commentSpace; public HjsonOptions() { @@ -40,6 +41,7 @@ public HjsonOptions() { bracesSameLine=false; allowCondense=true; allowMultiVal=true; + emitRootBraces=false; space=" "; commentSpace=""; outputComments=false; @@ -78,21 +80,17 @@ public HjsonOptions() { /** * Detects whether root braces should be emitted. * - * @deprecated will always return true. * @return true if this feature is enabled. */ - @Deprecated - public boolean getEmitRootBraces() { return true; } + public boolean getEmitRootBraces() { return emitRootBraces; } /** * Sets whether root braces should be emitted. * - * @deprecated root braces are always emitted. * @param value value * @return this, to enable chaining */ - @Deprecated - public HjsonOptions setEmitRootBraces(boolean value) { return this; } + public HjsonOptions setEmitRootBraces(boolean value) { emitRootBraces=value; return this; } /** * Detects whether braces and brackets should be placed on new lines. diff --git a/src/main/org/hjson/HjsonParser.java b/src/org/hjson/HjsonParser.java similarity index 100% rename from src/main/org/hjson/HjsonParser.java rename to src/org/hjson/HjsonParser.java diff --git a/src/main/org/hjson/HjsonWriter.java b/src/org/hjson/HjsonWriter.java similarity index 93% rename from src/main/org/hjson/HjsonWriter.java rename to src/org/hjson/HjsonWriter.java index d64891c..70e8f8f 100644 --- a/src/main/org/hjson/HjsonWriter.java +++ b/src/org/hjson/HjsonWriter.java @@ -32,6 +32,7 @@ class HjsonWriter { private boolean bracesSameLine; private boolean allowCondense; private boolean allowMultiVal; + private boolean emitRootBraces; private String space, commentSpace; static Pattern needsEscapeName=Pattern.compile("[,\\{\\[\\}\\]\\s:#\"']|//|/\\*"); @@ -45,11 +46,13 @@ public HjsonWriter(HjsonOptions options) { space=options.getSpace(); commentSpace=options.getCommentSpace(); outputComments=options.getOutputComments(); + emitRootBraces=options.getEmitRootBraces(); } else { dsfProviders=new IHjsonDsfProvider[0]; bracesSameLine=false; allowCondense=true; allowMultiVal=true; + emitRootBraces=false; space=" "; commentSpace=""; outputComments=false; @@ -97,7 +100,7 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea } // Write the header, if applicable. - if (this.outputComments && level==0 && value.hasBOLComment()) { + if (outputComments && level==0 && value.hasBOLComment()) { writeHeader(tw, value, level); } @@ -127,18 +130,19 @@ public void save(JsonValue value, Writer tw, int level, String separator, boolea } // Write any following comments. - if (this.outputComments && value.hasEOLComment()) { + if (outputComments && value.hasEOLComment()) { writeEOLComment(tw, value, level); } } void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean noIndent) throws IOException { // Start the beginning of the container. - openContainer(tw, noIndent, obj.isCondensed(), level, separator, '{'); + boolean emitBraces = emitBraces(obj, level); + if (!emitBraces) openContainer(tw, noIndent, obj.isCondensed(), level, separator, '{'); int index=0; for (JsonObject.Member pair : obj) { - if (this.outputComments && pair.getValue().hasBOLComment()) { + if (outputComments && pair.getValue().hasBOLComment()) { writeBOLComment(tw, pair.getValue(), level); } @@ -150,11 +154,11 @@ void writeObject(JsonObject obj, Writer tw, int level, String separator, boolean index++; } // Put interior comments at the bottom. - if (this.outputComments && obj.hasInteriorComment()) { + if (outputComments && obj.hasInteriorComment()) { writeInteriorComment(tw, obj, level); } // We've reached the end of the container. Close it off. - closeContainer(tw, obj.isCondensed(), obj.size(), level, '}'); + if (!emitBraces) closeContainer(tw, obj.isCondensed(), obj.size(), level, '}'); } void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean noIndent) throws IOException { @@ -173,13 +177,17 @@ void writeArray(JsonArray arr, Writer tw, int level, String separator, boolean n save(element, tw, level+1, "", true, forceQuoteArray); } // Put the interior comments at the bottom. - if (this.outputComments && arr.hasInteriorComment()) { + if (outputComments && arr.hasInteriorComment()) { writeInteriorComment(tw, arr, level); } // We've reached the end of the container. Close it off. closeContainer(tw, arr.isCondensed(), n, level, ']'); } + boolean emitBraces(JsonObject obj, int level) { + return emitRootBraces && level==0 && !(obj.hasBOLComment() && outputComments); + } + void openContainer(Writer tw, boolean noIndent, boolean condensed, int level, String separator, char openWith) throws IOException { if (!noIndent) { if (bracesSameLine || condensed) tw.write(separator); else nl(tw, level); } tw.write(openWith); @@ -219,7 +227,9 @@ void handleContainerLines(Writer tw, boolean compact, int index, int level, int // NL every (lineLength) # lines. if (!(compact && allowCondense)) { nl(tw, level+1); - } else { // Manually separate. + } else if (index>0) { // Manually separate. + tw.write(", "); + } else { tw.write(' '); } } else { diff --git a/src/main/org/hjson/IHjsonDsfProvider.java b/src/org/hjson/IHjsonDsfProvider.java similarity index 100% rename from src/main/org/hjson/IHjsonDsfProvider.java rename to src/org/hjson/IHjsonDsfProvider.java diff --git a/src/main/org/hjson/JsonArray.java b/src/org/hjson/JsonArray.java similarity index 100% rename from src/main/org/hjson/JsonArray.java rename to src/org/hjson/JsonArray.java diff --git a/src/main/org/hjson/JsonDsf.java b/src/org/hjson/JsonDsf.java similarity index 100% rename from src/main/org/hjson/JsonDsf.java rename to src/org/hjson/JsonDsf.java diff --git a/src/main/org/hjson/JsonLiteral.java b/src/org/hjson/JsonLiteral.java similarity index 100% rename from src/main/org/hjson/JsonLiteral.java rename to src/org/hjson/JsonLiteral.java diff --git a/src/main/org/hjson/JsonNumber.java b/src/org/hjson/JsonNumber.java similarity index 100% rename from src/main/org/hjson/JsonNumber.java rename to src/org/hjson/JsonNumber.java diff --git a/src/main/org/hjson/JsonObject.java b/src/org/hjson/JsonObject.java similarity index 100% rename from src/main/org/hjson/JsonObject.java rename to src/org/hjson/JsonObject.java diff --git a/src/main/org/hjson/JsonParser.java b/src/org/hjson/JsonParser.java similarity index 100% rename from src/main/org/hjson/JsonParser.java rename to src/org/hjson/JsonParser.java diff --git a/src/main/org/hjson/JsonString.java b/src/org/hjson/JsonString.java similarity index 100% rename from src/main/org/hjson/JsonString.java rename to src/org/hjson/JsonString.java diff --git a/src/main/org/hjson/JsonType.java b/src/org/hjson/JsonType.java similarity index 100% rename from src/main/org/hjson/JsonType.java rename to src/org/hjson/JsonType.java diff --git a/src/main/org/hjson/JsonValue.java b/src/org/hjson/JsonValue.java similarity index 100% rename from src/main/org/hjson/JsonValue.java rename to src/org/hjson/JsonValue.java diff --git a/src/main/org/hjson/JsonWriter.java b/src/org/hjson/JsonWriter.java similarity index 100% rename from src/main/org/hjson/JsonWriter.java rename to src/org/hjson/JsonWriter.java diff --git a/src/main/org/hjson/ParseException.java b/src/org/hjson/ParseException.java similarity index 100% rename from src/main/org/hjson/ParseException.java rename to src/org/hjson/ParseException.java diff --git a/src/main/org/hjson/Stringify.java b/src/org/hjson/Stringify.java similarity index 100% rename from src/main/org/hjson/Stringify.java rename to src/org/hjson/Stringify.java diff --git a/src/main/org/hjson/WritingBuffer.java b/src/org/hjson/WritingBuffer.java similarity index 100% rename from src/main/org/hjson/WritingBuffer.java rename to src/org/hjson/WritingBuffer.java diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index e1185a1..b8536d1 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -1,4 +1,4 @@ -package org.hjson.test; +package test.org.hjson.test; import org.hjson.*; import java.io.*; @@ -20,7 +20,7 @@ public static String convertStreamToString(InputStream is) throws IOException { } private static String load(String file, boolean cr) throws Exception { - InputStream res=Main.class.getResourceAsStream("/"+file); + InputStream res=Main.class.getResourceAsStream("/assets/"+file); if (res==null) throw new Exception(file+" not found!"); String text=convertStreamToString(res); String std=text.replace("\r", ""); // make sure we have unix style text regardless of the input @@ -31,7 +31,6 @@ 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); @@ -39,10 +38,13 @@ private static boolean test(String name, String file, boolean inputCr, boolean o try { HjsonOptions opt=new HjsonOptions(); opt.setParseLegacyRoot(false); + if (name.startsWith("comments")) { + opt.setOutputComments(true); + } JsonValue data=JsonValue.readHjson(text, opt); String data1=data.toString(Stringify.FORMATTED); - String hjson1=data.toString(useComments ? Stringify.HJSON_COMMENTS : Stringify.HJSON); + String hjson1=data.toString(opt); if (!shouldFail) { JsonValue result=JsonValue.readJSON(load(name+"_result.json", inputCr)); String data2=result.toString(Stringify.FORMATTED); From df33c588e24e67bbf067a94cbe737273de037662 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Sun, 21 Jun 2020 21:33:31 -0500 Subject: [PATCH 29/63] Value Usage Tracking --- src/org/hjson/JsonArray.java | 50 ++++++++++++++++++++++++----------- src/org/hjson/JsonObject.java | 26 +++++++++++++++++- src/org/hjson/JsonValue.java | 24 ++++++++++++++++- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/org/hjson/JsonArray.java b/src/org/hjson/JsonArray.java index 8d6a993..2e819aa 100644 --- a/src/org/hjson/JsonArray.java +++ b/src/org/hjson/JsonArray.java @@ -332,7 +332,7 @@ public JsonArray add(JsonValue value, String comment) { * index >= size */ public JsonArray set(int index, int value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -351,7 +351,7 @@ public JsonArray set(int index, int value) { * index >= size */ public JsonArray set(int index, int value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -369,7 +369,7 @@ public JsonArray set(int index, int value, String comment) { * index >= size */ public JsonArray set(int index, long value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -388,7 +388,7 @@ public JsonArray set(int index, long value) { * index >= size */ public JsonArray set(int index, long value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -406,7 +406,7 @@ public JsonArray set(int index, long value, String comment) { * index >= size */ public JsonArray set(int index, float value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -425,7 +425,7 @@ public JsonArray set(int index, float value) { * index >= size */ public JsonArray set(int index, float value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -443,7 +443,7 @@ public JsonArray set(int index, float value, String comment) { * index >= size */ public JsonArray set(int index, double value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -462,7 +462,7 @@ public JsonArray set(int index, double value) { * index >= size */ public JsonArray set(int index, double value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -480,7 +480,7 @@ public JsonArray set(int index, double value, String comment) { * index >= size */ public JsonArray set(int index, boolean value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -499,7 +499,7 @@ public JsonArray set(int index, boolean value) { * index >= size */ public JsonArray set(int index, boolean value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -517,7 +517,7 @@ public JsonArray set(int index, boolean value, String comment) { * index >= size */ public JsonArray set(int index, String value) { - values.set(index, valueOf(value)); + set(index, valueOf(value)); return this; } @@ -536,7 +536,7 @@ public JsonArray set(int index, String value) { * index >= size */ public JsonArray set(int index, String value, String comment) { - values.set(index, valueOf(value).setComment(comment)); + set(index, valueOf(value).setComment(comment)); return this; } @@ -556,7 +556,7 @@ public JsonArray set(int index, JsonValue value) { if (value==null) { throw new NullPointerException("value is null"); } - values.set(index, value); + values.set(index, value).setAccessed(true); return this; } @@ -593,7 +593,7 @@ public JsonArray set(int index, JsonValue value, String comment) { * @return the array itself to enable chaining. */ public JsonArray setComment(int index, String comment) { - values.get(index).setComment(comment); + get(index).setComment(comment); return this; } @@ -612,7 +612,7 @@ public JsonArray setComment(int index, String 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); + get(index).setComment(type, style, comment); return this; } @@ -660,7 +660,7 @@ public boolean isEmpty() { * index >= size */ public JsonValue get(int index) { - return values.get(index); + return values.get(index).setAccessed(true); } /** @@ -710,6 +710,24 @@ public List values() { */ public JsonArray setCondensed(boolean value) { condensed=value; return this; } + /** + * Generates a list of paths that have not yet been accessed in-code. + * @return the list of unused paths. + */ + public List getUnusedPaths() { + List paths=new ArrayList(); + int index=0; + for (JsonValue v : this) { + if (v.isObject()) { + for (String s : v.asObject().getUnusedPaths()) { + paths.add("["+index+"]."+s); + } + } + index++; + } + return paths; + } + /** * 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/org/hjson/JsonObject.java b/src/org/hjson/JsonObject.java index 0001761..327976d 100644 --- a/src/org/hjson/JsonObject.java +++ b/src/org/hjson/JsonObject.java @@ -661,6 +661,7 @@ public JsonObject set(String name, JsonValue value) { if (value==null) { throw new NullPointerException("value is null"); } + value.setAccessed(true); int index=indexOf(name); if (index!=-1) { values.set(index, value); @@ -761,7 +762,7 @@ public JsonValue get(String name) { throw new NullPointerException("name is null"); } int index=indexOf(name); - return index!=-1 ? values.get(index) : null; + return index!=-1 ? values.get(index).setAccessed(true) : null; } /** @@ -942,6 +943,29 @@ public List names() { */ public JsonObject setCondensed(boolean value) { condensed=value; return this; } + /** + * Generates a list of paths that have not yet been accessed in-code. + * @return the list of unused paths. + */ + public List getUnusedPaths() { + List paths=new ArrayList(); + for (Member m : this) { + if (!m.value.isAccessed()) { + paths.add(m.name); + } //else {paths.add("*"+m.name);} + if (m.value.isObject()) { + for (String s : m.value.asObject().getUnusedPaths()) { + paths.add(m.name+"."+s); + } + } else if (m.value.isArray()) { + for (String s : m.value.asArray().getUnusedPaths()) { + paths.add(m.name+s); + } + } + } + return paths; + } + /** * Sorts all members of this object according to their keys, in alphabetical order. * diff --git a/src/org/hjson/JsonValue.java b/src/org/hjson/JsonValue.java index ad972dc..d008b43 100644 --- a/src/org/hjson/JsonValue.java +++ b/src/org/hjson/JsonValue.java @@ -27,7 +27,6 @@ import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; -import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Set; @@ -70,6 +69,11 @@ public abstract class JsonValue implements Serializable { */ protected String bolComment="", eolComment="", intComment=""; + /** + * A flag indicating whether this value has been specifically called for. + */ + protected boolean accessed; + /** * Gets the newline charater(s). * @@ -372,6 +376,24 @@ public boolean isNull() { return false; } + /** + * Detects whether this value has been accessed in-code. + * @return true if the value has been used. + */ + public boolean isAccessed() { + return accessed; + } + + /** + * Overrides whether this field has been accessed in-code. + * @param b The value to override with. + * @return This, to enable chaining. + */ + public JsonValue setAccessed(boolean b) { + accessed=b; + return this; + } + /** * Detects whether this value contains any comments. * From d93f21fc4b57b639f111410a532316c3d3f3f4d9 Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Sun, 21 Jun 2020 22:17:17 -0500 Subject: [PATCH 30/63] Bump Jitpack --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b1b3bc..c121847 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # hjson-java - + [![Build Status](https://img.shields.io/travis/hjson/hjson-java.svg?style=flat-square)](http://travis-ci.org/hjson/hjson-java) [![Maven Central](https://img.shields.io/maven-central/v/org.hjson/hjson.svg?style=flat-square)](http://search.maven.org/#search|ga|1|g%3A%22org.hjson%22%20a%3A%22hjson%22) [![Javadoc](https://javadoc-emblem.rhcloud.com/doc/org.hjson/hjson/badge.svg?style=flat-square&color=blue)](http://www.javadoc.io/doc/org.hjson/hjson) From 6eed3f3dfc2ba5191a0f06afaa82d9b8f673f38b Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Mon, 22 Jun 2020 18:24:47 -0500 Subject: [PATCH 31/63] Revert Project Structure Changes --- {src/assets => assets}/charset_result.hjson | 0 {src/assets => assets}/charset_result.json | 0 {src/assets => assets}/charset_test.hjson | 0 {src/assets => assets}/comments1_result.hjson | 0 {src/assets => assets}/comments1_result.json | 0 {src/assets => assets}/comments1_test.hjson | 0 {src/assets => assets}/empty_result.hjson | 0 {src/assets => assets}/empty_result.json | 0 {src/assets => assets}/empty_test.hjson | 0 {src/assets => assets}/failCharset1_test.hjson | 0 {src/assets => assets}/failJSON02_test.json | 0 {src/assets => assets}/failJSON05_test.json | 0 {src/assets => assets}/failJSON06_test.json | 0 {src/assets => assets}/failJSON07_test.json | 0 {src/assets => assets}/failJSON08_test.json | 0 {src/assets => assets}/failJSON10_test.json | 0 {src/assets => assets}/failJSON11_test.json | 0 {src/assets => assets}/failJSON12_test.json | 0 {src/assets => assets}/failJSON13_test.json | 0 {src/assets => assets}/failJSON14_test.json | 0 {src/assets => assets}/failJSON15_test.json | 0 {src/assets => assets}/failJSON16_test.json | 0 {src/assets => assets}/failJSON17_test.json | 0 {src/assets => assets}/failJSON19_test.json | 0 {src/assets => assets}/failJSON20_test.json | 0 {src/assets => assets}/failJSON21_test.json | 0 {src/assets => assets}/failJSON22_test.json | 0 {src/assets => assets}/failJSON23_test.json | 0 {src/assets => assets}/failJSON26_test.json | 0 {src/assets => assets}/failJSON28_test.json | 0 {src/assets => assets}/failJSON29_test.json | 0 {src/assets => assets}/failJSON30_test.json | 0 {src/assets => assets}/failJSON31_test.json | 0 {src/assets => assets}/failJSON32_test.json | 0 {src/assets => assets}/failJSON33_test.json | 0 {src/assets => assets}/failJSON34_test.json | 0 {src/assets => assets}/failKey1_test.hjson | 0 {src/assets => assets}/failKey2_test.hjson | 0 {src/assets => assets}/failKey3_test.hjson | 0 {src/assets => assets}/failKey4_test.hjson | 0 {src/assets => assets}/failKey5_test.hjson | 0 {src/assets => assets}/failMLStr1_test.hjson | 0 {src/assets => assets}/failObj1_test.hjson | 0 {src/assets => assets}/failObj2_test.hjson | 0 {src/assets => assets}/failObj3_test.hjson | 0 {src/assets => assets}/failStr1a_test.hjson | 0 {src/assets => assets}/failStr1b_test.hjson | 0 {src/assets => assets}/failStr1c_test.hjson | 0 {src/assets => assets}/failStr1d_test.hjson | 0 {src/assets => assets}/failStr2a_test.hjson | 0 {src/assets => assets}/failStr2b_test.hjson | 0 {src/assets => assets}/failStr2c_test.hjson | 0 {src/assets => assets}/failStr2d_test.hjson | 0 {src/assets => assets}/failStr3a_test.hjson | 0 {src/assets => assets}/failStr3b_test.hjson | 0 {src/assets => assets}/failStr3c_test.hjson | 0 {src/assets => assets}/failStr3d_test.hjson | 0 {src/assets => assets}/failStr4a_test.hjson | 0 {src/assets => assets}/failStr4b_test.hjson | 0 {src/assets => assets}/failStr4c_test.hjson | 0 {src/assets => assets}/failStr4d_test.hjson | 0 {src/assets => assets}/failStr5a_test.hjson | 0 {src/assets => assets}/failStr5b_test.hjson | 0 {src/assets => assets}/failStr5c_test.hjson | 0 {src/assets => assets}/failStr5d_test.hjson | 0 {src/assets => assets}/failStr6a_test.hjson | 0 {src/assets => assets}/failStr6b_test.hjson | 0 {src/assets => assets}/failStr6c_test.hjson | 0 {src/assets => assets}/failStr6d_test.hjson | 0 {src/assets => assets}/failStr7a_test.hjson | 0 {src/assets => assets}/failStr8a_test.hjson | 0 {src/assets => assets}/kan_result.hjson | 0 {src/assets => assets}/kan_result.json | 0 {src/assets => assets}/kan_test.hjson | 0 {src/assets => assets}/keys_result.hjson | 0 {src/assets => assets}/keys_result.json | 0 {src/assets => assets}/keys_test.hjson | 0 {src/assets => assets}/mltabs_result.hjson | 0 {src/assets => assets}/mltabs_result.json | 0 {src/assets => assets}/mltabs_test.json | 0 {src/assets => assets}/oa_result.hjson | 0 {src/assets => assets}/oa_result.json | 0 {src/assets => assets}/oa_test.hjson | 0 {src/assets => assets}/pass1_result.hjson | 0 {src/assets => assets}/pass1_result.json | 0 {src/assets => assets}/pass1_test.json | 0 {src/assets => assets}/pass2_result.hjson | 0 {src/assets => assets}/pass2_result.json | 0 {src/assets => assets}/pass2_test.json | 0 {src/assets => assets}/pass3_result.hjson | 0 {src/assets => assets}/pass3_result.json | 0 {src/assets => assets}/pass3_test.json | 0 {src/assets => assets}/pass4_result.hjson | 0 {src/assets => assets}/pass4_result.json | 0 {src/assets => assets}/pass4_test.json | 0 {src/assets => assets}/passSingle_result.hjson | 0 {src/assets => assets}/passSingle_result.json | 0 {src/assets => assets}/passSingle_test.hjson | 0 {src/assets => assets}/rmcomments_result.hjson | 0 {src/assets => assets}/rmcomments_result.json | 0 {src/assets => assets}/rmcomments_test.hjson | 0 {src/assets => assets}/stringify1_result.hjson | 0 {src/assets => assets}/stringify1_result.json | 0 {src/assets => assets}/stringify1_test.hjson | 0 {src/assets => assets}/strings2_result.hjson | 0 {src/assets => assets}/strings2_result.json | 0 {src/assets => assets}/strings2_test.hjson | 0 {src/assets => assets}/strings_result.hjson | 0 {src/assets => assets}/strings_result.json | 0 {src/assets => assets}/strings_test.hjson | 0 {src/assets => assets}/testlist.txt | 0 {src/assets => assets}/trail_result.hjson | 0 {src/assets => assets}/trail_result.json | 0 {src/assets => assets}/trail_test.hjson | 0 build.gradle | 10 +++++++++- src/{ => main}/org/hjson/CommentStyle.java | 0 src/{ => main}/org/hjson/CommentType.java | 0 src/{ => main}/org/hjson/HjsonDsf.java | 0 src/{ => main}/org/hjson/HjsonOptions.java | 0 src/{ => main}/org/hjson/HjsonParser.java | 0 src/{ => main}/org/hjson/HjsonWriter.java | 0 src/{ => main}/org/hjson/IHjsonDsfProvider.java | 0 src/{ => main}/org/hjson/JsonArray.java | 0 src/{ => main}/org/hjson/JsonDsf.java | 0 src/{ => main}/org/hjson/JsonLiteral.java | 0 src/{ => main}/org/hjson/JsonNumber.java | 0 src/{ => main}/org/hjson/JsonObject.java | 2 +- src/{ => main}/org/hjson/JsonParser.java | 0 src/{ => main}/org/hjson/JsonString.java | 0 src/{ => main}/org/hjson/JsonType.java | 0 src/{ => main}/org/hjson/JsonValue.java | 2 ++ src/{ => main}/org/hjson/JsonWriter.java | 0 src/{ => main}/org/hjson/ParseException.java | 0 src/{ => main}/org/hjson/Stringify.java | 0 src/{ => main}/org/hjson/WritingBuffer.java | 0 src/test/org/hjson/test/Main.java | 7 ++++--- 136 files changed, 16 insertions(+), 5 deletions(-) rename {src/assets => assets}/charset_result.hjson (100%) rename {src/assets => assets}/charset_result.json (100%) rename {src/assets => assets}/charset_test.hjson (100%) rename {src/assets => assets}/comments1_result.hjson (100%) rename {src/assets => assets}/comments1_result.json (100%) rename {src/assets => assets}/comments1_test.hjson (100%) rename {src/assets => assets}/empty_result.hjson (100%) rename {src/assets => assets}/empty_result.json (100%) rename {src/assets => assets}/empty_test.hjson (100%) rename {src/assets => assets}/failCharset1_test.hjson (100%) rename {src/assets => assets}/failJSON02_test.json (100%) rename {src/assets => assets}/failJSON05_test.json (100%) rename {src/assets => assets}/failJSON06_test.json (100%) rename {src/assets => assets}/failJSON07_test.json (100%) rename {src/assets => assets}/failJSON08_test.json (100%) rename {src/assets => assets}/failJSON10_test.json (100%) rename {src/assets => assets}/failJSON11_test.json (100%) rename {src/assets => assets}/failJSON12_test.json (100%) rename {src/assets => assets}/failJSON13_test.json (100%) rename {src/assets => assets}/failJSON14_test.json (100%) rename {src/assets => assets}/failJSON15_test.json (100%) rename {src/assets => assets}/failJSON16_test.json (100%) rename {src/assets => assets}/failJSON17_test.json (100%) rename {src/assets => assets}/failJSON19_test.json (100%) rename {src/assets => assets}/failJSON20_test.json (100%) rename {src/assets => assets}/failJSON21_test.json (100%) rename {src/assets => assets}/failJSON22_test.json (100%) rename {src/assets => assets}/failJSON23_test.json (100%) rename {src/assets => assets}/failJSON26_test.json (100%) rename {src/assets => assets}/failJSON28_test.json (100%) rename {src/assets => assets}/failJSON29_test.json (100%) rename {src/assets => assets}/failJSON30_test.json (100%) rename {src/assets => assets}/failJSON31_test.json (100%) rename {src/assets => assets}/failJSON32_test.json (100%) rename {src/assets => assets}/failJSON33_test.json (100%) rename {src/assets => assets}/failJSON34_test.json (100%) rename {src/assets => assets}/failKey1_test.hjson (100%) rename {src/assets => assets}/failKey2_test.hjson (100%) rename {src/assets => assets}/failKey3_test.hjson (100%) rename {src/assets => assets}/failKey4_test.hjson (100%) rename {src/assets => assets}/failKey5_test.hjson (100%) rename {src/assets => assets}/failMLStr1_test.hjson (100%) rename {src/assets => assets}/failObj1_test.hjson (100%) rename {src/assets => assets}/failObj2_test.hjson (100%) rename {src/assets => assets}/failObj3_test.hjson (100%) rename {src/assets => assets}/failStr1a_test.hjson (100%) rename {src/assets => assets}/failStr1b_test.hjson (100%) rename {src/assets => assets}/failStr1c_test.hjson (100%) rename {src/assets => assets}/failStr1d_test.hjson (100%) rename {src/assets => assets}/failStr2a_test.hjson (100%) rename {src/assets => assets}/failStr2b_test.hjson (100%) rename {src/assets => assets}/failStr2c_test.hjson (100%) rename {src/assets => assets}/failStr2d_test.hjson (100%) rename {src/assets => assets}/failStr3a_test.hjson (100%) rename {src/assets => assets}/failStr3b_test.hjson (100%) rename {src/assets => assets}/failStr3c_test.hjson (100%) rename {src/assets => assets}/failStr3d_test.hjson (100%) rename {src/assets => assets}/failStr4a_test.hjson (100%) rename {src/assets => assets}/failStr4b_test.hjson (100%) rename {src/assets => assets}/failStr4c_test.hjson (100%) rename {src/assets => assets}/failStr4d_test.hjson (100%) rename {src/assets => assets}/failStr5a_test.hjson (100%) rename {src/assets => assets}/failStr5b_test.hjson (100%) rename {src/assets => assets}/failStr5c_test.hjson (100%) rename {src/assets => assets}/failStr5d_test.hjson (100%) rename {src/assets => assets}/failStr6a_test.hjson (100%) rename {src/assets => assets}/failStr6b_test.hjson (100%) rename {src/assets => assets}/failStr6c_test.hjson (100%) rename {src/assets => assets}/failStr6d_test.hjson (100%) rename {src/assets => assets}/failStr7a_test.hjson (100%) rename {src/assets => assets}/failStr8a_test.hjson (100%) rename {src/assets => assets}/kan_result.hjson (100%) rename {src/assets => assets}/kan_result.json (100%) rename {src/assets => assets}/kan_test.hjson (100%) rename {src/assets => assets}/keys_result.hjson (100%) rename {src/assets => assets}/keys_result.json (100%) rename {src/assets => assets}/keys_test.hjson (100%) rename {src/assets => assets}/mltabs_result.hjson (100%) rename {src/assets => assets}/mltabs_result.json (100%) rename {src/assets => assets}/mltabs_test.json (100%) rename {src/assets => assets}/oa_result.hjson (100%) rename {src/assets => assets}/oa_result.json (100%) rename {src/assets => assets}/oa_test.hjson (100%) rename {src/assets => assets}/pass1_result.hjson (100%) rename {src/assets => assets}/pass1_result.json (100%) rename {src/assets => assets}/pass1_test.json (100%) rename {src/assets => assets}/pass2_result.hjson (100%) rename {src/assets => assets}/pass2_result.json (100%) rename {src/assets => assets}/pass2_test.json (100%) rename {src/assets => assets}/pass3_result.hjson (100%) rename {src/assets => assets}/pass3_result.json (100%) rename {src/assets => assets}/pass3_test.json (100%) rename {src/assets => assets}/pass4_result.hjson (100%) rename {src/assets => assets}/pass4_result.json (100%) rename {src/assets => assets}/pass4_test.json (100%) rename {src/assets => assets}/passSingle_result.hjson (100%) rename {src/assets => assets}/passSingle_result.json (100%) rename {src/assets => assets}/passSingle_test.hjson (100%) rename {src/assets => assets}/rmcomments_result.hjson (100%) rename {src/assets => assets}/rmcomments_result.json (100%) rename {src/assets => assets}/rmcomments_test.hjson (100%) rename {src/assets => assets}/stringify1_result.hjson (100%) rename {src/assets => assets}/stringify1_result.json (100%) rename {src/assets => assets}/stringify1_test.hjson (100%) rename {src/assets => assets}/strings2_result.hjson (100%) rename {src/assets => assets}/strings2_result.json (100%) rename {src/assets => assets}/strings2_test.hjson (100%) rename {src/assets => assets}/strings_result.hjson (100%) rename {src/assets => assets}/strings_result.json (100%) rename {src/assets => assets}/strings_test.hjson (100%) rename {src/assets => assets}/testlist.txt (100%) rename {src/assets => assets}/trail_result.hjson (100%) rename {src/assets => assets}/trail_result.json (100%) rename {src/assets => assets}/trail_test.hjson (100%) rename src/{ => main}/org/hjson/CommentStyle.java (100%) rename src/{ => main}/org/hjson/CommentType.java (100%) rename src/{ => main}/org/hjson/HjsonDsf.java (100%) rename src/{ => main}/org/hjson/HjsonOptions.java (100%) rename src/{ => main}/org/hjson/HjsonParser.java (100%) rename src/{ => main}/org/hjson/HjsonWriter.java (100%) rename src/{ => main}/org/hjson/IHjsonDsfProvider.java (100%) rename src/{ => main}/org/hjson/JsonArray.java (100%) rename src/{ => main}/org/hjson/JsonDsf.java (100%) rename src/{ => main}/org/hjson/JsonLiteral.java (100%) rename src/{ => main}/org/hjson/JsonNumber.java (100%) rename src/{ => main}/org/hjson/JsonObject.java (99%) rename src/{ => main}/org/hjson/JsonParser.java (100%) rename src/{ => main}/org/hjson/JsonString.java (100%) rename src/{ => main}/org/hjson/JsonType.java (100%) rename src/{ => main}/org/hjson/JsonValue.java (99%) rename src/{ => main}/org/hjson/JsonWriter.java (100%) rename src/{ => main}/org/hjson/ParseException.java (100%) rename src/{ => main}/org/hjson/Stringify.java (100%) rename src/{ => main}/org/hjson/WritingBuffer.java (100%) diff --git a/src/assets/charset_result.hjson b/assets/charset_result.hjson similarity index 100% rename from src/assets/charset_result.hjson rename to assets/charset_result.hjson diff --git a/src/assets/charset_result.json b/assets/charset_result.json similarity index 100% rename from src/assets/charset_result.json rename to assets/charset_result.json diff --git a/src/assets/charset_test.hjson b/assets/charset_test.hjson similarity index 100% rename from src/assets/charset_test.hjson rename to assets/charset_test.hjson diff --git a/src/assets/comments1_result.hjson b/assets/comments1_result.hjson similarity index 100% rename from src/assets/comments1_result.hjson rename to assets/comments1_result.hjson diff --git a/src/assets/comments1_result.json b/assets/comments1_result.json similarity index 100% rename from src/assets/comments1_result.json rename to assets/comments1_result.json diff --git a/src/assets/comments1_test.hjson b/assets/comments1_test.hjson similarity index 100% rename from src/assets/comments1_test.hjson rename to assets/comments1_test.hjson diff --git a/src/assets/empty_result.hjson b/assets/empty_result.hjson similarity index 100% rename from src/assets/empty_result.hjson rename to assets/empty_result.hjson diff --git a/src/assets/empty_result.json b/assets/empty_result.json similarity index 100% rename from src/assets/empty_result.json rename to assets/empty_result.json diff --git a/src/assets/empty_test.hjson b/assets/empty_test.hjson similarity index 100% rename from src/assets/empty_test.hjson rename to assets/empty_test.hjson diff --git a/src/assets/failCharset1_test.hjson b/assets/failCharset1_test.hjson similarity index 100% rename from src/assets/failCharset1_test.hjson rename to assets/failCharset1_test.hjson diff --git a/src/assets/failJSON02_test.json b/assets/failJSON02_test.json similarity index 100% rename from src/assets/failJSON02_test.json rename to assets/failJSON02_test.json diff --git a/src/assets/failJSON05_test.json b/assets/failJSON05_test.json similarity index 100% rename from src/assets/failJSON05_test.json rename to assets/failJSON05_test.json diff --git a/src/assets/failJSON06_test.json b/assets/failJSON06_test.json similarity index 100% rename from src/assets/failJSON06_test.json rename to assets/failJSON06_test.json diff --git a/src/assets/failJSON07_test.json b/assets/failJSON07_test.json similarity index 100% rename from src/assets/failJSON07_test.json rename to assets/failJSON07_test.json diff --git a/src/assets/failJSON08_test.json b/assets/failJSON08_test.json similarity index 100% rename from src/assets/failJSON08_test.json rename to assets/failJSON08_test.json diff --git a/src/assets/failJSON10_test.json b/assets/failJSON10_test.json similarity index 100% rename from src/assets/failJSON10_test.json rename to assets/failJSON10_test.json diff --git a/src/assets/failJSON11_test.json b/assets/failJSON11_test.json similarity index 100% rename from src/assets/failJSON11_test.json rename to assets/failJSON11_test.json diff --git a/src/assets/failJSON12_test.json b/assets/failJSON12_test.json similarity index 100% rename from src/assets/failJSON12_test.json rename to assets/failJSON12_test.json diff --git a/src/assets/failJSON13_test.json b/assets/failJSON13_test.json similarity index 100% rename from src/assets/failJSON13_test.json rename to assets/failJSON13_test.json diff --git a/src/assets/failJSON14_test.json b/assets/failJSON14_test.json similarity index 100% rename from src/assets/failJSON14_test.json rename to assets/failJSON14_test.json diff --git a/src/assets/failJSON15_test.json b/assets/failJSON15_test.json similarity index 100% rename from src/assets/failJSON15_test.json rename to assets/failJSON15_test.json diff --git a/src/assets/failJSON16_test.json b/assets/failJSON16_test.json similarity index 100% rename from src/assets/failJSON16_test.json rename to assets/failJSON16_test.json diff --git a/src/assets/failJSON17_test.json b/assets/failJSON17_test.json similarity index 100% rename from src/assets/failJSON17_test.json rename to assets/failJSON17_test.json diff --git a/src/assets/failJSON19_test.json b/assets/failJSON19_test.json similarity index 100% rename from src/assets/failJSON19_test.json rename to assets/failJSON19_test.json diff --git a/src/assets/failJSON20_test.json b/assets/failJSON20_test.json similarity index 100% rename from src/assets/failJSON20_test.json rename to assets/failJSON20_test.json diff --git a/src/assets/failJSON21_test.json b/assets/failJSON21_test.json similarity index 100% rename from src/assets/failJSON21_test.json rename to assets/failJSON21_test.json diff --git a/src/assets/failJSON22_test.json b/assets/failJSON22_test.json similarity index 100% rename from src/assets/failJSON22_test.json rename to assets/failJSON22_test.json diff --git a/src/assets/failJSON23_test.json b/assets/failJSON23_test.json similarity index 100% rename from src/assets/failJSON23_test.json rename to assets/failJSON23_test.json diff --git a/src/assets/failJSON26_test.json b/assets/failJSON26_test.json similarity index 100% rename from src/assets/failJSON26_test.json rename to assets/failJSON26_test.json diff --git a/src/assets/failJSON28_test.json b/assets/failJSON28_test.json similarity index 100% rename from src/assets/failJSON28_test.json rename to assets/failJSON28_test.json diff --git a/src/assets/failJSON29_test.json b/assets/failJSON29_test.json similarity index 100% rename from src/assets/failJSON29_test.json rename to assets/failJSON29_test.json diff --git a/src/assets/failJSON30_test.json b/assets/failJSON30_test.json similarity index 100% rename from src/assets/failJSON30_test.json rename to assets/failJSON30_test.json diff --git a/src/assets/failJSON31_test.json b/assets/failJSON31_test.json similarity index 100% rename from src/assets/failJSON31_test.json rename to assets/failJSON31_test.json diff --git a/src/assets/failJSON32_test.json b/assets/failJSON32_test.json similarity index 100% rename from src/assets/failJSON32_test.json rename to assets/failJSON32_test.json diff --git a/src/assets/failJSON33_test.json b/assets/failJSON33_test.json similarity index 100% rename from src/assets/failJSON33_test.json rename to assets/failJSON33_test.json diff --git a/src/assets/failJSON34_test.json b/assets/failJSON34_test.json similarity index 100% rename from src/assets/failJSON34_test.json rename to assets/failJSON34_test.json diff --git a/src/assets/failKey1_test.hjson b/assets/failKey1_test.hjson similarity index 100% rename from src/assets/failKey1_test.hjson rename to assets/failKey1_test.hjson diff --git a/src/assets/failKey2_test.hjson b/assets/failKey2_test.hjson similarity index 100% rename from src/assets/failKey2_test.hjson rename to assets/failKey2_test.hjson diff --git a/src/assets/failKey3_test.hjson b/assets/failKey3_test.hjson similarity index 100% rename from src/assets/failKey3_test.hjson rename to assets/failKey3_test.hjson diff --git a/src/assets/failKey4_test.hjson b/assets/failKey4_test.hjson similarity index 100% rename from src/assets/failKey4_test.hjson rename to assets/failKey4_test.hjson diff --git a/src/assets/failKey5_test.hjson b/assets/failKey5_test.hjson similarity index 100% rename from src/assets/failKey5_test.hjson rename to assets/failKey5_test.hjson diff --git a/src/assets/failMLStr1_test.hjson b/assets/failMLStr1_test.hjson similarity index 100% rename from src/assets/failMLStr1_test.hjson rename to assets/failMLStr1_test.hjson diff --git a/src/assets/failObj1_test.hjson b/assets/failObj1_test.hjson similarity index 100% rename from src/assets/failObj1_test.hjson rename to assets/failObj1_test.hjson diff --git a/src/assets/failObj2_test.hjson b/assets/failObj2_test.hjson similarity index 100% rename from src/assets/failObj2_test.hjson rename to assets/failObj2_test.hjson diff --git a/src/assets/failObj3_test.hjson b/assets/failObj3_test.hjson similarity index 100% rename from src/assets/failObj3_test.hjson rename to assets/failObj3_test.hjson diff --git a/src/assets/failStr1a_test.hjson b/assets/failStr1a_test.hjson similarity index 100% rename from src/assets/failStr1a_test.hjson rename to assets/failStr1a_test.hjson diff --git a/src/assets/failStr1b_test.hjson b/assets/failStr1b_test.hjson similarity index 100% rename from src/assets/failStr1b_test.hjson rename to assets/failStr1b_test.hjson diff --git a/src/assets/failStr1c_test.hjson b/assets/failStr1c_test.hjson similarity index 100% rename from src/assets/failStr1c_test.hjson rename to assets/failStr1c_test.hjson diff --git a/src/assets/failStr1d_test.hjson b/assets/failStr1d_test.hjson similarity index 100% rename from src/assets/failStr1d_test.hjson rename to assets/failStr1d_test.hjson diff --git a/src/assets/failStr2a_test.hjson b/assets/failStr2a_test.hjson similarity index 100% rename from src/assets/failStr2a_test.hjson rename to assets/failStr2a_test.hjson diff --git a/src/assets/failStr2b_test.hjson b/assets/failStr2b_test.hjson similarity index 100% rename from src/assets/failStr2b_test.hjson rename to assets/failStr2b_test.hjson diff --git a/src/assets/failStr2c_test.hjson b/assets/failStr2c_test.hjson similarity index 100% rename from src/assets/failStr2c_test.hjson rename to assets/failStr2c_test.hjson diff --git a/src/assets/failStr2d_test.hjson b/assets/failStr2d_test.hjson similarity index 100% rename from src/assets/failStr2d_test.hjson rename to assets/failStr2d_test.hjson diff --git a/src/assets/failStr3a_test.hjson b/assets/failStr3a_test.hjson similarity index 100% rename from src/assets/failStr3a_test.hjson rename to assets/failStr3a_test.hjson diff --git a/src/assets/failStr3b_test.hjson b/assets/failStr3b_test.hjson similarity index 100% rename from src/assets/failStr3b_test.hjson rename to assets/failStr3b_test.hjson diff --git a/src/assets/failStr3c_test.hjson b/assets/failStr3c_test.hjson similarity index 100% rename from src/assets/failStr3c_test.hjson rename to assets/failStr3c_test.hjson diff --git a/src/assets/failStr3d_test.hjson b/assets/failStr3d_test.hjson similarity index 100% rename from src/assets/failStr3d_test.hjson rename to assets/failStr3d_test.hjson diff --git a/src/assets/failStr4a_test.hjson b/assets/failStr4a_test.hjson similarity index 100% rename from src/assets/failStr4a_test.hjson rename to assets/failStr4a_test.hjson diff --git a/src/assets/failStr4b_test.hjson b/assets/failStr4b_test.hjson similarity index 100% rename from src/assets/failStr4b_test.hjson rename to assets/failStr4b_test.hjson diff --git a/src/assets/failStr4c_test.hjson b/assets/failStr4c_test.hjson similarity index 100% rename from src/assets/failStr4c_test.hjson rename to assets/failStr4c_test.hjson diff --git a/src/assets/failStr4d_test.hjson b/assets/failStr4d_test.hjson similarity index 100% rename from src/assets/failStr4d_test.hjson rename to assets/failStr4d_test.hjson diff --git a/src/assets/failStr5a_test.hjson b/assets/failStr5a_test.hjson similarity index 100% rename from src/assets/failStr5a_test.hjson rename to assets/failStr5a_test.hjson diff --git a/src/assets/failStr5b_test.hjson b/assets/failStr5b_test.hjson similarity index 100% rename from src/assets/failStr5b_test.hjson rename to assets/failStr5b_test.hjson diff --git a/src/assets/failStr5c_test.hjson b/assets/failStr5c_test.hjson similarity index 100% rename from src/assets/failStr5c_test.hjson rename to assets/failStr5c_test.hjson diff --git a/src/assets/failStr5d_test.hjson b/assets/failStr5d_test.hjson similarity index 100% rename from src/assets/failStr5d_test.hjson rename to assets/failStr5d_test.hjson diff --git a/src/assets/failStr6a_test.hjson b/assets/failStr6a_test.hjson similarity index 100% rename from src/assets/failStr6a_test.hjson rename to assets/failStr6a_test.hjson diff --git a/src/assets/failStr6b_test.hjson b/assets/failStr6b_test.hjson similarity index 100% rename from src/assets/failStr6b_test.hjson rename to assets/failStr6b_test.hjson diff --git a/src/assets/failStr6c_test.hjson b/assets/failStr6c_test.hjson similarity index 100% rename from src/assets/failStr6c_test.hjson rename to assets/failStr6c_test.hjson diff --git a/src/assets/failStr6d_test.hjson b/assets/failStr6d_test.hjson similarity index 100% rename from src/assets/failStr6d_test.hjson rename to assets/failStr6d_test.hjson diff --git a/src/assets/failStr7a_test.hjson b/assets/failStr7a_test.hjson similarity index 100% rename from src/assets/failStr7a_test.hjson rename to assets/failStr7a_test.hjson diff --git a/src/assets/failStr8a_test.hjson b/assets/failStr8a_test.hjson similarity index 100% rename from src/assets/failStr8a_test.hjson rename to assets/failStr8a_test.hjson diff --git a/src/assets/kan_result.hjson b/assets/kan_result.hjson similarity index 100% rename from src/assets/kan_result.hjson rename to assets/kan_result.hjson diff --git a/src/assets/kan_result.json b/assets/kan_result.json similarity index 100% rename from src/assets/kan_result.json rename to assets/kan_result.json diff --git a/src/assets/kan_test.hjson b/assets/kan_test.hjson similarity index 100% rename from src/assets/kan_test.hjson rename to assets/kan_test.hjson diff --git a/src/assets/keys_result.hjson b/assets/keys_result.hjson similarity index 100% rename from src/assets/keys_result.hjson rename to assets/keys_result.hjson diff --git a/src/assets/keys_result.json b/assets/keys_result.json similarity index 100% rename from src/assets/keys_result.json rename to assets/keys_result.json diff --git a/src/assets/keys_test.hjson b/assets/keys_test.hjson similarity index 100% rename from src/assets/keys_test.hjson rename to assets/keys_test.hjson diff --git a/src/assets/mltabs_result.hjson b/assets/mltabs_result.hjson similarity index 100% rename from src/assets/mltabs_result.hjson rename to assets/mltabs_result.hjson diff --git a/src/assets/mltabs_result.json b/assets/mltabs_result.json similarity index 100% rename from src/assets/mltabs_result.json rename to assets/mltabs_result.json diff --git a/src/assets/mltabs_test.json b/assets/mltabs_test.json similarity index 100% rename from src/assets/mltabs_test.json rename to assets/mltabs_test.json diff --git a/src/assets/oa_result.hjson b/assets/oa_result.hjson similarity index 100% rename from src/assets/oa_result.hjson rename to assets/oa_result.hjson diff --git a/src/assets/oa_result.json b/assets/oa_result.json similarity index 100% rename from src/assets/oa_result.json rename to assets/oa_result.json diff --git a/src/assets/oa_test.hjson b/assets/oa_test.hjson similarity index 100% rename from src/assets/oa_test.hjson rename to assets/oa_test.hjson diff --git a/src/assets/pass1_result.hjson b/assets/pass1_result.hjson similarity index 100% rename from src/assets/pass1_result.hjson rename to assets/pass1_result.hjson diff --git a/src/assets/pass1_result.json b/assets/pass1_result.json similarity index 100% rename from src/assets/pass1_result.json rename to assets/pass1_result.json diff --git a/src/assets/pass1_test.json b/assets/pass1_test.json similarity index 100% rename from src/assets/pass1_test.json rename to assets/pass1_test.json diff --git a/src/assets/pass2_result.hjson b/assets/pass2_result.hjson similarity index 100% rename from src/assets/pass2_result.hjson rename to assets/pass2_result.hjson diff --git a/src/assets/pass2_result.json b/assets/pass2_result.json similarity index 100% rename from src/assets/pass2_result.json rename to assets/pass2_result.json diff --git a/src/assets/pass2_test.json b/assets/pass2_test.json similarity index 100% rename from src/assets/pass2_test.json rename to assets/pass2_test.json diff --git a/src/assets/pass3_result.hjson b/assets/pass3_result.hjson similarity index 100% rename from src/assets/pass3_result.hjson rename to assets/pass3_result.hjson diff --git a/src/assets/pass3_result.json b/assets/pass3_result.json similarity index 100% rename from src/assets/pass3_result.json rename to assets/pass3_result.json diff --git a/src/assets/pass3_test.json b/assets/pass3_test.json similarity index 100% rename from src/assets/pass3_test.json rename to assets/pass3_test.json diff --git a/src/assets/pass4_result.hjson b/assets/pass4_result.hjson similarity index 100% rename from src/assets/pass4_result.hjson rename to assets/pass4_result.hjson diff --git a/src/assets/pass4_result.json b/assets/pass4_result.json similarity index 100% rename from src/assets/pass4_result.json rename to assets/pass4_result.json diff --git a/src/assets/pass4_test.json b/assets/pass4_test.json similarity index 100% rename from src/assets/pass4_test.json rename to assets/pass4_test.json diff --git a/src/assets/passSingle_result.hjson b/assets/passSingle_result.hjson similarity index 100% rename from src/assets/passSingle_result.hjson rename to assets/passSingle_result.hjson diff --git a/src/assets/passSingle_result.json b/assets/passSingle_result.json similarity index 100% rename from src/assets/passSingle_result.json rename to assets/passSingle_result.json diff --git a/src/assets/passSingle_test.hjson b/assets/passSingle_test.hjson similarity index 100% rename from src/assets/passSingle_test.hjson rename to assets/passSingle_test.hjson diff --git a/src/assets/rmcomments_result.hjson b/assets/rmcomments_result.hjson similarity index 100% rename from src/assets/rmcomments_result.hjson rename to assets/rmcomments_result.hjson diff --git a/src/assets/rmcomments_result.json b/assets/rmcomments_result.json similarity index 100% rename from src/assets/rmcomments_result.json rename to assets/rmcomments_result.json diff --git a/src/assets/rmcomments_test.hjson b/assets/rmcomments_test.hjson similarity index 100% rename from src/assets/rmcomments_test.hjson rename to assets/rmcomments_test.hjson diff --git a/src/assets/stringify1_result.hjson b/assets/stringify1_result.hjson similarity index 100% rename from src/assets/stringify1_result.hjson rename to assets/stringify1_result.hjson diff --git a/src/assets/stringify1_result.json b/assets/stringify1_result.json similarity index 100% rename from src/assets/stringify1_result.json rename to assets/stringify1_result.json diff --git a/src/assets/stringify1_test.hjson b/assets/stringify1_test.hjson similarity index 100% rename from src/assets/stringify1_test.hjson rename to assets/stringify1_test.hjson diff --git a/src/assets/strings2_result.hjson b/assets/strings2_result.hjson similarity index 100% rename from src/assets/strings2_result.hjson rename to assets/strings2_result.hjson diff --git a/src/assets/strings2_result.json b/assets/strings2_result.json similarity index 100% rename from src/assets/strings2_result.json rename to assets/strings2_result.json diff --git a/src/assets/strings2_test.hjson b/assets/strings2_test.hjson similarity index 100% rename from src/assets/strings2_test.hjson rename to assets/strings2_test.hjson diff --git a/src/assets/strings_result.hjson b/assets/strings_result.hjson similarity index 100% rename from src/assets/strings_result.hjson rename to assets/strings_result.hjson diff --git a/src/assets/strings_result.json b/assets/strings_result.json similarity index 100% rename from src/assets/strings_result.json rename to assets/strings_result.json diff --git a/src/assets/strings_test.hjson b/assets/strings_test.hjson similarity index 100% rename from src/assets/strings_test.hjson rename to assets/strings_test.hjson diff --git a/src/assets/testlist.txt b/assets/testlist.txt similarity index 100% rename from src/assets/testlist.txt rename to assets/testlist.txt diff --git a/src/assets/trail_result.hjson b/assets/trail_result.hjson similarity index 100% rename from src/assets/trail_result.hjson rename to assets/trail_result.hjson diff --git a/src/assets/trail_result.json b/assets/trail_result.json similarity index 100% rename from src/assets/trail_result.json rename to assets/trail_result.json diff --git a/src/assets/trail_test.hjson b/assets/trail_test.hjson similarity index 100% rename from src/assets/trail_test.hjson rename to assets/trail_test.hjson diff --git a/build.gradle b/build.gradle index 7813d86..979dd3e 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,14 @@ sourceSets { srcDir 'src/main' } } + test { + java { + srcDir 'src/test' + } + resources { + srcDir 'assets' + } + } } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -40,7 +48,7 @@ artifacts { } task(testSuite, dependsOn: ['classes','testClasses'], type: JavaExec) { - main = 'test.org.hjson.test.Main' + main = 'org.hjson.test.Main' classpath = files(sourceSets.main.runtimeClasspath, sourceSets.test.runtimeClasspath) } diff --git a/src/org/hjson/CommentStyle.java b/src/main/org/hjson/CommentStyle.java similarity index 100% rename from src/org/hjson/CommentStyle.java rename to src/main/org/hjson/CommentStyle.java diff --git a/src/org/hjson/CommentType.java b/src/main/org/hjson/CommentType.java similarity index 100% rename from src/org/hjson/CommentType.java rename to src/main/org/hjson/CommentType.java diff --git a/src/org/hjson/HjsonDsf.java b/src/main/org/hjson/HjsonDsf.java similarity index 100% rename from src/org/hjson/HjsonDsf.java rename to src/main/org/hjson/HjsonDsf.java diff --git a/src/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java similarity index 100% rename from src/org/hjson/HjsonOptions.java rename to src/main/org/hjson/HjsonOptions.java diff --git a/src/org/hjson/HjsonParser.java b/src/main/org/hjson/HjsonParser.java similarity index 100% rename from src/org/hjson/HjsonParser.java rename to src/main/org/hjson/HjsonParser.java diff --git a/src/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java similarity index 100% rename from src/org/hjson/HjsonWriter.java rename to src/main/org/hjson/HjsonWriter.java diff --git a/src/org/hjson/IHjsonDsfProvider.java b/src/main/org/hjson/IHjsonDsfProvider.java similarity index 100% rename from src/org/hjson/IHjsonDsfProvider.java rename to src/main/org/hjson/IHjsonDsfProvider.java diff --git a/src/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java similarity index 100% rename from src/org/hjson/JsonArray.java rename to src/main/org/hjson/JsonArray.java diff --git a/src/org/hjson/JsonDsf.java b/src/main/org/hjson/JsonDsf.java similarity index 100% rename from src/org/hjson/JsonDsf.java rename to src/main/org/hjson/JsonDsf.java diff --git a/src/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java similarity index 100% rename from src/org/hjson/JsonLiteral.java rename to src/main/org/hjson/JsonLiteral.java diff --git a/src/org/hjson/JsonNumber.java b/src/main/org/hjson/JsonNumber.java similarity index 100% rename from src/org/hjson/JsonNumber.java rename to src/main/org/hjson/JsonNumber.java diff --git a/src/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java similarity index 99% rename from src/org/hjson/JsonObject.java rename to src/main/org/hjson/JsonObject.java index 327976d..0e582aa 100644 --- a/src/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -132,7 +132,7 @@ public static JsonObject unmodifiableObject(JsonObject object) { * 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. + * @return whether the key exists. */ public boolean has(String name) { return indexOf(name)!=-1; diff --git a/src/org/hjson/JsonParser.java b/src/main/org/hjson/JsonParser.java similarity index 100% rename from src/org/hjson/JsonParser.java rename to src/main/org/hjson/JsonParser.java diff --git a/src/org/hjson/JsonString.java b/src/main/org/hjson/JsonString.java similarity index 100% rename from src/org/hjson/JsonString.java rename to src/main/org/hjson/JsonString.java diff --git a/src/org/hjson/JsonType.java b/src/main/org/hjson/JsonType.java similarity index 100% rename from src/org/hjson/JsonType.java rename to src/main/org/hjson/JsonType.java diff --git a/src/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java similarity index 99% rename from src/org/hjson/JsonValue.java rename to src/main/org/hjson/JsonValue.java index d008b43..1c64d4f 100644 --- a/src/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -266,6 +266,8 @@ public static JsonValue valueOfDsf(Object value) { /** * Returns a JsonValue from an Object of unknown type. + * + * @param value the value to get a JSON representation for * @return a new JsonValue. */ @SuppressWarnings("unchecked") diff --git a/src/org/hjson/JsonWriter.java b/src/main/org/hjson/JsonWriter.java similarity index 100% rename from src/org/hjson/JsonWriter.java rename to src/main/org/hjson/JsonWriter.java diff --git a/src/org/hjson/ParseException.java b/src/main/org/hjson/ParseException.java similarity index 100% rename from src/org/hjson/ParseException.java rename to src/main/org/hjson/ParseException.java diff --git a/src/org/hjson/Stringify.java b/src/main/org/hjson/Stringify.java similarity index 100% rename from src/org/hjson/Stringify.java rename to src/main/org/hjson/Stringify.java diff --git a/src/org/hjson/WritingBuffer.java b/src/main/org/hjson/WritingBuffer.java similarity index 100% rename from src/org/hjson/WritingBuffer.java rename to src/main/org/hjson/WritingBuffer.java diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index b8536d1..0e03917 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -1,4 +1,4 @@ -package test.org.hjson.test; +package org.hjson.test; import org.hjson.*; import java.io.*; @@ -20,7 +20,7 @@ public static String convertStreamToString(InputStream is) throws IOException { } private static String load(String file, boolean cr) throws Exception { - InputStream res=Main.class.getResourceAsStream("/assets/"+file); + InputStream res=Main.class.getResourceAsStream("/"+file); if (res==null) throw new Exception(file+" not found!"); String text=convertStreamToString(res); String std=text.replace("\r", ""); // make sure we have unix style text regardless of the input @@ -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 comments=name.startsWith("comments"); JsonValue.setEol(outputCr?"\r\n":"\n"); String text=load(file, inputCr); @@ -38,7 +39,7 @@ private static boolean test(String name, String file, boolean inputCr, boolean o try { HjsonOptions opt=new HjsonOptions(); opt.setParseLegacyRoot(false); - if (name.startsWith("comments")) { + if (comments) { opt.setOutputComments(true); } From 8ae93ad446cafd4aa7b69c1e96314d8229ad3b9e Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Mon, 22 Jun 2020 18:34:35 -0500 Subject: [PATCH 32/63] Update Version Number --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 979dd3e..c1dfdfd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0' +version = '3.0.0-C1' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 4ff07499a410acecc5cde3b89ff5705b07a1491b Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Sun, 2 Aug 2020 19:09:16 -0500 Subject: [PATCH 33/63] Fix legacy bug; new tests --- assets/legacy_result.hjson | 9 +++++++++ assets/legacy_result.json | 12 ++++++++++++ assets/legacy_test.hjson | 7 +++++++ assets/sameline_result.hjson | 11 +++++++++++ assets/sameline_result.json | 20 ++++++++++++++++++++ assets/sameline_test.hjson | 11 +++++++++++ assets/testlist.txt | 2 ++ src/main/org/hjson/HjsonParser.java | 10 ++++++---- src/main/org/hjson/JsonValue.java | 2 +- src/test/org/hjson/test/Main.java | 6 +++++- 10 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 assets/legacy_result.hjson create mode 100644 assets/legacy_result.json create mode 100644 assets/legacy_test.hjson create mode 100644 assets/sameline_result.hjson create mode 100644 assets/sameline_result.json create mode 100644 assets/sameline_test.hjson diff --git a/assets/legacy_result.hjson b/assets/legacy_result.hjson new file mode 100644 index 0000000..e5c55e8 --- /dev/null +++ b/assets/legacy_result.hjson @@ -0,0 +1,9 @@ +{ + num: 55 + dec: 55.5 + obj: + { + value: 55 + } + array: [ 55 ] +} \ No newline at end of file diff --git a/assets/legacy_result.json b/assets/legacy_result.json new file mode 100644 index 0000000..32ab595 --- /dev/null +++ b/assets/legacy_result.json @@ -0,0 +1,12 @@ +{ + "num": 55, + "dec": 55.5, + "obj": + { + "value": 55 + }, + "array": + [ + 55 + ] +} \ No newline at end of file diff --git a/assets/legacy_test.hjson b/assets/legacy_test.hjson new file mode 100644 index 0000000..79e91f2 --- /dev/null +++ b/assets/legacy_test.hjson @@ -0,0 +1,7 @@ +num: 55 +dec: 55.5 +obj: +{ + value: 55 +} +array: [ 55 ] \ No newline at end of file diff --git a/assets/sameline_result.hjson b/assets/sameline_result.hjson new file mode 100644 index 0000000..424a4e6 --- /dev/null +++ b/assets/sameline_result.hjson @@ -0,0 +1,11 @@ +{ + obj: { + inner: { "value": true } + } + array: [ + { + inner: [ 0, 80 ] + num: 33 + } + ] +} \ No newline at end of file diff --git a/assets/sameline_result.json b/assets/sameline_result.json new file mode 100644 index 0000000..c149357 --- /dev/null +++ b/assets/sameline_result.json @@ -0,0 +1,20 @@ +{ + "obj": + { + "inner": + { + "value": true + } + }, + "array": + [ + { + "inner": + [ + 0, + 80 + ], + "num": 33 + } + ] +} \ No newline at end of file diff --git a/assets/sameline_test.hjson b/assets/sameline_test.hjson new file mode 100644 index 0000000..424a4e6 --- /dev/null +++ b/assets/sameline_test.hjson @@ -0,0 +1,11 @@ +{ + obj: { + inner: { "value": true } + } + array: [ + { + inner: [ 0, 80 ] + num: 33 + } + ] +} \ No newline at end of file diff --git a/assets/testlist.txt b/assets/testlist.txt index 3da776e..445aaa9 100644 --- a/assets/testlist.txt +++ b/assets/testlist.txt @@ -65,6 +65,7 @@ failStr7a_test.hjson failStr8a_test.hjson kan_test.hjson keys_test.hjson +legacy_test.hjson mltabs_test.json oa_test.hjson pass1_test.json @@ -73,6 +74,7 @@ pass3_test.json pass4_test.json passSingle_test.hjson rmcomments_test.hjson +sameline_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 d76b21f..4329f84 100644 --- a/src/main/org/hjson/HjsonParser.java +++ b/src/main/org/hjson/HjsonParser.java @@ -172,7 +172,8 @@ private JsonObject readObject(boolean expectCloser) throws IOException { // Skip the opening brace. if (expectCloser) read(); JsonObject object=new JsonObject(); - ContainerData data=new ContainerData(isContainerCompact()); + boolean compact=isContainerCompact(expectCloser); + ContainerData data=new ContainerData(compact); while (true) { // Comment above / before name. @@ -209,7 +210,8 @@ private JsonObject readObject(boolean expectCloser) throws IOException { private JsonArray readArray() throws IOException { read(); // Clear the opening bracket. JsonArray array=new JsonArray(); - ContainerData data=new ContainerData(isContainerCompact()); + boolean compact=isContainerCompact(true); + ContainerData data=new ContainerData(compact); while (true) { // Any comments above / before value. @@ -281,14 +283,14 @@ private int readNextDelimiter() throws IOException { return -1; } - private boolean isContainerCompact() throws IOException { + private boolean isContainerCompact(boolean expectCloser) 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'; + return current!='\n' && expectCloser; } private String readName() throws IOException { diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 1c64d4f..d6fea3d 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -266,7 +266,7 @@ public static JsonValue valueOfDsf(Object value) { /** * Returns a JsonValue from an Object of unknown type. - * + * * @param value the value to get a JSON representation for * @return a new JsonValue. */ diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index 0e03917..65cb68e 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -32,20 +32,24 @@ private static boolean test(String name, String file, boolean inputCr, boolean o boolean isJson=extIdx>=0 && file.substring(extIdx).equals(".json"); boolean shouldFail=name.startsWith("fail"); boolean comments=name.startsWith("comments"); + boolean sameLine=name.startsWith("sameline"); JsonValue.setEol(outputCr?"\r\n":"\n"); String text=load(file, inputCr); try { HjsonOptions opt=new HjsonOptions(); - opt.setParseLegacyRoot(false); if (comments) { opt.setOutputComments(true); } + if (sameLine) { + opt.setBracesSameLine(true); + } JsonValue data=JsonValue.readHjson(text, opt); String data1=data.toString(Stringify.FORMATTED); String hjson1=data.toString(opt); + if (!shouldFail) { JsonValue result=JsonValue.readJSON(load(name+"_result.json", inputCr)); String data2=result.toString(Stringify.FORMATTED); From f5cde7a2c58fb8150c0e5272175ab8ffde5a5d8d Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Thu, 8 Jul 2021 18:15:29 -0500 Subject: [PATCH 34/63] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index c121847..a912e76 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +# PersonTheCat/hjson-java + +### Modified version of hjson-java which supports parsing and editing comments in code. + +Note that this repository is currently extremely experimental. I am planning a full rewrite from scratch in the coming months. +This will enable storing whitespace and other formatting info, additional data types, and some miscellaneous moderinizations +to the project to bring it up to spec with Java 8. + # hjson-java [![Build Status](https://img.shields.io/travis/hjson/hjson-java.svg?style=flat-square)](http://travis-ci.org/hjson/hjson-java) From 3f041f600a31ca05749ec1910fb48a1ed4de0f81 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Thu, 8 Jul 2021 21:39:58 -0500 Subject: [PATCH 35/63] Merge changes from Cave Generator --- assets/comments1_result.hjson | 4 +- assets/comments1_test.hjson | 4 +- assets/sameline_result.hjson | 4 +- assets/sameline_test.hjson | 4 +- src/main/org/hjson/HjsonDsf.java | 7 - src/main/org/hjson/HjsonOptions.java | 111 ++++++++++++--- src/main/org/hjson/HjsonParser.java | 141 ++++++++++--------- src/main/org/hjson/HjsonWriter.java | 137 ++++++++++-------- src/main/org/hjson/IHjsonDsfProvider.java | 11 +- src/main/org/hjson/JsonArray.java | 90 +++++++++++- src/main/org/hjson/JsonDsf.java | 1 - src/main/org/hjson/JsonLiteral.java | 4 +- src/main/org/hjson/JsonNumber.java | 3 +- src/main/org/hjson/JsonObject.java | 160 ++++++++++++++++++++-- src/main/org/hjson/JsonString.java | 2 +- src/main/org/hjson/JsonValue.java | 29 +++- src/main/org/hjson/JsonWriter.java | 2 +- src/test/org/hjson/test/Main.java | 5 +- 18 files changed, 531 insertions(+), 188 deletions(-) diff --git a/assets/comments1_result.hjson b/assets/comments1_result.hjson index 4d2efb1..bbf564e 100644 --- a/assets/comments1_result.hjson +++ b/assets/comments1_result.hjson @@ -55,8 +55,8 @@ # be correctly quoted, when necessary. multiLineObj: { - "value1": 1, "value2": 2 - "value3": "three", "value4": 4 + value1: 1, value2: 2 + value3: "three", value4: 4 } # Unnecessary quotes will be removed. unnecessaryQuotes: diff --git a/assets/comments1_test.hjson b/assets/comments1_test.hjson index 9a032b4..11d0447 100644 --- a/assets/comments1_test.hjson +++ b/assets/comments1_test.hjson @@ -55,8 +55,8 @@ # be correctly quoted, when necessary. multiLineObj: { - "value1": 1, "value2": 2 - "value3": "three", "value4": 4 + value1: 1, value2: 2 + value3: "three", value4: 4 } # Unnecessary quotes will be removed. unnecessaryQuotes: diff --git a/assets/sameline_result.hjson b/assets/sameline_result.hjson index 424a4e6..fdd0528 100644 --- a/assets/sameline_result.hjson +++ b/assets/sameline_result.hjson @@ -1,6 +1,6 @@ { obj: { - inner: { "value": true } + inner: { value: true } } array: [ { @@ -8,4 +8,4 @@ num: 33 } ] -} \ No newline at end of file +} diff --git a/assets/sameline_test.hjson b/assets/sameline_test.hjson index 424a4e6..fdd0528 100644 --- a/assets/sameline_test.hjson +++ b/assets/sameline_test.hjson @@ -1,6 +1,6 @@ { obj: { - inner: { "value": true } + inner: { value: true } } array: [ { @@ -8,4 +8,4 @@ num: 33 } ] -} \ No newline at end of file +} diff --git a/src/main/org/hjson/HjsonDsf.java b/src/main/org/hjson/HjsonDsf.java index 9c704ba..1885f6b 100644 --- a/src/main/org/hjson/HjsonDsf.java +++ b/src/main/org/hjson/HjsonDsf.java @@ -21,8 +21,6 @@ ******************************************************************************/ package org.hjson; -import java.util.*; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -44,11 +42,6 @@ private HjsonDsf() {} * @return DSF provider */ public static IHjsonDsfProvider hex(boolean stringify) { return new DsfHex(stringify); } - // /** - // * Returns a date DSF provider. - // * @return DSF provider - // */ - // public static IHjsonDsfProvider date() { return new DsfDate(); } static boolean isInvalidDsfChar(char c) { diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java index 052baf0..4b92415 100644 --- a/src/main/org/hjson/HjsonOptions.java +++ b/src/main/org/hjson/HjsonOptions.java @@ -28,6 +28,7 @@ public class HjsonOptions { private IHjsonDsfProvider[] dsf; private boolean outputComments; + private boolean outputEmptyLines; private boolean legacyRoot; private boolean bracesSameLine; private boolean allowCondense; @@ -45,6 +46,7 @@ public HjsonOptions() { space=" "; commentSpace=""; outputComments=false; + outputEmptyLines=false; } /** @@ -52,7 +54,9 @@ public HjsonOptions() { * * @return providers. */ - public IHjsonDsfProvider[] getDsfProviders() { return dsf.clone(); } + public IHjsonDsfProvider[] getDsfProviders() { + return dsf.clone(); + } /** * Sets the DSF providers. @@ -60,14 +64,19 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setDsfProviders(IHjsonDsfProvider... value) { dsf=value.clone(); return this; } + public HjsonOptions setDsfProviders(IHjsonDsfProvider... value) { + dsf = value.clone(); + return this; + } /** * Detects whether objects without root braces are supported. * * @return true if this feature is enabled. */ - public boolean getParseLegacyRoot() { return legacyRoot; } + public boolean getParseLegacyRoot() { + return legacyRoot; + } /** * Sets whether root braces should be emitted. @@ -75,14 +84,19 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setParseLegacyRoot(boolean value) { legacyRoot=value; return this; } + public HjsonOptions setParseLegacyRoot(boolean value) { + legacyRoot = value; + return this; + } /** * Detects whether root braces should be emitted. * * @return true if this feature is enabled. */ - public boolean getEmitRootBraces() { return emitRootBraces; } + public boolean getEmitRootBraces() { + return emitRootBraces; + } /** * Sets whether root braces should be emitted. @@ -90,7 +104,10 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setEmitRootBraces(boolean value) { emitRootBraces=value; return this; } + public HjsonOptions setEmitRootBraces(boolean value) { + emitRootBraces = value; + return this; + } /** * Detects whether braces and brackets should be placed on new lines. @@ -105,14 +122,19 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setBracesSameLine(boolean value) { bracesSameLine=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 getAllowMultiVal() { return allowMultiVal; } + public boolean getAllowMultiVal() { + return allowMultiVal; + } /** * Sets whether more than one value is ever allowed to be placed on a single line. @@ -120,14 +142,19 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setAllowMultiVal(boolean value) { allowMultiVal=value; return this; } + 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 getAllowCondense() { return allowCondense; } + public boolean getAllowCondense() { + return allowCondense; + } /** * Sets whether objects and arrays can be displayed on a single line. @@ -135,7 +162,10 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setAllowCondense(boolean value) { allowCondense=value; return this; } + public HjsonOptions setAllowCondense(boolean value) { + allowCondense = value; + return this; + } /** * Gets the characters to be placed per-level on each new line. @@ -150,7 +180,10 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setSpace(String value) { space=value; return this; } + public HjsonOptions setSpace(String value) { + space = value; + return this; + } /** * Sets the number of spaces to be placed per-level on each new line. @@ -158,14 +191,19 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setSpace(int value) { space=numSpaces(value); return this; } + public HjsonOptions setSpace(int value) { + space = numSpaces(value); + return this; + } /** * Gets the characters to be placed before comments on new lines. * * @return the number of spaces. */ - public String getCommentSpace() { return commentSpace; } + public String getCommentSpace() { + return commentSpace; + } /** * Sets the characters to be placed before comments on new lines. @@ -173,7 +211,10 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setCommentSpace(String value) { commentSpace=value; return this; } + public HjsonOptions setCommentSpace(String value) { + commentSpace = value; + return this; + } /** * Sets the number of spaces to be placed before comments on new lines. @@ -181,7 +222,10 @@ public HjsonOptions() { * @param value value * @return this, to enable chaining */ - public HjsonOptions setCommentSpace(int value) { commentSpace=numSpaces(value); return this; } + public HjsonOptions setCommentSpace(int value) { + commentSpace = numSpaces(value); + return this; + } /** * Generates a String object based on the input number of spaces. @@ -190,8 +234,10 @@ public HjsonOptions() { * @return a string containing the input number of spaces. */ private String numSpaces(int value) { - StringBuilder sb = new StringBuilder(); - for (int i=0; i=0 && space!=name.length()) { index=start+space; throw error("Found whitespace in your key name (use quotes to include)"); } return name.toString(); - } else if (isWhiteSpace(current)) { + } else if (isWhitespace(current)) { if (space<0) space=name.length(); } else if (current<' ') { throw error("Name is not closed"); @@ -324,7 +324,7 @@ private String readMlString() throws IOException { // skip white/to (newline) for (; ; ) { - if (isWhiteSpace(current) && current!='\n') read(); + if (isWhitespace(current) && current!='\n') read(); else break; } if (current=='\n') { read(); skipIndent(indent); } @@ -362,7 +362,7 @@ else if (current=='\'') { private void skipIndent(int indent) throws IOException { while (indent-->0) { - if (isWhiteSpace(current) && current!='\n') read(); + if (isWhitespace(current) && current!='\n') read(); else break; } } @@ -438,7 +438,7 @@ private static boolean isDigit(char ch) { return ch>='0' && ch<='9'; } - static JsonValue tryParseNumber(StringBuilder value, boolean stopAtNext) throws IOException { + static JsonValue tryParseNumber(StringBuilder value, boolean stopAtNext) { int idx=0, len=value.length(); if (idx0) - { + if (peek.length()>0) { // normally peek will only hold not more than one character so this should not matter for performance current=peek.charAt(0); peek.deleteCharAt(0); + } else { + current=reader.read(); } - else current=reader.read(); - if (current<0) return false; + 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) captureBuffer.deleteCharAt(len-1); - capture=false; + int len = captureBuffer.length(); + if (len > 0) { + captureBuffer.deleteCharAt(len - 1); + } + capture = false; } private String endCapture() { pauseCapture(); - String captured; - if (captureBuffer.length()>0) { - captured=captureBuffer.toString(); + final String captured; + if (captureBuffer.length() > 0) { + captured = captureBuffer.toString(); captureBuffer.setLength(0); } else { - captured=""; + captured = ""; } capture=false; return captured; @@ -627,41 +640,41 @@ private ParseException expected(String expected) { if (isEndOfText()) { return error("Unexpected end of input"); } - return error("Expected "+expected); + return error("Expected " + expected); } private ParseException error(String message) { - int column=index-lineOffset; - int offset=isEndOfText()?index:index-1; - return new ParseException(message, offset, line, column-1); + int column = index - lineOffset; + int offset = isEndOfText() ? index : index - 1; + return new ParseException(message, offset, line, column - 1); } - static boolean isWhiteSpace(int ch) { - return ch==' ' || ch=='\t' || ch=='\n' || ch=='\r'; + static boolean isWhitespace(int ch) { + return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; } - private boolean isWhiteSpace() { - return isWhiteSpace((char)current); + private boolean isWhitespace() { + return isWhitespace((char)current); } private boolean isHexDigit() { - return current>='0' && current<='9' - || current>='a' && current<='f' - || current>='A' && current<='F'; + return current >= '0' && current <= '9' + || current >= 'a' && current <= 'f' + || current >= 'A' && current <= 'F'; } private boolean isEndOfText() { - return current==-1; + return current == -1; } private static class ContainerData { - private int lineLength=1; - private int sumLineLength=0; - private int numLines=0; + private int lineLength = 1; + private int sumLineLength = 0; + private int numLines = 0; private boolean condensed; private ContainerData(boolean condensed) { - this.condensed=condensed; + this.condensed = condensed; } private void incrLineLength() { @@ -679,25 +692,27 @@ private void nl() { } private int finalLineLength(int size) { - return sumLineLength>0 ? avgLineLength() : condensed ? size : 1; + return sumLineLength > 0 ? avgLineLength() : condensed ? size : 1; } private int avgLineLength() { int avgLineLength=sumLineLength/numLines; - if (avgLineLength<=0) avgLineLength=1; + if (avgLineLength<=0) { + avgLineLength=1; + } return 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 70e8f8f..a009a23 100644 --- a/src/main/org/hjson/HjsonWriter.java +++ b/src/main/org/hjson/HjsonWriter.java @@ -1,4 +1,5 @@ -/******************************************************************************* +/* + ****************************************************************************** * Copyright (c) 2015-2017 Christian Zangl * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,15 +28,17 @@ class HjsonWriter { - private IHjsonDsfProvider[] dsfProviders; - private boolean outputComments; - private boolean bracesSameLine; - private boolean allowCondense; - private boolean allowMultiVal; - private boolean emitRootBraces; - private String space, commentSpace; + private final IHjsonDsfProvider[] dsfProviders; + private final boolean outputComments; + private final boolean outputEmptyLines; + private final boolean bracesSameLine; + private final boolean allowCondense; + private final boolean allowMultiVal; + private final boolean emitRootBraces; + private final String space; + private final String commentSpace; - static Pattern needsEscapeName=Pattern.compile("[,\\{\\[\\}\\]\\s:#\"']|//|/\\*"); + private static final Pattern NEEDS_ESCAPE_NAME = Pattern.compile("[,{\\[}\\]\\s:#\"']|//|/\\*"); public HjsonWriter(HjsonOptions options) { if (options!=null) { @@ -46,6 +49,7 @@ public HjsonWriter(HjsonOptions options) { space=options.getSpace(); commentSpace=options.getCommentSpace(); outputComments=options.getOutputComments(); + outputEmptyLines=options.getOutputEmptyLines(); emitRootBraces=options.getEmitRootBraces(); } else { dsfProviders=new IHjsonDsfProvider[0]; @@ -56,26 +60,25 @@ public HjsonWriter(HjsonOptions options) { space=" "; commentSpace=""; outputComments=false; + outputEmptyLines=false; } } public HjsonWriter(HjsonOptions options, boolean outputComments) { - this(options); - - this.outputComments = outputComments; + this((options==null?new HjsonOptions():options).setOutputComments(outputComments)); } - void nl(Writer tw, int level) throws IOException { + private void nl(Writer tw, int level) throws IOException { tw.write(JsonValue.eol); indent(tw, level); } - void indent(Writer tw, int level) throws IOException { + private void indent(Writer tw, int level) throws IOException { for (int i=0; i0) { + private void closeContainer(Writer tw, boolean forceNl, boolean compact, int size, int level, char closeWith) throws IOException { + if (forceNl) { + nl(tw, level); + } else if (size>0) { if (compact && allowCondense && allowMultiVal) tw.write(' '); else nl(tw, level); } tw.write(closeWith); } - static String escapeName(String name) { - return escapeName(name, false); - } - - static String escapeName(String name, boolean force) { - if (force || name.length()==0 || needsEscapeName.matcher(name).find()) + private static String escapeName(String name) { + if (name.length()==0 || NEEDS_ESCAPE_NAME.matcher(name).find()) return "\""+JsonWriter.escapeString(name)+"\""; else return name; } - void writeString(String value, Writer tw, int level, boolean forceQuotes, String separator) throws IOException { + private void writeString(String value, Writer tw, int level, boolean forceQuotes) throws IOException { 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'; + char left1=value.length()>1?value.charAt(1):'\0'; boolean doEscape=false; char[] valuec=value.toCharArray(); for(char ch : valuec) { @@ -268,7 +291,7 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String } if (doEscape || - HjsonParser.isWhiteSpace(left) || HjsonParser.isWhiteSpace(right) || + HjsonParser.isWhitespace(left) || HjsonParser.isWhitespace(right) || left=='"' || left=='\'' || left=='#' || @@ -290,7 +313,7 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String boolean noEscapeML=true, allWhite=true; for(char ch : valuec) { if (needsEscapeML(ch)) { noEscapeML=false; break; } - else if (!HjsonParser.isWhiteSpace(ch)) allWhite=false; + else if (!HjsonParser.isWhitespace(ch)) allWhite=false; } if (noEscapeML && !allWhite && !value.contains("'''")) writeMLString(value, tw, level); else tw.write("\""+JsonWriter.escapeString(value)+"\""); @@ -302,7 +325,7 @@ void writeString(String value, Writer tw, int level, boolean forceQuotes, String } } - void writeMLString(String value, Writer tw, int level) throws IOException { + private void writeMLString(String value, Writer tw, int level) throws IOException { String[] lines=value.replace("\r", "").split("\n", -1); if (lines.length==1) { @@ -324,7 +347,7 @@ void writeMLString(String value, Writer tw, int level) throws IOException { } } - void writeComment(String comment, Writer tw, int level) throws IOException { + private 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); @@ -338,31 +361,27 @@ void writeComment(String comment, Writer tw, int level) throws IOException { } } - static boolean startsWithKeyword(String text) { + private static boolean startsWithKeyword(String text) { int p; if (text.startsWith("true") || text.startsWith("null")) p=4; else if (text.startsWith("false")) p=5; else return false; - while (pp+1 && (text.charAt(p+1)=='/' || text.charAt(p+1)=='*')); } - static boolean forceQuoteArray(JsonValue value, JsonArray array, boolean outputComments) { + private 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, boolean outputComments) { + private 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) { - return object.isCondensed() || object.getLineLength()>1; - } - - static boolean needsQuotes(char c) { + private static boolean needsQuotes(char c) { switch (c) { case '\t': case '\f': @@ -375,7 +394,7 @@ static boolean needsQuotes(char c) { } } - static boolean needsEscape(char c) { + private static boolean needsEscape(char c) { switch (c) { case '\"': case '\\': @@ -385,7 +404,7 @@ static boolean needsEscape(char c) { } } - static boolean needsEscapeML(char c) { + private static boolean needsEscapeML(char c) { switch (c) { case '\n': case '\r': diff --git a/src/main/org/hjson/IHjsonDsfProvider.java b/src/main/org/hjson/IHjsonDsfProvider.java index 620bd87..1f7b818 100644 --- a/src/main/org/hjson/IHjsonDsfProvider.java +++ b/src/main/org/hjson/IHjsonDsfProvider.java @@ -31,25 +31,28 @@ public interface IHjsonDsfProvider * * @return name */ - public String getName(); + String getName(); + /** * Gets the description of this DSF. * * @return description */ - public String getDescription(); + String getDescription(); + /** * Tries to parse the text as a DSF value. * * @param text the DSF value * @return JsonValue */ - public JsonValue parse(String text); + JsonValue parse(String text); + /** * Stringifies DSF values. * * @param value the JSON value * @return string */ - public String stringify(JsonValue value); + String stringify(JsonValue value); } diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 2e819aa..985a620 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -27,7 +27,6 @@ import java.util.Iterator; import java.util.List; - /** * Represents a JSON array, an ordered collection of JSON values. *

@@ -59,7 +58,6 @@ * This class is not supposed to be extended by clients. *

*/ -@SuppressWarnings("serial") // use default serial UID public class JsonArray extends JsonValue implements Iterable { @@ -616,6 +614,25 @@ public JsonArray setComment(int index, CommentType type, CommentStyle style, Str return this; } + /** + * Marks every value in this array as being accessed or not accessed. + * + * @param b + * whether to mark each field as accessed. + * @return the array itself, to enable chaining. + */ + public JsonArray setAllAccessed(boolean b) { + for (JsonValue value : this) { + value.setAccessed(b); + if (value.isObject()) { + value.asObject().setAllAccessed(b); + } else if (value.isArray()) { + value.asArray().setAllAccessed(b); + } + } + return this; + } + /** * Removes the element at the specified index from this array. * @@ -649,6 +666,31 @@ public boolean isEmpty() { return values.isEmpty(); } + /** + * Clears every element from this array. + * + * @throws UnsupportedOperationException if this object is unmodifiable. + * @return the array itself, to enable method chaining + */ + public JsonArray clear() { + values.clear(); + return this; + } + + /** + * Adds every value from another array. + * + * @throws UnsupportedOperationException if this object is unmodifiable. + * @param array The array to copy values from. + * @return the array itself, to enable method chaining + */ + public JsonArray addAll(JsonArray array) { + for (JsonValue value : array) { + add(value); + } + return this; + } + /** * Returns the value of the element at the specified position in this array. * @@ -663,6 +705,28 @@ public JsonValue get(int index) { return values.get(index).setAccessed(true); } + /** + * Returns whether this array contains a value. + * + * @param value The value to search for. + * @return true if this array contains the value. + */ + public boolean contains(JsonValue value) { + return values.contains(value); + } + + /** + * Returns whether this array contains a value of unknown type. + * + * Todo: implement concrete functions for other known types. + * + * @param value The value to search for. + * @return true if this array contains the value. + */ + public boolean contains(Object value) { + return contains(JsonValue.valueOf(value)); + } + /** * Returns a list of the values in this array in document order. The returned list is backed by * this array and will reflect subsequent changes. It cannot be used to modify this array. @@ -715,11 +779,29 @@ public List values() { * @return the list of unused paths. */ public List getUnusedPaths() { - List paths=new ArrayList(); + return this.getUsedPaths(false); + } + + /** + * Generates a list of paths that have been accessed in-code. + * @return the list of unused paths. + */ + public List getUsedPaths() { + return this.getUsedPaths(true); + } + + /** + * Generates a list of paths that either have or have not been accessed in-code. + * + * @param used whether the value should have been accessed. + * @return the list of unused paths. + */ + public List getUsedPaths(boolean used) { + final List paths=new ArrayList<>(); int index=0; for (JsonValue v : this) { if (v.isObject()) { - for (String s : v.asObject().getUnusedPaths()) { + for (String s : v.asObject().getUsedPaths(used)) { paths.add("["+index+"]."+s); } } diff --git a/src/main/org/hjson/JsonDsf.java b/src/main/org/hjson/JsonDsf.java index 8e9c8c3..d62e109 100644 --- a/src/main/org/hjson/JsonDsf.java +++ b/src/main/org/hjson/JsonDsf.java @@ -21,7 +21,6 @@ ******************************************************************************/ package org.hjson; -@SuppressWarnings("serial") // use default serial UID class JsonDsf extends JsonValue { private final Object value; diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java index e391a47..4901747 100644 --- a/src/main/org/hjson/JsonLiteral.java +++ b/src/main/org/hjson/JsonLiteral.java @@ -22,8 +22,6 @@ ******************************************************************************/ package org.hjson; - -@SuppressWarnings("serial") // use default serial UID class JsonLiteral extends JsonValue { enum Iv { T, F, N }; @@ -58,7 +56,7 @@ public static JsonLiteral jsonFalse() { @Override public int hashCode() { - return value.hashCode(); + return super.hashCode() * 59 + value.hashCode(); } @Override diff --git a/src/main/org/hjson/JsonNumber.java b/src/main/org/hjson/JsonNumber.java index 46844a5..4bb60c1 100644 --- a/src/main/org/hjson/JsonNumber.java +++ b/src/main/org/hjson/JsonNumber.java @@ -24,7 +24,6 @@ import java.math.BigDecimal; -@SuppressWarnings("serial") // use default serial UID class JsonNumber extends JsonValue { private final double value; @@ -78,7 +77,7 @@ public double asDouble() { @Override public int hashCode() { - return Double.valueOf(value).hashCode(); + return super.hashCode() * 59 + Double.valueOf(value).hashCode(); } @Override diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 0e582aa..28f628e 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -128,6 +128,15 @@ public static JsonObject unmodifiableObject(JsonObject object) { return new JsonObject(object, true); } + /** + * Returns the list of keys contained within this object. + * + * @return the every name defined in the object. + */ + public List getNames() { + return names; + } + /** * Returns whether the input key is contained within this object. * @@ -410,11 +419,68 @@ public JsonObject add(String name, JsonValue value) { * @return the object itself, to enable method chaining */ public JsonObject add(String name, JsonValue value, String comment) { + if (comment==null) { + throw new NullPointerException("comment is null"); + } + value.setComment(comment); + return add(name, value); + } + + /** + * Variant of {@link #add(String, JsonValue)} which will insert a value at a particular position. + * + * Todo: decide whether to keep this before merging with hjson-java. + * + * @param index + * the index where this value will be placed + * @param name + * the name of the member to add + * @param value + * the value of the member to add + * @return the object itself, to enable method chaining + */ + public JsonObject insert(int index, String name, JsonValue value) { + if (name==null) { + throw new NullPointerException("name is null"); + } if (value==null) { throw new NullPointerException("value is null"); } + // Collect all current members into an array; + final List members=new ArrayList<>(); + for (Member m : this) { + members.add(m); + } + members.add(index, new Member(name, value)); + // Reset everything. + clear(); + // Re-add the values, now in the correct order. + for (Member m : members) { + add(m.name, m.value); + } + return this; + } + + /** + * Variant of {@link #insert(int, String, JsonValue)} which includes a comment. + * + * @param index + * the index where this value will be placed + * @param name + * the name of the member to add + * @param value + * the value of the member to add + * @param comment + * the comment to set on the value. + * @return the object itself, to enable method chaining + */ + public JsonObject insert(int index, String name, JsonValue value, String comment) { + if (comment==null) { + throw new NullPointerException("comment is null"); + } value.setComment(comment); - return add(name, value); + insert(index, name, value); + return this; } /** @@ -700,7 +766,7 @@ public JsonObject set(String name, JsonValue value, String comment) { * 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. + * @return the object itself, to enable chaining. */ public JsonObject setComment(String name, String comment) { get(name).setComment(comment); @@ -719,13 +785,33 @@ public JsonObject setComment(String name, String comment) { * 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. + * @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; } + /** + * Marks every value in this object as being accessed or not accessed. + * + * @param b + * whether to mark each field as accessed. + * @return the object itself, to enable chaining. + */ + public JsonObject setAllAccessed(boolean b) { + for (Member m : this) { + final JsonValue value=m.value; + value.setAccessed(b); + if (value.isObject()) { + value.asObject().setAllAccessed(b); + } else if (value.isArray()) { + value.asArray().setAllAccessed(b); + } + } + 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 @@ -896,6 +982,37 @@ public boolean isEmpty() { return names.isEmpty(); } + /** + * Clears every element from this object. + * + * @throws UnsupportedOperationException if this object is unmodifiable. + * @return the object itself, to enable method chaining + */ + public JsonObject clear() { + names.clear(); + values.clear(); + table.clear(); + return this; + } + + /** + * Adds every member (key/value pair) from another object. + * + * @throws UnsupportedOperationException if this object is unmodifiable. + * @param object The object to copy values from. + * @return the object itself, to enable method chaining + */ + public JsonObject addAll(JsonObject object) { + for (Member m : object) { + if (has(m.getName())) { + set(m.getName(), m.getValue()); + } else { + add(m.getName(), m.getValue()); + } + } + return this; + } + /** * Returns a list of the names in this object in document order. The returned list is backed by * this object and will reflect subsequent changes. It cannot be used to modify this object. @@ -948,17 +1065,35 @@ public List names() { * @return the list of unused paths. */ public List getUnusedPaths() { - List paths=new ArrayList(); + return this.getUsedPaths(false); + } + + /** + * Generates a list of paths that have been accessed in-code. + * @return the list of used paths. + */ + public List getUsedPaths() { + return this.getUsedPaths(true); + } + + /** + * Generates a list of paths that either have or have not been accessed in-code. + * + * @param used whether the path should have been accessed. + * @return the list of used paths. + */ + public List getUsedPaths(boolean used) { + final List paths=new ArrayList(); for (Member m : this) { - if (!m.value.isAccessed()) { + if (used == m.value.isAccessed()) { paths.add(m.name); } //else {paths.add("*"+m.name);} if (m.value.isObject()) { - for (String s : m.value.asObject().getUnusedPaths()) { + for (String s : m.value.asObject().getUsedPaths(used)) { paths.add(m.name+"."+s); } } else if (m.value.isArray()) { - for (String s : m.value.asArray().getUnusedPaths()) { + for (String s : m.value.asArray().getUsedPaths(used)) { paths.add(m.name+s); } } @@ -973,19 +1108,18 @@ public List getUnusedPaths() { */ 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()]); + Member[] membersArray=members.toArray(new Member[0]); // Sort the new array. Arrays.sort(membersArray, new MemberComparator()); // Clear the original values. - names.clear(); - values.clear(); + clear(); // Re-add the values, now in order. for (Member m : membersArray) { @@ -1180,6 +1314,10 @@ int get(Object name) { private int hashSlotfor (Object element) { return element.hashCode() & hashTable.length-1; } + + private void clear() { + Arrays.fill(hashTable, (byte) 0); + } } public static class MemberComparator implements Comparator { diff --git a/src/main/org/hjson/JsonString.java b/src/main/org/hjson/JsonString.java index 678c1e0..df2cfe2 100644 --- a/src/main/org/hjson/JsonString.java +++ b/src/main/org/hjson/JsonString.java @@ -51,7 +51,7 @@ public String asString() { @Override public int hashCode() { - return string.hashCode(); + return super.hashCode() * 59 + string.hashCode(); } @Override diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index d6fea3d..91b95fa 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -72,7 +72,12 @@ public abstract class JsonValue implements Serializable { /** * A flag indicating whether this value has been specifically called for. */ - protected boolean accessed; + protected boolean accessed=false; + + /** + * Indicates the number of empty lines above this value. + */ + protected int numLines=0; /** * Gets the newline charater(s). @@ -82,7 +87,7 @@ public abstract class JsonValue implements Serializable { public static String getEol() { return eol; } /** - * Sets the newline charater(s). + * Sets the newline character(s). * * @param value the eol value */ @@ -396,6 +401,20 @@ public JsonValue setAccessed(boolean b) { return this; } + /** + * Detects the number of empty lines before this value. + * + * @return the number of empty lines + */ + public int getNumLines() { + return numLines; + } + + public JsonValue setNumLines(int num) { + numLines=num; + return this; + } + /** * Detects whether this value contains any comments. * @@ -778,7 +797,11 @@ public boolean equals(Object object) { @Override public int hashCode() { - return super.hashCode(); + int result = 1; + result *= 59 + (this.bolComment == null ? 43 : this.bolComment.hashCode()); + result *= 59 + (this.eolComment == null ? 43 : this.eolComment.hashCode()); + result *= 59 + (this.intComment == null ? 43 : this.intComment.hashCode()); + return result; } static boolean isPunctuatorChar(int c) { diff --git a/src/main/org/hjson/JsonWriter.java b/src/main/org/hjson/JsonWriter.java index 8d73c7f..ebf58fa 100644 --- a/src/main/org/hjson/JsonWriter.java +++ b/src/main/org/hjson/JsonWriter.java @@ -98,7 +98,7 @@ public void save(JsonValue value, Writer tw, int level) throws IOException { static String escapeName(String name) { boolean needsEscape=name.length()==0; for(char ch : name.toCharArray()) { - if (HjsonParser.isWhiteSpace(ch) || ch=='{' || ch=='}' || ch=='[' || ch==']' || ch==',' || ch==':') { + if (HjsonParser.isWhitespace(ch) || ch=='{' || ch=='}' || ch=='[' || ch==']' || ch==',' || ch==':') { needsEscape=true; break; } diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index 65cb68e..7a3971b 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -2,6 +2,8 @@ import org.hjson.*; import java.io.*; +import java.nio.charset.StandardCharsets; + import static java.lang.System.out; public class Main { @@ -10,7 +12,7 @@ public static String convertStreamToString(InputStream is) throws IOException { Writer writer=new StringWriter(); char[] buffer=new char[1024]; try { - Reader reader=new BufferedReader(new InputStreamReader(is, "UTF-8")); + Reader reader=new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); int n; while ((n=reader.read(buffer))!=-1) writer.write(buffer, 0, n); } finally { @@ -24,6 +26,7 @@ private static String load(String file, boolean cr) throws Exception { if (res==null) throw new Exception(file+" not found!"); String text=convertStreamToString(res); String std=text.replace("\r", ""); // make sure we have unix style text regardless of the input + if (std.endsWith("\n")) std=std.substring(0, std.length()-1); // clip off empty lines at the end of the input return cr ? std.replace("\n", "\r\n") : std; } From 04d7dd8fc1699b2bb08fb116c47733be884e2e4c Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Wed, 25 Aug 2021 08:12:38 -0500 Subject: [PATCH 36/63] Safer new line configuration --- build.gradle | 2 +- src/main/org/hjson/HjsonOptions.java | 24 +++++++++++++++++++++++- src/main/org/hjson/HjsonWriter.java | 5 ++++- src/main/org/hjson/JsonValue.java | 5 ++++- src/main/org/hjson/JsonWriter.java | 2 +- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index c1dfdfd..3a969cf 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C1' +version = '3.0.0-C2' group = 'org.hjson' description = """Hjson, the Human JSON.""" diff --git a/src/main/org/hjson/HjsonOptions.java b/src/main/org/hjson/HjsonOptions.java index 4b92415..a1e74a3 100644 --- a/src/main/org/hjson/HjsonOptions.java +++ b/src/main/org/hjson/HjsonOptions.java @@ -35,6 +35,7 @@ public class HjsonOptions { private boolean allowMultiVal; private boolean emitRootBraces; private String space, commentSpace; + private String newLine; public HjsonOptions() { dsf=new IHjsonDsfProvider[0]; @@ -47,6 +48,7 @@ public HjsonOptions() { commentSpace=""; outputComments=false; outputEmptyLines=false; + newLine=JsonValue.eol; } /** @@ -199,7 +201,7 @@ public HjsonOptions setSpace(int value) { /** * Gets the characters to be placed before comments on new lines. * - * @return the number of spaces. + * @return the number of spaces */ public String getCommentSpace() { return commentSpace; @@ -216,6 +218,26 @@ public HjsonOptions setCommentSpace(String value) { return this; } + /** + * Gets the new line character(s) to be output by the writer. + * + * @return the new line character(s) + */ + public String getNewLine() { + return this.newLine; + } + + /** + * Sets the new line character(s) to be output by the writer. + * + * @param nl The new line characters to be used + * @return this, to enable chaining + */ + public HjsonOptions setNewLine(String nl) { + if ("\n".equals(nl) || "\r\n".equals(nl)) newLine = nl; + return this; + } + /** * Sets the number of spaces to be placed before comments on new lines. * diff --git a/src/main/org/hjson/HjsonWriter.java b/src/main/org/hjson/HjsonWriter.java index a009a23..3acca28 100644 --- a/src/main/org/hjson/HjsonWriter.java +++ b/src/main/org/hjson/HjsonWriter.java @@ -37,6 +37,7 @@ class HjsonWriter { private final boolean emitRootBraces; private final String space; private final String commentSpace; + private final String eol; private static final Pattern NEEDS_ESCAPE_NAME = Pattern.compile("[,{\\[}\\]\\s:#\"']|//|/\\*"); @@ -51,6 +52,7 @@ public HjsonWriter(HjsonOptions options) { outputComments=options.getOutputComments(); outputEmptyLines=options.getOutputEmptyLines(); emitRootBraces=options.getEmitRootBraces(); + eol=options.getNewLine(); } else { dsfProviders=new IHjsonDsfProvider[0]; bracesSameLine=false; @@ -61,6 +63,7 @@ public HjsonWriter(HjsonOptions options) { commentSpace=""; outputComments=false; outputEmptyLines=false; + eol=JsonValue.eol; } } @@ -69,7 +72,7 @@ public HjsonWriter(HjsonOptions options, boolean outputComments) { } private void nl(Writer tw, int level) throws IOException { - tw.write(JsonValue.eol); + tw.write(this.eol); indent(tw, level); } diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 91b95fa..0158a31 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -80,17 +80,20 @@ public abstract class JsonValue implements Serializable { protected int numLines=0; /** - * Gets the newline charater(s). + * Gets the newline character(s). * * @return the eol value */ + @Deprecated public static String getEol() { return eol; } /** * Sets the newline character(s). * + * @deprecated Use {@link HjsonOptions#setNewLine} * @param value the eol value */ + @Deprecated public static void setEol(String value) { if (value.equals("\r\n") || value.equals("\n")) eol=value; } diff --git a/src/main/org/hjson/JsonWriter.java b/src/main/org/hjson/JsonWriter.java index ebf58fa..a672e35 100644 --- a/src/main/org/hjson/JsonWriter.java +++ b/src/main/org/hjson/JsonWriter.java @@ -46,7 +46,7 @@ public void save(JsonValue value, Writer tw, int level) throws IOException { switch (value.getType()) { case OBJECT: JsonObject obj=value.asObject(); - if (obj.size()>0) nl(tw, level); + if (obj.size()>0 && level>0) nl(tw, level); tw.write('{'); for (JsonObject.Member pair : obj) { if (following) tw.write(","); From 5356d7f6c353ab40cac2ad7cd2c739a4d4c3e8ab Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Wed, 25 Aug 2021 08:14:13 -0500 Subject: [PATCH 37/63] Bump version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3a969cf..2d78c66 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C2' +version = '3.0.0-C3' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 6368ec32485f4b7b82f19bb47f73ecba5877121e Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Tue, 5 Oct 2021 11:28:10 -0500 Subject: [PATCH 38/63] Better raw conversions --- build.gradle | 2 +- src/main/org/hjson/JsonArray.java | 3 ++- src/main/org/hjson/JsonObject.java | 14 ++++++++++++++ src/main/org/hjson/JsonValue.java | 20 ++++++++++++++++---- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 2d78c66..9add7f8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C3' +version = '3.0.0-C4' group = 'org.hjson' description = """Hjson, the Human JSON.""" diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 985a620..6f5e898 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -114,8 +114,9 @@ public static JsonArray unmodifiableArray(JsonArray array) { } /** - * Unsafe. Returns a raw list of the objects contained within this array. For compatibiliity with + * Unsafe. Returns a raw list of the values contained within this array. For compatibility with * other config wrappers. + * * @return the array as a list of raw objects. */ public List asRawList() { diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 28f628e..7d69580 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -128,6 +128,20 @@ public static JsonObject unmodifiableObject(JsonObject object) { return new JsonObject(object, true); } + /** + * Unsafe. Returns a raw map of the values contained within this object. For compatibility with + * other config wrappers. + * + * @return the object as a map of string -> raw object. + */ + public Map asRawMap() { + final Map map=new HashMap<>(); + for (final Member member : this) { + map.put(member.name, member.value.asRaw()); + } + return map; + } + /** * Returns the list of keys contained within this object. * diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 0158a31..cc5d42b 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -27,6 +27,7 @@ import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; +import java.lang.reflect.Array; import java.util.List; import java.util.Map; import java.util.Set; @@ -278,14 +279,18 @@ public static JsonValue valueOfDsf(Object value) { * @param value the value to get a JSON representation for * @return a new JsonValue. */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) public static JsonValue valueOf(Object value) { - if (value instanceof Number) { + if (value==null) { + return JsonLiteral.jsonNull(); + } else if (value instanceof Number) { return new JsonNumber(((Number) value).doubleValue()); } else if (value instanceof String) { return new JsonString((String) value); } else if (value instanceof Boolean) { return (Boolean) value ? JsonLiteral.jsonTrue() : JsonLiteral.jsonFalse(); + } else if (value instanceof Enum) { + return new JsonString(((Enum) value).name()); } else if (value instanceof List) { JsonArray array=new JsonArray(); for (Object o : (List) value) { @@ -293,12 +298,19 @@ public static JsonValue valueOf(Object value) { } return array; } else if (value instanceof Map) { - Set entries=((Map)value).entrySet(); JsonObject object=new JsonObject(); + Set entries=((Map)value).entrySet(); for (Map.Entry entry : entries) { object.set(entry.getKey().toString(), valueOf(entry.getValue())); } return object; + } else if (value.getClass().isArray()) { + JsonArray array=new JsonArray(); + int length=Array.getLength(value); + for (int i=0; i T asRaw() { switch (getType()) { case STRING : return (T) asString(); case NUMBER : return (T) Double.valueOf(asDouble()); - case OBJECT : return (T) asObject(); + case OBJECT : return (T) asObject().asRawMap(); case ARRAY : return (T) asArray().asRawList(); case BOOLEAN : return (T) Boolean.valueOf(asBoolean()); case DSF : return (T) asDsf(); From 58abb6683692884d075e25d49ec9525c4d267f0e Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sat, 13 Nov 2021 15:44:43 -0600 Subject: [PATCH 39/63] JsonValue#copyComments and JsonValue#clearComments --- src/main/org/hjson/JsonValue.java | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index cc5d42b..a6a9c1f 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -558,6 +558,34 @@ public JsonValue setFullComment(CommentType type, String comment) { return this; } + /** + * Copies every comment from another JSON value into this value. The input value be null, but + * will simply be ignored, if so. + * + * @param value The JSON value being copied out of. + * @return this, to enable chaining + */ + public JsonValue copyComments(JsonValue value) { + if (value!=null) { + this.bolComment=value.bolComment; + this.eolComment=value.eolComment; + this.intComment=value.intComment; + } + return this; + } + + /** + * Removes every comment from this JSON value. + * + * @return this, to enable chaining. + */ + public JsonValue clearComments() { + this.bolComment=""; + this.eolComment=""; + this.intComment=""; + 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 1bc0294d6b9a163308efd8016a46c8e5100e4243 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sat, 13 Nov 2021 15:48:30 -0600 Subject: [PATCH 40/63] Bump version to C5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9add7f8..8972aa3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C4' +version = '3.0.0-C5' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 465fe445c14e58dcaf1e43a97007a19a6e728340 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 16:03:38 -0600 Subject: [PATCH 41/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8972aa3..7ad0d65 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C5' +version = '3.0.0-C6' group = 'org.hjson' description = """Hjson, the Human JSON.""" From e4f7489dcd66bed88347f252f5ac31042986cc8a Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 16:16:32 -0600 Subject: [PATCH 42/63] Expose indexOf and get by index --- src/main/org/hjson/JsonObject.java | 39 ++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 7d69580..6fb07c7 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -978,6 +978,22 @@ public String getString(String name, String defaultValue) { return value!=null ? value.asString() : defaultValue; } + /** + * Returns the value of the member with the specified index in this object. + * + *

Note that this method is intended for reflecting on data in the object without semantically + * "consuming" it. For this reason, it does not implicitly flag the returned value as used.

+ * + * @param index + * the index of the member whose value is to be returned + * @return the value of the last member with the specified index, or null if this + * object does not contain a member with that index + * @throws ArrayIndexOutOfBoundsException if the given index does not exist. + */ + public JsonValue get(int index) { + return values.get(index); + } + /** * Returns the number of members (name/value pairs) in this object. * @@ -1143,6 +1159,21 @@ public JsonObject sort() { return this; } + /** + * Returns the index of the member with the given name. If this object contains multiple members + * with the same name, the last member will be returned. + * + * @param name The name of the member whose value is being returned. + * @return The index of the member with this name, or else -1. + */ + public int indexOf(String name) { + int index=table.get(name); + if (index!=-1 && name.equals(names.get(index))) { + return index; + } + return names.lastIndexOf(name); + } + /** * Returns an iterator over the members of this object in document order. The returned iterator * cannot be used to modify this object. @@ -1209,14 +1240,6 @@ public boolean equals(Object obj) { return names.equals(other.names) && values.equals(other.values); } - int indexOf(String name) { - int index=table.get(name); - if (index!=-1 && name.equals(names.get(index))) { - return index; - } - return names.lastIndexOf(name); - } - private synchronized void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { From c67c6e61b5b47f605333e781aff07f1958fcad55 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 16:19:23 -0600 Subject: [PATCH 43/63] Expose JsonLiteral --- src/main/org/hjson/JsonLiteral.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java index 4901747..e7f3f18 100644 --- a/src/main/org/hjson/JsonLiteral.java +++ b/src/main/org/hjson/JsonLiteral.java @@ -22,7 +22,7 @@ ******************************************************************************/ package org.hjson; -class JsonLiteral extends JsonValue { +public class JsonLiteral extends JsonValue { enum Iv { T, F, N }; From 87654329df1840bfd2c6c66a9f05886aba296619 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 16:28:08 -0600 Subject: [PATCH 44/63] Expose JsonValue#formatComment --- src/main/org/hjson/JsonValue.java | 65 ++++++++++++++++++------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index a6a9c1f..54034fc 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -399,7 +399,8 @@ public boolean isNull() { } /** - * Detects whether this value has been accessed in-code. + * Detects whether this value has been accessed in-code. + * * @return true if the value has been used. */ public boolean isAccessed() { @@ -484,38 +485,14 @@ 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 + * @param type Whether to place this comment before the line, after the line, or inside the * object or array, if applicable. * @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(); - 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; + return setFullComment(type, formatComment(style, comment)); } /** @@ -586,6 +563,40 @@ public JsonValue clearComments() { return this; } + /** + * Generates the formatted expression of the given text as a JSON comment. + * + * @param style Whether to use #, //, or another such comment style. + * @param comment The unformatted comment to be paired with this value. + * @return The formatted, "raw" comment. + */ + public static String formatComment(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]); + } + } + return formatted.toString(); + } + /** * 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 2823fc50614b8bf03a499153aa32371d91621895 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 18:00:30 -0600 Subject: [PATCH 45/63] New utilities for comment manipulation --- src/main/org/hjson/JsonValue.java | 91 ++++++++++++- src/test/org/hjson/test/JsonValueTest.java | 141 +++++++++++++++++++++ src/test/org/hjson/test/Main.java | 5 +- 3 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/test/org/hjson/test/JsonValueTest.java diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 54034fc..0043d8f 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -483,8 +483,42 @@ public boolean hasComments() { */ public String getInteriorComment() { return intComment; } + /** + * Gets any comment associated with this value by its type. + * + * @param type The type of comment being queried. + * @return The full contents of this comment, including any comment indicators. + */ + public String getComment(CommentType type) { + switch (type) { + case BOL: return getBOLComment(); + case EOL: return getEOLComment(); + default: return getInteriorComment(); + } + } + + /** + * Gets any comment that exists above this value. Its indicators will be manually stripped. + * + * @return The text contents of this comment, excluding any comment indicators. + */ + public String getCommentText() { + return getCommentText(CommentType.BOL); + } + + /** + * Gets any comment associated with this value. Its indicators will be manually stripped. + * + * @param type The type of comment being queried. + * @return The text contents of this comment, excluding any comment indicators. + */ + public String getCommentText(CommentType type) { + return stripComment(getComment(type)); + } + /** * Adds a comment to be associated with this value. + * * @param type Whether to place this comment before the line, after the line, or inside the * object or array, if applicable. * @param style Whether to use #, //, or another such comment style. @@ -497,7 +531,7 @@ public JsonValue setComment(CommentType type, CommentStyle style, String comment /** * Shorthand for {@link #setComment(CommentType, CommentStyle, String)} which defaults to sending - * a beginning of line, single line comment, using the default indicator, #. + * a beginning of line comment using the default indicator, #. * * @param comment The unformatted comment to be paired with this value. * @return this, to enable chaining @@ -508,7 +542,7 @@ public JsonValue setComment(String comment) { /** * Shorthand for calling {@link #setComment(CommentType, CommentStyle, String)} which defaults to - * sending an end of line, single line comment, using the default indicator, #. + * sending an end of line comment using the default indicator, #. * * @param comment The unformatted comment to be paired with this value. * @return this, to enable chaining @@ -517,6 +551,42 @@ public JsonValue setEOLComment(String comment) { return setComment(CommentType.EOL, CommentStyle.HASH, comment); } + /** + * Shorthand for calling {@link #appendComment(CommentType, CommentStyle, String)} which defaults to + * appending a beginning of line comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue appendComment(String comment) { + return appendComment(CommentType.BOL, CommentStyle.HASH, comment); + } + + /** + * Shorthand for calling {@link #appendComment(CommentType, CommentStyle, String)} which defaults to + * appending an end of line comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue appendEOLComment(String comment) { + return appendComment(CommentType.EOL, CommentStyle.HASH, comment); + } + + /** + * Adds a new line onto the existing comment in the given position. + * + * @param type Whether to place this comment before the line, after the line, or inside the + * object or array, if applicable. + * @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 appendComment(CommentType type, CommentStyle style, String comment) { + String existing=getComment(type); + return setFullComment(type, existing+'\n'+formatComment(style, comment)); + } + /** * Counterpart to {@link #setComment(CommentType, CommentStyle, String)} which receives * the full, formatted comment to be stored by this value. @@ -572,7 +642,7 @@ public JsonValue clearComments() { */ public static String formatComment(CommentStyle style, String comment) { StringBuilder formatted=new StringBuilder(); - if (style.equals(CommentStyle.BLOCK)){ + if (style.equals(CommentStyle.BLOCK)) { formatted.append("/*"); formatted.append(eol); formatted.append(comment); @@ -597,6 +667,21 @@ public static String formatComment(CommentStyle style, String comment) { return formatted.toString(); } + /** + * Generates the raw text contents of this comment, stripping any comment indicators. + * + * @param comment The raw comment body, with indicators. + * @return The stripped version of the comment, including its message only. + */ + public static String stripComment(String comment) { + String noSingles=comment.replaceAll("(?<=^|\n\r?)\\s*(//|#)\\s?", ""); + if (noSingles.contains("/*")) { + return noSingles.replaceAll("(\\s*\n\r?)?\\s?\\*/", "") + .replaceAll("(?<=^|\n\r?)\\s*/?\\*\\s?", ""); + } + return noSingles; + } + /** * 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. diff --git a/src/test/org/hjson/test/JsonValueTest.java b/src/test/org/hjson/test/JsonValueTest.java new file mode 100644 index 0000000..230eb7d --- /dev/null +++ b/src/test/org/hjson/test/JsonValueTest.java @@ -0,0 +1,141 @@ +package org.hjson.test; + +import org.hjson.CommentStyle; +import org.hjson.JsonValue; + +import java.util.Objects; + +final class JsonValueTest { + + private boolean testsPassing = true; + + boolean allPassing() { + JsonValue.setEol("\n"); + formatComment_generatesHashComment(); + formatComment_generatesLineComment(); + formatComment_generatesBlockComment(); + formatComment_generatesMultilineHash(); + formatComment_generatesMultilineLine(); + stripComment_stripsHashComment(); + stripComment_stripsLineComment(); + stripComment_stripsBlockComment(); + stripComment_stripsMultilineHash(); + stripComment_stripsMultilineLine(); + stripComment_stripsMultilineBlock(); + stripComment_stripsComplexComment(); + return testsPassing; + } + + private void formatComment_generatesHashComment() { + final String comment = "here's a comment"; + final String expected = "# here's a comment"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.HASH, comment)); + } + + private void formatComment_generatesLineComment() { + final String comment = "here's another comment"; + final String expected = "// here's another comment"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.LINE, comment)); + } + + private void formatComment_generatesBlockComment() { + final String comment = "here's a block comment"; + final String expected = "/*\nhere's a block comment\n*/"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.BLOCK, comment)); + } + + private void formatComment_generatesMultilineHash() { + final String comment = "here's a comment\nwith multiple lines"; + final String expected = "# here's a comment\n# with multiple lines"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.HASH, comment)); + } + + private void formatComment_generatesMultilineLine() { + final String comment = "here's a comment\nwith multiple lines"; + final String expected = "// here's a comment\n// with multiple lines"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.LINE, comment)); + } + + private void stripComment_stripsHashComment() { + final String comment = "# hashed comment"; + final String expected = "hashed comment"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsLineComment() { + final String comment = "// line comment"; + final String expected = "line comment"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsBlockComment() { + final String comment = "/* block comment */"; + final String expected = "block comment"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsMultilineHash() { + final String comment = "# hashed comment\n# second line"; + final String expected = "hashed comment\nsecond line"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsMultilineLine() { + final String comment = "// line comment\n// second line"; + final String expected = "line comment\nsecond line"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsMultilineBlock() { + final String comment = "/* block comment\n* second line\n */"; + final String expected = "block comment\nsecond line"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void stripComment_stripsComplexComment() { + final String comment = "/* block comment\n* second line\n /*\n# third line\n// fourth line"; + final String expected = "block comment\nsecond line\nthird line\nfourth line"; + + assertEquals(expected, JsonValue.stripComment(comment)); + } + + private void assertEquals(Object expected, Object actual) { + if (!Objects.equals(expected, actual)) { + System.err.println("Expected:\n" + expected + "\nActual:\n" + actual); + fail(1); + } + pass(1); + } + + private void pass() { + pass(0); + } + + private void fail() { + fail(0); + } + + private void pass(int up) { + System.out.println("- " + getCaller(up) + " OK"); + } + + private void fail(int up) { + System.err.println("- " + getCaller(up) + " FAILED"); + this.testsPassing = false; + } + + private String getCaller(int up) { + return Thread.currentThread().getStackTrace()[3 + up].getMethodName(); + } +} diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index 7a3971b..0b9c993 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -93,7 +93,7 @@ static boolean failErr(String name, String type, String s1, String s2) { public static void main(String[] args) throws Exception { - out.println("running tests..."); + out.println("running output tests..."); String[] testNames=load("testlist.txt", false).split("\n"); boolean allOK=true; @@ -114,6 +114,9 @@ && test(name, file, true, true)) { else { allOK=false; } } + JsonValueTest logicTests=new JsonValueTest(); + if (!logicTests.allPassing()) allOK=false; + if (!allOK) { out.println("FAILED!"); System.exit(1); From addbc28d40c53e320967a751c41c43c58149fab6 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 20:37:05 -0600 Subject: [PATCH 46/63] JsonArray#indexOf and #lastIndexOf --- src/main/org/hjson/JsonArray.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 6f5e898..168a9c2 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -706,6 +706,26 @@ public JsonValue get(int index) { return values.get(index).setAccessed(true); } + /** + * Returns the index of the given element, or else -1 if not found. + * + * @param value The value being queried in the array. + * @return The index of the element, or else -1 if not found. + */ + public int indexOf(JsonValue value) { + return values.indexOf(value); + } + + /** + * Returns the last index of the given element, or else -1 if not found. + * + * @param value The value being queried in the array. + * @return The last index of the element, or else -1 if not found. + */ + public int lastIndexOf(JsonValue value) { + return values.lastIndexOf(value); + } + /** * Returns whether this array contains a value. * From 5742b306817ca1a184dec5da0c6e1dec175b8ff4 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 20:42:55 -0600 Subject: [PATCH 47/63] JsonValue#deepCopy and #shallowCopy --- src/main/org/hjson/JsonArray.java | 19 +++++++++++++ src/main/org/hjson/JsonDsf.java | 6 ++++ src/main/org/hjson/JsonLiteral.java | 6 ++++ src/main/org/hjson/JsonNumber.java | 6 ++++ src/main/org/hjson/JsonObject.java | 19 +++++++++++++ src/main/org/hjson/JsonString.java | 6 ++++ src/main/org/hjson/JsonValue.java | 32 ++++++++++++++++++++++ src/test/org/hjson/test/JsonValueTest.java | 9 ++++++ 8 files changed, 103 insertions(+) diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 168a9c2..95a8b49 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -870,6 +870,25 @@ public JsonArray asArray() { return this; } + @Override + public JsonValue shallowCopy() { + JsonArray clone=(JsonArray)new JsonArray().copyComments(this); + for (JsonValue value : values) { + clone.add(value); + } + return clone; + } + + @Override + public JsonArray deepCopy(boolean trackAccess) { + JsonArray clone=(JsonArray)new JsonArray().copyComments(this); + if (trackAccess) clone.setAccessed(accessed); + for (JsonValue value : values) { + clone.add(value.deepCopy(trackAccess)); + } + return clone; + } + @Override public int hashCode() { return values.hashCode(); diff --git a/src/main/org/hjson/JsonDsf.java b/src/main/org/hjson/JsonDsf.java index d62e109..025e0b9 100644 --- a/src/main/org/hjson/JsonDsf.java +++ b/src/main/org/hjson/JsonDsf.java @@ -44,6 +44,12 @@ public Object asDsf() { return value; } + @Override + public JsonValue deepCopy(boolean trackAccess) { + JsonValue clone=new JsonDsf(value).copyComments(this); + return trackAccess?clone.setAccessed(accessed):clone; + } + @Override public int hashCode() { return value.hashCode(); diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java index e7f3f18..ecf684c 100644 --- a/src/main/org/hjson/JsonLiteral.java +++ b/src/main/org/hjson/JsonLiteral.java @@ -89,6 +89,12 @@ public boolean asBoolean() { return value==Iv.N ? super.asBoolean() : value==Iv.T; } + @Override + public JsonValue deepCopy(boolean trackAccess) { + JsonValue clone=new JsonLiteral(value).copyComments(this); + return trackAccess?clone.setAccessed(accessed):clone; + } + @Override public boolean equals(Object object) { if (this==object) { diff --git a/src/main/org/hjson/JsonNumber.java b/src/main/org/hjson/JsonNumber.java index 4bb60c1..0aad9b6 100644 --- a/src/main/org/hjson/JsonNumber.java +++ b/src/main/org/hjson/JsonNumber.java @@ -75,6 +75,12 @@ public double asDouble() { return value; } + @Override + public JsonValue deepCopy(boolean trackAccess) { + JsonValue clone=new JsonNumber(value).copyComments(this); + return trackAccess?clone.setAccessed(accessed):clone; + } + @Override public int hashCode() { return super.hashCode() * 59 + Double.valueOf(value).hashCode(); diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 6fb07c7..e679df8 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -1217,6 +1217,25 @@ public JsonObject asObject() { return this; } + @Override + public JsonValue shallowCopy() { + JsonObject clone=(JsonObject)new JsonObject().copyComments(this); + for (Member member : this) { + clone.add(member.getName(), member.getValue()); + } + return clone; + } + + @Override + public JsonValue deepCopy(boolean trackAccess) { + JsonObject clone=(JsonObject)new JsonObject().copyComments(this); + if (trackAccess) clone.setAccessed(accessed); + for (Member member : this) { + clone.add(member.getName(), member.getValue().deepCopy(trackAccess)); + } + return clone; + } + @Override public int hashCode() { int result=1; diff --git a/src/main/org/hjson/JsonString.java b/src/main/org/hjson/JsonString.java index df2cfe2..706c877 100644 --- a/src/main/org/hjson/JsonString.java +++ b/src/main/org/hjson/JsonString.java @@ -49,6 +49,12 @@ public String asString() { return string; } + @Override + public JsonValue deepCopy(boolean trackAccess) { + JsonValue clone=new JsonString(string).copyComments(this); + return trackAccess?clone.setAccessed(accessed):clone; + } + @Override public int hashCode() { return super.hashCode() * 59 + string.hashCode(); diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 0043d8f..c90960d 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -820,6 +820,38 @@ public T asRaw() { } } + /** + * Generates a new instance of this value which is largely identical to this one. If this value + * is a container type, a new container will be generated containing the original values. + * + * @return A new instance of this value with the same data, comments, and other metadata. + */ + public JsonValue shallowCopy() { + return deepCopy(); + } + + /** + * Generates a new instance of this value which is exactly identical to this one. Regardless of + * which type this value is, it will exclusively contain new instances recursively. + * + *

This implementation ignores whether the value has been accessed, but this may additionally + * be copied with an optional boolean parameter.

+ * + * @return A new instance of this value with the same data, comments, and other metadata. + */ + public JsonValue deepCopy() { + return deepCopy(false); + } + + /** + * Generates a new instance of this value which is exactly identical to this one. Regardless of + * which type this value is, it will exclusively contain new instances recursively. + * + * @param trackAccess Whether to additionally persist access records to the new value. + * @return A new instance of this value with the same data, comments, and other metadata. + */ + public abstract JsonValue deepCopy(boolean trackAccess); + /** * Writes the JSON representation of this value to the given writer in its minimal form, without * any additional whitespace. diff --git a/src/test/org/hjson/test/JsonValueTest.java b/src/test/org/hjson/test/JsonValueTest.java index 230eb7d..387af76 100644 --- a/src/test/org/hjson/test/JsonValueTest.java +++ b/src/test/org/hjson/test/JsonValueTest.java @@ -1,6 +1,7 @@ package org.hjson.test; import org.hjson.CommentStyle; +import org.hjson.JsonLiteral; import org.hjson.JsonValue; import java.util.Objects; @@ -23,6 +24,7 @@ boolean allPassing() { stripComment_stripsMultilineLine(); stripComment_stripsMultilineBlock(); stripComment_stripsComplexComment(); + setComment_getCommentText_preservesExactText(); return testsPassing; } @@ -110,6 +112,13 @@ private void stripComment_stripsComplexComment() { assertEquals(expected, JsonValue.stripComment(comment)); } + private void setComment_getCommentText_preservesExactText() { + final String comment = "Hello, World!"; + final JsonValue value = JsonLiteral.jsonNull().setComment(comment); + + assertEquals(comment, value.getCommentText()); + } + private void assertEquals(Object expected, Object actual) { if (!Objects.equals(expected, actual)) { System.err.println("Expected:\n" + expected + "\nActual:\n" + actual); From 9dcad469f0b42865e5f98d060835ac1af8067fe8 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 21:11:01 -0600 Subject: [PATCH 48/63] Better equals and hash implementations --- src/main/org/hjson/JsonArray.java | 13 +++++-------- src/main/org/hjson/JsonDsf.java | 16 ++++++++++++++-- src/main/org/hjson/JsonLiteral.java | 23 ++++++++++------------- src/main/org/hjson/JsonNumber.java | 13 +++++-------- src/main/org/hjson/JsonObject.java | 11 ++++------- src/main/org/hjson/JsonString.java | 13 +++++-------- src/main/org/hjson/JsonValue.java | 12 ++++++++++++ 7 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 95a8b49..99c641d 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -891,7 +891,7 @@ public JsonArray deepCopy(boolean trackAccess) { @Override public int hashCode() { - return values.hashCode(); + return super.hashCode() * 59 + values.hashCode(); } @Override @@ -899,13 +899,10 @@ public boolean equals(Object object) { if (this==object) { return true; } - if (object==null) { - return false; + if (object instanceof JsonArray) { + JsonArray other=(JsonArray)object; + return values.equals(other.values) && commentsMatch(other); } - if (getClass()!=object.getClass()) { - return false; - } - JsonArray other=(JsonArray)object; - return values.equals(other.values); + return false; } } diff --git a/src/main/org/hjson/JsonDsf.java b/src/main/org/hjson/JsonDsf.java index 025e0b9..1b83ce8 100644 --- a/src/main/org/hjson/JsonDsf.java +++ b/src/main/org/hjson/JsonDsf.java @@ -47,11 +47,23 @@ public Object asDsf() { @Override public JsonValue deepCopy(boolean trackAccess) { JsonValue clone=new JsonDsf(value).copyComments(this); - return trackAccess?clone.setAccessed(accessed):clone; + return trackAccess ? clone.setAccessed(accessed) : clone; } @Override public int hashCode() { - return value.hashCode(); + return super.hashCode() * 59 + value.hashCode(); + } + + @Override + public boolean equals(Object object) { + if (this==object) { + return true; + } + if (object instanceof JsonDsf) { + JsonDsf other=(JsonDsf)object; + return value.equals(other.value) && commentsMatch(other); + } + return false; } } diff --git a/src/main/org/hjson/JsonLiteral.java b/src/main/org/hjson/JsonLiteral.java index ecf684c..72c4ca1 100644 --- a/src/main/org/hjson/JsonLiteral.java +++ b/src/main/org/hjson/JsonLiteral.java @@ -54,11 +54,6 @@ public static JsonLiteral jsonFalse() { return new JsonLiteral(Iv.F); } - @Override - public int hashCode() { - return super.hashCode() * 59 + value.hashCode(); - } - @Override public JsonType getType() { return value==Iv.N ? JsonType.NULL : JsonType.BOOLEAN; @@ -92,7 +87,12 @@ public boolean asBoolean() { @Override public JsonValue deepCopy(boolean trackAccess) { JsonValue clone=new JsonLiteral(value).copyComments(this); - return trackAccess?clone.setAccessed(accessed):clone; + return trackAccess ? clone.setAccessed(accessed) : clone; + } + + @Override + public int hashCode() { + return super.hashCode() * 59 + value.hashCode(); } @Override @@ -100,13 +100,10 @@ public boolean equals(Object object) { if (this==object) { return true; } - if (object==null) { - return false; - } - if (getClass()!=object.getClass()) { - return false; + if (object instanceof JsonLiteral) { + JsonLiteral other=(JsonLiteral)object; + return value==other.value && commentsMatch(other); } - JsonLiteral other=(JsonLiteral)object; - return value==other.value; + return false; } } diff --git a/src/main/org/hjson/JsonNumber.java b/src/main/org/hjson/JsonNumber.java index 0aad9b6..5fc79e2 100644 --- a/src/main/org/hjson/JsonNumber.java +++ b/src/main/org/hjson/JsonNumber.java @@ -78,7 +78,7 @@ public double asDouble() { @Override public JsonValue deepCopy(boolean trackAccess) { JsonValue clone=new JsonNumber(value).copyComments(this); - return trackAccess?clone.setAccessed(accessed):clone; + return trackAccess ? clone.setAccessed(accessed) : clone; } @Override @@ -91,13 +91,10 @@ public boolean equals(Object object) { if (this==object) { return true; } - if (object==null) { - return false; + if (object instanceof JsonNumber) { + JsonNumber other=(JsonNumber)object; + return value==other.value && commentsMatch(other); } - if (getClass()!=object.getClass()) { - return false; - } - JsonNumber other=(JsonNumber)object; - return value==other.value; + return false; } } diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index e679df8..edc3b2e 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -1249,14 +1249,11 @@ public boolean equals(Object obj) { if (this==obj) { return true; } - if (obj==null) { - return false; + if (obj instanceof JsonObject) { + JsonObject other=(JsonObject)obj; + return names.equals(other.names) && values.equals(other.values) && commentsMatch(other); } - if (getClass()!=obj.getClass()) { - return false; - } - JsonObject other=(JsonObject)obj; - return names.equals(other.names) && values.equals(other.values); + return false; } private synchronized void readObject(ObjectInputStream inputStream) throws IOException, diff --git a/src/main/org/hjson/JsonString.java b/src/main/org/hjson/JsonString.java index 706c877..fc99153 100644 --- a/src/main/org/hjson/JsonString.java +++ b/src/main/org/hjson/JsonString.java @@ -52,7 +52,7 @@ public String asString() { @Override public JsonValue deepCopy(boolean trackAccess) { JsonValue clone=new JsonString(string).copyComments(this); - return trackAccess?clone.setAccessed(accessed):clone; + return trackAccess ? clone.setAccessed(accessed) : clone; } @Override @@ -65,13 +65,10 @@ public boolean equals(Object object) { if (this==object) { return true; } - if (object==null) { - return false; + if (object instanceof JsonString) { + JsonString other=(JsonString)object; + return string.equals(other.string) && commentsMatch(other); } - if (getClass()!=object.getClass()) { - return false; - } - JsonString other=(JsonString)object; - return string.equals(other.string); + return false; } } diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index c90960d..5153c95 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -633,6 +633,18 @@ public JsonValue clearComments() { return this; } + /** + * Returns whether the two value contain identical comments. + * + * @param value The JSON value being compared to. + * @return true if the values contain identical comments. + */ + public boolean commentsMatch(JsonValue value) { + return bolComment.equals(value.bolComment) + && eolComment.equals(value.eolComment) + && intComment.equals(value.intComment); + } + /** * Generates the formatted expression of the given text as a JSON comment. * From 654de79993fcaa60b225b69524061a310a5a0e45 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 21:11:24 -0600 Subject: [PATCH 49/63] Test cases for deep and shallow copy --- src/test/org/hjson/test/JsonValueTest.java | 72 ++++++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/src/test/org/hjson/test/JsonValueTest.java b/src/test/org/hjson/test/JsonValueTest.java index 387af76..e507761 100644 --- a/src/test/org/hjson/test/JsonValueTest.java +++ b/src/test/org/hjson/test/JsonValueTest.java @@ -2,6 +2,7 @@ import org.hjson.CommentStyle; import org.hjson.JsonLiteral; +import org.hjson.JsonObject; import org.hjson.JsonValue; import java.util.Objects; @@ -25,6 +26,9 @@ boolean allPassing() { stripComment_stripsMultilineBlock(); stripComment_stripsComplexComment(); setComment_getCommentText_preservesExactText(); + shallowCopy_deeplyCopiesValues(); + shallowCopy_shallowCopiesContainer(); + deepCopy_deeplyCopiesContainer(); return testsPassing; } @@ -119,32 +123,76 @@ private void setComment_getCommentText_preservesExactText() { assertEquals(comment, value.getCommentText()); } + private void shallowCopy_deeplyCopiesValues() { + final JsonValue value = JsonValue.valueOf(true).setAccessed(true).setComment("comment"); + final JsonValue clone = value.shallowCopy(); + + assertEquals(value, clone); + assertNotEquals(value.isAccessed(), clone.isAccessed()); + } + + private void shallowCopy_shallowCopiesContainer() { + final JsonObject value = new JsonObject().add("test", "test"); + final JsonObject clone = (JsonObject) value.shallowCopy(); + + assertEquals(value, clone); + for (int i = 0; i < value.size(); i++) { + assertSame(value.get(i), clone.get(i)); + } + } + + private void deepCopy_deeplyCopiesContainer() { + final JsonObject value = new JsonObject().add("test", "test"); + final JsonObject clone = (JsonObject) value.deepCopy(); + + assertEquals(value, clone); + for (int i = 0; i < value.size(); i++) { + assertNotSame(value.get(i), clone.get(i)); + } + } + private void assertEquals(Object expected, Object actual) { if (!Objects.equals(expected, actual)) { System.err.println("Expected:\n" + expected + "\nActual:\n" + actual); - fail(1); + fail(); } - pass(1); + pass(); } - private void pass() { - pass(0); + private void assertNotEquals(Object expected, Object actual) { + if (Objects.equals(expected, actual)) { + System.err.println("Values should not match:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } + pass(); } - private void fail() { - fail(0); + private void assertSame(Object expected, Object actual) { + if (expected != actual) { + System.err.println("Expected instance equality:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } + pass(); } - private void pass(int up) { - System.out.println("- " + getCaller(up) + " OK"); + private void assertNotSame(Object expected, Object actual) { + if (expected == actual) { + System.err.println("Should be a different instance:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } + pass(); } - private void fail(int up) { - System.err.println("- " + getCaller(up) + " FAILED"); + private void pass() { + System.out.println("- " + getCaller() + " OK"); + } + + private void fail() { + System.err.println("- " + getCaller() + " FAILED"); this.testsPassing = false; } - private String getCaller(int up) { - return Thread.currentThread().getStackTrace()[3 + up].getMethodName(); + private String getCaller() { + return Thread.currentThread().getStackTrace()[4].getMethodName(); } } From 8d4a6eb43da1c9c8d9b7ccc22db944eb4db74f53 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 21:26:42 -0600 Subject: [PATCH 50/63] Only append comment if comment is not empty --- src/main/org/hjson/JsonValue.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 5153c95..e965088 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -584,6 +584,9 @@ public JsonValue appendEOLComment(String comment) { */ public JsonValue appendComment(CommentType type, CommentStyle style, String comment) { String existing=getComment(type); + if (existing.isEmpty()) { + return setFullComment(type, formatComment(style, comment)); + } return setFullComment(type, existing+'\n'+formatComment(style, comment)); } From 0a635c84b6622435ea170489e844c5e1429f2f35 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 21:30:21 -0600 Subject: [PATCH 51/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7ad0d65..c97ca10 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C6' +version = '3.0.0-C7' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 5220e4d3f2772899fa98da472b705af6e5b3f388 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Sun, 6 Feb 2022 21:35:17 -0600 Subject: [PATCH 52/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c97ca10..fda5b74 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C7' +version = '3.0.0-C8' group = 'org.hjson' description = """Hjson, the Human JSON.""" From face1b510e1b4cee9f46a07411b6ca5128138190 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Mon, 7 Feb 2022 18:06:19 -0600 Subject: [PATCH 53/63] A few new test cases and bugs fixed --- src/main/org/hjson/JsonArray.java | 3 + src/main/org/hjson/JsonObject.java | 2 +- src/test/org/hjson/test/JsonObjectTest.java | 39 +++++++++++ src/test/org/hjson/test/JsonTest.java | 78 +++++++++++++++++++++ src/test/org/hjson/test/JsonValueTest.java | 56 +-------------- src/test/org/hjson/test/Main.java | 4 +- 6 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 src/test/org/hjson/test/JsonObjectTest.java create mode 100644 src/test/org/hjson/test/JsonTest.java diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 99c641d..39d538e 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -821,6 +821,9 @@ public List getUsedPaths(boolean used) { final List paths=new ArrayList<>(); int index=0; for (JsonValue v : this) { + if (used == v.isAccessed()) { + paths.add("["+index+"]"); + } if (v.isObject()) { for (String s : v.asObject().getUsedPaths(used)) { paths.add("["+index+"]."+s); diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index edc3b2e..0c9d037 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -1117,7 +1117,7 @@ public List getUsedPaths(boolean used) { for (Member m : this) { if (used == m.value.isAccessed()) { paths.add(m.name); - } //else {paths.add("*"+m.name);} + } if (m.value.isObject()) { for (String s : m.value.asObject().getUsedPaths(used)) { paths.add(m.name+"."+s); diff --git a/src/test/org/hjson/test/JsonObjectTest.java b/src/test/org/hjson/test/JsonObjectTest.java new file mode 100644 index 0000000..a9868e1 --- /dev/null +++ b/src/test/org/hjson/test/JsonObjectTest.java @@ -0,0 +1,39 @@ +package org.hjson.test; + +import org.hjson.JsonObject; +import org.hjson.JsonValue; + +import java.util.Arrays; + +public class JsonObjectTest extends JsonTest { + + @Override + void run() { + getUnusedPaths_returnsUnusedPathsOnly(); + getUsedPaths_returnsUsedPathsOnly(); + getAllPaths_returnsAllPaths(); + } + + void getUnusedPaths_returnsUnusedPathsOnly() { + final JsonObject subject = parse("a:{b:[{c:{}}]}"); + subject.get("a"); + + assertEquals(Arrays.asList("a.b", "a.b[0]", "a.b[0].c"), subject.getUnusedPaths()); + } + + void getUsedPaths_returnsUsedPathsOnly() { + final JsonObject subject = parse("a:{b:[{c:[]}]}x:[{y:{z:{}}}]"); + subject.get("a").asObject().get("b"); + subject.get("x").asArray().get(0); + + assertEquals(Arrays.asList("a", "a.b", "x", "x[0]"), subject.getUsedPaths()); + } + + void getAllPaths_returnsAllPaths() { + + } + + private static JsonObject parse(final String json) { + return JsonValue.readHjson(json).asObject(); + } +} diff --git a/src/test/org/hjson/test/JsonTest.java b/src/test/org/hjson/test/JsonTest.java new file mode 100644 index 0000000..6bf8893 --- /dev/null +++ b/src/test/org/hjson/test/JsonTest.java @@ -0,0 +1,78 @@ +package org.hjson.test; + +import org.hjson.JsonValue; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public abstract class JsonTest { + + private final Set methodsReported = new HashSet<>(); + protected boolean testsPassing = true; + + abstract void run(); + + final boolean allPassing() { + JsonValue.setEol("\n"); + run(); + return testsPassing; + } + + protected final void assertEquals(Object expected, Object actual) { + if (!Objects.equals(expected, actual)) { + System.err.println("Expected:\n" + expected + "\nActual:\n" + actual); + fail(); + } else { + pass(); + } + } + + protected final void assertNotEquals(Object expected, Object actual) { + if (Objects.equals(expected, actual)) { + System.err.println("Values should not match:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } else { + pass(); + } + } + + protected final void assertSame(Object expected, Object actual) { + if (expected != actual) { + System.err.println("Expected instance equality:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } else { + pass(); + } + } + + protected final void assertNotSame(Object expected, Object actual) { + if (expected == actual) { + System.err.println("Should be a different instance:\nExpected:\n" + expected + "\nActual:\n" + actual); + fail(); + } else { + pass(); + } + } + + protected final void pass() { + final String caller = getCaller(); + if (methodsReported.add(caller)) { + System.out.println("- " + caller + " OK"); + } + } + + protected final void fail() { + System.out.println("- " + getCaller() + " FAILED @ " + getCallerDetails()); + this.testsPassing = false; + } + + private String getCaller() { + return Thread.currentThread().getStackTrace()[4].getMethodName(); + } + + private String getCallerDetails() { + final StackTraceElement[] st = Thread.currentThread().getStackTrace(); + return st[3].getMethodName() + "[" + st[4].getLineNumber() + "]"; + } +} diff --git a/src/test/org/hjson/test/JsonValueTest.java b/src/test/org/hjson/test/JsonValueTest.java index e507761..2906f1d 100644 --- a/src/test/org/hjson/test/JsonValueTest.java +++ b/src/test/org/hjson/test/JsonValueTest.java @@ -5,14 +5,10 @@ import org.hjson.JsonObject; import org.hjson.JsonValue; -import java.util.Objects; +final class JsonValueTest extends JsonTest { -final class JsonValueTest { - - private boolean testsPassing = true; - - boolean allPassing() { - JsonValue.setEol("\n"); + @Override + void run() { formatComment_generatesHashComment(); formatComment_generatesLineComment(); formatComment_generatesBlockComment(); @@ -29,7 +25,6 @@ boolean allPassing() { shallowCopy_deeplyCopiesValues(); shallowCopy_shallowCopiesContainer(); deepCopy_deeplyCopiesContainer(); - return testsPassing; } private void formatComment_generatesHashComment() { @@ -150,49 +145,4 @@ private void deepCopy_deeplyCopiesContainer() { assertNotSame(value.get(i), clone.get(i)); } } - - private void assertEquals(Object expected, Object actual) { - if (!Objects.equals(expected, actual)) { - System.err.println("Expected:\n" + expected + "\nActual:\n" + actual); - fail(); - } - pass(); - } - - private void assertNotEquals(Object expected, Object actual) { - if (Objects.equals(expected, actual)) { - System.err.println("Values should not match:\nExpected:\n" + expected + "\nActual:\n" + actual); - fail(); - } - pass(); - } - - private void assertSame(Object expected, Object actual) { - if (expected != actual) { - System.err.println("Expected instance equality:\nExpected:\n" + expected + "\nActual:\n" + actual); - fail(); - } - pass(); - } - - private void assertNotSame(Object expected, Object actual) { - if (expected == actual) { - System.err.println("Should be a different instance:\nExpected:\n" + expected + "\nActual:\n" + actual); - fail(); - } - pass(); - } - - private void pass() { - System.out.println("- " + getCaller() + " OK"); - } - - private void fail() { - System.err.println("- " + getCaller() + " FAILED"); - this.testsPassing = false; - } - - private String getCaller() { - return Thread.currentThread().getStackTrace()[4].getMethodName(); - } } diff --git a/src/test/org/hjson/test/Main.java b/src/test/org/hjson/test/Main.java index 0b9c993..24dded1 100644 --- a/src/test/org/hjson/test/Main.java +++ b/src/test/org/hjson/test/Main.java @@ -114,8 +114,8 @@ && test(name, file, true, true)) { else { allOK=false; } } - JsonValueTest logicTests=new JsonValueTest(); - if (!logicTests.allPassing()) allOK=false; + if (!new JsonValueTest().allPassing()) allOK=false; + if (!new JsonObjectTest().allPassing()) allOK=false; if (!allOK) { out.println("FAILED!"); From eca87a6ffe9c7818a7baa2e6109b175d1b6acf0a Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Mon, 7 Feb 2022 18:17:01 -0600 Subject: [PATCH 54/63] JsonObject and JsonArray#getAllPaths --- src/main/org/hjson/JsonArray.java | 30 +++++++++++++++++++++ src/main/org/hjson/JsonObject.java | 24 +++++++++++++++++ src/test/org/hjson/test/JsonObjectTest.java | 6 ++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 39d538e..9014281 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -797,6 +797,7 @@ public List values() { /** * Generates a list of paths that have not yet been accessed in-code. + * * @return the list of unused paths. */ public List getUnusedPaths() { @@ -805,6 +806,7 @@ public List getUnusedPaths() { /** * Generates a list of paths that have been accessed in-code. + * * @return the list of unused paths. */ public List getUsedPaths() { @@ -828,6 +830,34 @@ public List getUsedPaths(boolean used) { for (String s : v.asObject().getUsedPaths(used)) { paths.add("["+index+"]."+s); } + } else if (v.isArray()) { + for (String s : v.asArray().getUsedPaths(used)) { + paths.add("["+index+"]"+s); + } + } + index++; + } + return paths; + } + + /** + * Generates a list of all possible paths in this array. + * + * @return the list of paths. + */ + public List getAllPaths() { + final List paths=new ArrayList(); + int index=0; + for (JsonValue v : this) { + paths.add("["+index+"]"); + if (v.isObject()) { + for (String s : v.asObject().getAllPaths()) { + paths.add("["+index+"]."+s); + } + } else if (v.isArray()) { + for (String s : v.asArray().getAllPaths()) { + paths.add("["+index+"]"+s); + } } index++; } diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 0c9d037..794d3cb 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -1092,6 +1092,7 @@ public List names() { /** * Generates a list of paths that have not yet been accessed in-code. + * * @return the list of unused paths. */ public List getUnusedPaths() { @@ -1100,6 +1101,7 @@ public List getUnusedPaths() { /** * Generates a list of paths that have been accessed in-code. + * * @return the list of used paths. */ public List getUsedPaths() { @@ -1131,6 +1133,28 @@ public List getUsedPaths(boolean used) { return paths; } + /** + * Generates a list of all possible paths in this object. + * + * @return the list of paths. + */ + public List getAllPaths() { + final List paths=new ArrayList(); + for (Member m : this) { + paths.add(m.name); + if (m.value.isObject()) { + for (String s : m.value.asObject().getAllPaths()) { + paths.add(m.name+"."+s); + } + } else if (m.value.isArray()) { + for (String s : m.value.asArray().getAllPaths()) { + paths.add(m.name+s); + } + } + } + return paths; + } + /** * Sorts all members of this object according to their keys, in alphabetical order. * diff --git a/src/test/org/hjson/test/JsonObjectTest.java b/src/test/org/hjson/test/JsonObjectTest.java index a9868e1..0393f80 100644 --- a/src/test/org/hjson/test/JsonObjectTest.java +++ b/src/test/org/hjson/test/JsonObjectTest.java @@ -22,7 +22,7 @@ void getUnusedPaths_returnsUnusedPathsOnly() { } void getUsedPaths_returnsUsedPathsOnly() { - final JsonObject subject = parse("a:{b:[{c:[]}]}x:[{y:{z:{}}}]"); + final JsonObject subject = parse("a:{b:[{c:[]}]},x:[{y:{z:{}}}]"); subject.get("a").asObject().get("b"); subject.get("x").asArray().get(0); @@ -30,7 +30,11 @@ void getUsedPaths_returnsUsedPathsOnly() { } void getAllPaths_returnsAllPaths() { + final JsonObject subject = parse("a:{},b:{},c:[[{d:[]}],[]]"); + subject.get("a"); + subject.get("c").asArray().get(0); + assertEquals(Arrays.asList("a", "b", "c", "c[0]", "c[0][0]", "c[0][0].d", "c[1]"), subject.getAllPaths()); } private static JsonObject parse(final String json) { From 9665341bb1bd17f4dc1a73b7a9c02479bd99cdd3 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Mon, 7 Feb 2022 18:17:29 -0600 Subject: [PATCH 55/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fda5b74..5274b92 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C8' +version = '3.0.0-C9' group = 'org.hjson' description = """Hjson, the Human JSON.""" From bbe91b0fbea4c1f0a50aca1e01f2e16079d02522 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 13:14:08 -0600 Subject: [PATCH 56/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5274b92..2e772aa 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C9' +version = '3.0.0-C10' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 4e0e5049b33f88959319a49c919eb8bfb4ec7744 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 13:14:27 -0600 Subject: [PATCH 57/63] JsonValue#prependComment and variants --- src/main/org/hjson/JsonValue.java | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index e965088..cf69eeb 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -573,6 +573,17 @@ public JsonValue appendEOLComment(String comment) { return appendComment(CommentType.EOL, CommentStyle.HASH, comment); } + /** + * Shorthand for calling {@link #appendComment(CommentType, CommentStyle, String)} which defaults to + * appending an interior comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue appendInteriorComment(String comment) { + return appendComment(CommentType.EOL, CommentStyle.HASH, comment); + } + /** * Adds a new line onto the existing comment in the given position. * @@ -590,6 +601,56 @@ public JsonValue appendComment(CommentType type, CommentStyle style, String comm return setFullComment(type, existing+'\n'+formatComment(style, comment)); } + /** + * Shorthand for calling {@link #prependComment(CommentType, CommentStyle, String)} which defaults to + * appending a beginning of line comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue prependComment(String comment) { + return prependComment(CommentType.BOL, CommentStyle.HASH, comment); + } + + /** + * Shorthand for calling {@link #prependComment(CommentType, CommentStyle, String)} which defaults to + * appending an end of line comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue prependEOLComment(String comment) { + return prependComment(CommentType.EOL, CommentStyle.HASH, comment); + } + + /** + * Shorthand for calling {@link #prependComment(CommentType, CommentStyle, String)} which defaults to + * appending an interior comment using the default indicator, # + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue prependInteriorComment(String comment) { + return prependComment(CommentType.EOL, CommentStyle.HASH, comment); + } + + /** + * Adds a new line onto the existing comment in the given position. + * + * @param type Whether to place this comment before the line, after the line, or inside the + * object or array, if applicable. + * @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 prependComment(CommentType type, CommentStyle style, String comment) { + String existing=getComment(type); + if (existing.isEmpty()) { + return setFullComment(type, formatComment(style, comment)); + } + return setFullComment(type, formatComment(style, comment)+"\n"+existing); + } + /** * Counterpart to {@link #setComment(CommentType, CommentStyle, String)} which receives * the full, formatted comment to be stored by this value. From 2b9f788f1d4a5d84416b51c5f52f9d48db8edd9f Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 13:27:10 -0600 Subject: [PATCH 58/63] Better copying of JSON metadata --- src/main/org/hjson/JsonArray.java | 15 ++++++++++++--- src/main/org/hjson/JsonObject.java | 15 ++++++++++++--- src/main/org/hjson/JsonValue.java | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/main/org/hjson/JsonArray.java b/src/main/org/hjson/JsonArray.java index 9014281..0523132 100644 --- a/src/main/org/hjson/JsonArray.java +++ b/src/main/org/hjson/JsonArray.java @@ -905,7 +905,7 @@ public JsonArray asArray() { @Override public JsonValue shallowCopy() { - JsonArray clone=(JsonArray)new JsonArray().copyComments(this); + JsonArray clone=(JsonArray)new JsonArray().copyMetadata(this, false); for (JsonValue value : values) { clone.add(value); } @@ -914,14 +914,23 @@ public JsonValue shallowCopy() { @Override public JsonArray deepCopy(boolean trackAccess) { - JsonArray clone=(JsonArray)new JsonArray().copyComments(this); - if (trackAccess) clone.setAccessed(accessed); + JsonArray clone=(JsonArray)new JsonArray().copyMetadata(this, trackAccess); for (JsonValue value : values) { clone.add(value.deepCopy(trackAccess)); } return clone; } + @Override + public JsonValue copyMetadata(JsonValue value, boolean trackAccess) { + if (value instanceof JsonArray) { + final JsonArray array=value.asArray(); + this.lineLength=array.lineLength; + this.condensed=array.condensed; + } + return super.copyMetadata(value, trackAccess); + } + @Override public int hashCode() { return super.hashCode() * 59 + values.hashCode(); diff --git a/src/main/org/hjson/JsonObject.java b/src/main/org/hjson/JsonObject.java index 794d3cb..4214f13 100644 --- a/src/main/org/hjson/JsonObject.java +++ b/src/main/org/hjson/JsonObject.java @@ -1243,7 +1243,7 @@ public JsonObject asObject() { @Override public JsonValue shallowCopy() { - JsonObject clone=(JsonObject)new JsonObject().copyComments(this); + JsonObject clone=(JsonObject)new JsonObject().copyMetadata(this, false); for (Member member : this) { clone.add(member.getName(), member.getValue()); } @@ -1252,14 +1252,23 @@ public JsonValue shallowCopy() { @Override public JsonValue deepCopy(boolean trackAccess) { - JsonObject clone=(JsonObject)new JsonObject().copyComments(this); - if (trackAccess) clone.setAccessed(accessed); + JsonObject clone=(JsonObject)new JsonObject().copyMetadata(this, trackAccess); for (Member member : this) { clone.add(member.getName(), member.getValue().deepCopy(trackAccess)); } return clone; } + @Override + public JsonValue copyMetadata(JsonValue value, boolean trackAccess) { + if (value instanceof JsonObject) { + final JsonObject object=value.asObject(); + this.lineLength=object.lineLength; + this.condensed=object.condensed; + } + return super.copyMetadata(value, trackAccess); + } + @Override public int hashCode() { int result=1; diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index cf69eeb..4a5fe67 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -928,6 +928,21 @@ public JsonValue deepCopy() { */ public abstract JsonValue deepCopy(boolean trackAccess); + /** + * Copies all metadata from another JSON value, including its comments, line length, + * whether it was accessed, and any other data. + * + * @param value The value being copied from. + * @param trackAccess Whether to additionally copy access trackers. + * @return this, for method chaining. + */ + public JsonValue copyMetadata(JsonValue value, boolean trackAccess) { + this.copyComments(value); + this.numLines=value.numLines; + if (trackAccess) this.accessed=value.accessed; + return this; + } + /** * Writes the JSON representation of this value to the given writer in its minimal form, without * any additional whitespace. From 4d161ed8969ddfee94d0c7f861c8e34bc3452f5a Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 13:31:30 -0600 Subject: [PATCH 59/63] Minor fixes for JsonValue#valueOf --- src/main/org/hjson/JsonValue.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 4a5fe67..c22fcb4 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -291,9 +291,9 @@ public static JsonValue valueOf(Object value) { return (Boolean) value ? JsonLiteral.jsonTrue() : JsonLiteral.jsonFalse(); } else if (value instanceof Enum) { return new JsonString(((Enum) value).name()); - } else if (value instanceof List) { + } else if (value instanceof Iterable) { JsonArray array=new JsonArray(); - for (Object o : (List) value) { + for (Object o : (Iterable) value) { array.add(valueOf(o)); } return array; @@ -308,7 +308,7 @@ public static JsonValue valueOf(Object value) { JsonArray array=new JsonArray(); int length=Array.getLength(value); for (int i=0; i Date: Fri, 11 Feb 2022 13:51:51 -0600 Subject: [PATCH 60/63] Better multiline block comment formatter --- src/main/org/hjson/JsonValue.java | 62 +++++++++++++++------- src/test/org/hjson/test/JsonValueTest.java | 10 +++- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index c22fcb4..026eda2 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -723,29 +723,51 @@ public boolean commentsMatch(JsonValue value) { * @return The formatted, "raw" comment. */ public static String formatComment(CommentStyle style, String comment) { - StringBuilder formatted=new StringBuilder(); + String[] lines=comment.split("\r?\n"); 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]); + return formatBlockComment(lines); + } + StringBuilder formatted=new StringBuilder(); + // 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]); + } + return formatted.toString(); + } + + /** + * Generates the formatted expression of the given text as a block style comment. + * + *

Note that this method will be broken by extraneous new lines in the input.

+ * + * @param lines The previously split string lines for this comment. + * @return The formatted, "raw" comment. + */ + public static String formatBlockComment(String... lines) { + StringBuilder formatted=new StringBuilder(); + if (lines.length==1) { + formatted.append("/* "); + formatted.append(lines[0]); + formatted.append(" */"); + return formatted.toString(); + } + formatted.append("/*"); + formatted.append(eol); + for (String line : lines) { + formatted.append(" * "); + formatted.append(line); + formatted.append(eol); } + formatted.append(" */"); return formatted.toString(); } diff --git a/src/test/org/hjson/test/JsonValueTest.java b/src/test/org/hjson/test/JsonValueTest.java index 2906f1d..e57c083 100644 --- a/src/test/org/hjson/test/JsonValueTest.java +++ b/src/test/org/hjson/test/JsonValueTest.java @@ -14,6 +14,7 @@ void run() { formatComment_generatesBlockComment(); formatComment_generatesMultilineHash(); formatComment_generatesMultilineLine(); + formatComment_generatesMultilineBlock(); stripComment_stripsHashComment(); stripComment_stripsLineComment(); stripComment_stripsBlockComment(); @@ -43,7 +44,7 @@ private void formatComment_generatesLineComment() { private void formatComment_generatesBlockComment() { final String comment = "here's a block comment"; - final String expected = "/*\nhere's a block comment\n*/"; + final String expected = "/* here's a block comment */"; assertEquals(expected, JsonValue.formatComment(CommentStyle.BLOCK, comment)); } @@ -62,6 +63,13 @@ private void formatComment_generatesMultilineLine() { assertEquals(expected, JsonValue.formatComment(CommentStyle.LINE, comment)); } + private void formatComment_generatesMultilineBlock() { + final String comment = "here's a block comment\nwith multiple lines"; + final String expected = "/*\n * here's a block comment\n * with multiple lines\n */"; + + assertEquals(expected, JsonValue.formatComment(CommentStyle.BLOCK, comment)); + } + private void stripComment_stripsHashComment() { final String comment = "# hashed comment"; final String expected = "hashed comment"; From 93f1305a4f853808de177a9261071992b3aa61af Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 19:06:07 -0600 Subject: [PATCH 61/63] Bump tag version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2e772aa..d349ebc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' -version = '3.0.0-C10' +version = '3.0.0-C11' group = 'org.hjson' description = """Hjson, the Human JSON.""" From 68d48ea8496518bc7ceed3979ce2d85bc3320777 Mon Sep 17 00:00:00 2001 From: PersonTheCat Date: Fri, 11 Feb 2022 19:08:17 -0600 Subject: [PATCH 62/63] Fix comment position --- src/main/org/hjson/JsonValue.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/org/hjson/JsonValue.java b/src/main/org/hjson/JsonValue.java index 026eda2..bfb0f83 100644 --- a/src/main/org/hjson/JsonValue.java +++ b/src/main/org/hjson/JsonValue.java @@ -557,6 +557,17 @@ public JsonValue setEOLComment(String comment) { return setComment(CommentType.EOL, CommentStyle.HASH, comment); } + /** + * Shorthand for calling {@link #setComment(CommentType, CommentStyle, String)} which defaults to + * sending an interior comment using the default indicator, #. + * + * @param comment The unformatted comment to be paired with this value. + * @return this, to enable chaining + */ + public JsonValue setInteriorComment(String comment) { + return setComment(CommentType.INTERIOR, CommentStyle.HASH, comment); + } + /** * Shorthand for calling {@link #appendComment(CommentType, CommentStyle, String)} which defaults to * appending a beginning of line comment using the default indicator, # @@ -587,7 +598,7 @@ public JsonValue appendEOLComment(String comment) { * @return this, to enable chaining */ public JsonValue appendInteriorComment(String comment) { - return appendComment(CommentType.EOL, CommentStyle.HASH, comment); + return appendComment(CommentType.INTERIOR, CommentStyle.HASH, comment); } /** @@ -637,7 +648,7 @@ public JsonValue prependEOLComment(String comment) { * @return this, to enable chaining */ public JsonValue prependInteriorComment(String comment) { - return prependComment(CommentType.EOL, CommentStyle.HASH, comment); + return prependComment(CommentType.INTERIOR, CommentStyle.HASH, comment); } /** From a3eb6c306b5f6c990cf7ba9f62b85a01bbd1dc2e Mon Sep 17 00:00:00 2001 From: PersonTheCat <33143148+PersonTheCat@users.noreply.github.com> Date: Thu, 10 Mar 2022 14:45:31 -0600 Subject: [PATCH 63/63] Notice of deprecation PersonTheCat/hjson-java may continue to receive a small amount of support, but has largely been replaced by XJS. --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a912e76..708880f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # PersonTheCat/hjson-java -### Modified version of hjson-java which supports parsing and editing comments in code. +## Notice of deprecation -Note that this repository is currently extremely experimental. I am planning a full rewrite from scratch in the coming months. -This will enable storing whitespace and other formatting info, additional data types, and some miscellaneous moderinizations -to the project to bring it up to spec with Java 8. +This repository is being replaced with a new ecosystem: [XJS](https://github.com/exjson). The new ecosystem will primarily focus on its own syntax and data storage format, but will provide compatibility with Hjson, YAML, JSON-C, and other formats through `xjs-compat`. It is also built from the ground up to support streams, type coercion, and provides a number of other utilities which I believe will make for an extremely convenient experience. If your code is based on this fork of Hjson, I recommend migrating as soon as possible. # hjson-java