Skip to content

Commit

Permalink
Reformat docs; minor fixes (#244)
Browse files Browse the repository at this point in the history
Co-authored-by: Gene Gleyzer <[email protected]>
Co-authored-by: Jonathan Knight <[email protected]>
  • Loading branch information
3 people authored Dec 31, 2024
1 parent f87fa95 commit 7b09e59
Show file tree
Hide file tree
Showing 9 changed files with 557 additions and 165 deletions.
16 changes: 8 additions & 8 deletions lib_json/src/main/x/json/JsonArrayBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class JsonArrayBuilder
/**
* Create a JSON array builder.
*
* @param template an optional `JsonArray` to use to populate
* the builder with an initial set of values
* @param factory a factory to create a new mutable `JsonArray`
* @param template (optional) an optional `JsonArray` to use to populate the builder with an
* initial set of values
* @param factory (optional) a factory to create a new mutable `JsonArray`
*/
construct(JsonArray? template = Null, Factory factory = () -> json.newArray()) {
this.factory = factory;
values = new Array();
this.values = new Array();
if (template.is(JsonArray)) {
values.addAll(template);
}
Expand Down Expand Up @@ -136,8 +136,8 @@ class JsonArrayBuilder
/**
* Merge a `JsonObject` into the array.
*
* All of the `JsonObject` keys must be strings that are integer literals
* in the range between zero and the current size of the array being built.
* All of the `JsonObject` keys must be strings that are integer literals in the range between
* zero and the current size of the array being built.
*/
@Override
protected void mergeObject(JsonObject o) {
Expand All @@ -147,8 +147,8 @@ class JsonArrayBuilder
Int? index = pointer.index;
assert index != Null as "Cannot merge JSON Object with non-Int keys into a JSON array";
assert 0 <= index < values.size as
$|Cannot merge JSON Object into JSON array - key\
| "{entry.key}" does not match an existing array entry in the range 0..<{values.size}
$|Cannot merge JSON Object into JSON array - key "{entry.key}" does not match \
|an existing array entry in the range 0..<{values.size}
;
map.put(pointer, entry.value);
}
Expand Down
97 changes: 47 additions & 50 deletions lib_json/src/main/x/json/JsonBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
@Abstract protected Id id(JsonPointer path);

/**
* Merge the specified `Doc` into the entry in this builder
* with the specified `Id`.
* Merge the specified `Doc` into the entry in this builder with the specified `Id`.
*
* The exact behaviour and merge rules will differ depending on the
* type of JSON value the builder builds.
* The exact behaviour and merge rules will differ depending on the type of JSON value the
* builder builds.
*/
@Abstract protected void merge(Id id, Doc doc);

Expand All @@ -41,30 +40,29 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
/**
* Return the `Doc` value the builder contains for the specified `Id`.
*
* As a `Doc` type can be `Null`, if there is no entry contained in the
* builder for the specified `Id` then a `Null` value will be returned,
* which is a valid `Doc` value.
* As a `Doc` type can be `Null`, if there is no entry contained in the builder for the
* specified `Id` then a `Null` value will be returned, which is a valid `Doc` value.
*/
@Abstract protected Doc get(Id id);

/**
* Perform a deep merge of the specified JSON structure with
* the JSON structure this builder is building.
* Perform a deep merge of the specified JSON structure with the JSON structure this builder is
* building.
*
* How the merge is performed will differ depending on the type of
* structure passed in and the structure being built.
* How the merge is performed will differ depending on the type of structure passed in and the
* structure being built.
*
* @param the `JsonStruct` to merge
* @param jsonStruct the `JsonStruct` to merge
*
* @return this `JsonBuilder`
*/
JsonBuilder deepMerge(JsonStruct s) {
switch (s.is(_)) {
JsonBuilder deepMerge(JsonStruct jsonStruct) {
switch (jsonStruct.is(_)) {
case JsonObject:
mergeObject(s);
mergeObject(jsonStruct);
break;
case JsonArray:
mergeArray(s);
mergeArray(jsonStruct);
break;
default:
assert;
Expand All @@ -88,13 +86,14 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
Doc existing = get(id);
switch (existing.is(_)) {
case JsonObject:
mergeObjectMember(existing, path, doc, id);
mergeIntoObjectMember(existing, path, doc, id);
break;
case JsonArray:
mergeArrayMember(existing, path, doc, id);
mergeIntoArrayMember(existing, path, doc, id);
break;
case Primitive:
mergePrimitiveMember(existing, path, doc, id);
// existing is a primitive so it cannot be merged into and is instead replaced
replaceMember(path, doc, id);
break;
default:
assert;
Expand All @@ -104,66 +103,64 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
}

/**
* Deeply merge the entries in a `JsonObject` into the JSON value being
* produced by this builder.
* Deeply merge the entries in a `JsonObject` into the JSON value being produced by this builder.
*
* @param o the `JsonObject` to merge
* @param jsonObj the `JsonObject` to merge
*/
protected void mergeObject(JsonObject o) {
for (Map.Entry<String, Doc> entry : o.entries) {
protected void mergeObject(JsonObject jsonObj) {
for (Map.Entry<String, Doc> entry : jsonObj.entries) {
deepMerge(JsonPointer.from(entry.key), entry.value);
}
}

/**
* Deeply merge a `JsonObject` value into this builder.
* Deeply merge a JSON value into a `JsonObject` in this builder.
*
* @param p the `JsonObject` to merge
* @param path the path to the location the object value should be merged into
* @param doc the value to merge the object into
* @param obj the `JsonObject` to merge into
* @param path the path to the location the `Doc` value should be merged into
* @param doc the JSON value to merge into the `JsonObject`
* @param id the id of the entry being merged into
*/
protected void mergeObjectMember(JsonObject o, JsonPointer path, Doc doc, Id id) {
protected void mergeIntoObjectMember(JsonObject obj, JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonObject updated = new JsonObjectBuilder(o).deepMerge(remainder, doc).build();
JsonObject updated = new JsonObjectBuilder(obj).deepMerge(remainder, doc).build();
update(id, updated);
}

/**
* Deeply merge the entries in a `JsonArray` into the JSON value being
* produced by this builder.
*
* @param a the `JsonArray` to merge
* @param array the `JsonArray` to merge
*/
protected void mergeArray(JsonArray a) {
for (Int i : 0 ..< a.size) {
deepMerge(JsonPointer.from(i.toString()), a[i]);
protected void mergeArray(JsonArray array) {
for (Int i : 0 ..< array.size) {
deepMerge(JsonPointer.from(i.toString()), array[i]);
}
}

/**
* Deeply merge a `JsonArray` value into this builder.
* Deeply merge a JSON value into a `JsonArray` value in this builder.
*
* @param a the `JsonArray` to merge
* @param path the path to the location the array value should be merged into
* @param doc the value to merge the array into
* @param id the id of the entry being merged into
* @param array the `JsonArray` to merge into
* @param path the path to the location the JSON value should be merged into
* @param doc the JSON value to merge the into the `JsonArray`
* @param id the id of the entry being merged into
*/
protected void mergeArrayMember(JsonArray a, JsonPointer path, Doc doc, Id id) {
protected void mergeIntoArrayMember(JsonArray array, JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonArray updated = new JsonArrayBuilder(a).deepMerge(remainder, doc).build();
JsonArray updated = new JsonArrayBuilder(array).deepMerge(remainder, doc).build();
update(id, updated);
}

/**
* Deeply merge a `Primitive` value into this builder.
* Replace a value in this builder with a specified value.
*
* @param p the `Primitive` to merge
* @param path the path to the location the primitive value should be merged into
* @param doc the value to merge the primitive into
* @param id the id of the entry being merged into
* @param path the path to the location of the value to replace
* @param doc the JSON value to replace any existing value with
* @param id the id of the entry being replaced
*/
protected void mergePrimitiveMember(Primitive p, JsonPointer path, Doc doc, Id id) {
protected void replaceMember(JsonPointer path, Doc doc, Id id) {
JsonPointer remainder = path.remainder ?: assert;
JsonObject updated = new JsonObjectBuilder().deepMerge(remainder, doc).build();
update(id, updated);
Expand Down Expand Up @@ -205,13 +202,13 @@ class JsonBuilder<JsonType extends JsonStruct, Id extends Int | String> {
/**
* Perform a deep copy of the specified JSON array.
*
* @param o the JSON array to copy
* @param array the JSON array to copy
*
* @return a mutable copy of the JSON array
*/
static JsonArray deepCopyArray(JsonArray a) {
static JsonArray deepCopyArray(JsonArray array) {
JsonArray copy = json.newArray();
for (Doc doc : a) {
for (Doc doc : array) {
copy.add(deepCopy(doc));
}
return copy;
Expand Down
87 changes: 64 additions & 23 deletions lib_json/src/main/x/json/JsonMergePatch.x
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* An implementation of a JSON Merge Patch as specified
* in [RFC7396](http://tools.ietf.org/html/rfc7396).
* An implementation of a JSON Merge Patch as specified in
* [JSON Merge Patch specification](http://tools.ietf.org/html/rfc7396).
*
* @param patch the JSON value to apply as a merge patch
*/
class JsonMergePatch(Doc patch) {

/**
* @return True iff this patch is empty, i.e. it will not apply any
* `True` iff this patch is empty, i.e. it will not apply to any.
*/
Boolean empty.get() {
Doc patch = this.patch;
Expand All @@ -21,41 +21,82 @@ class JsonMergePatch(Doc patch) {
* Apply this patch to the specified target.
*
* @param target the JSON value to apply this patch to
* @param inPlace True to modify the target in place (if applicable), or
* False to leave the target unmodified and return a patched
* copy of the target
* @param inPlace (optional) `True` to modify the target in place (if applicable), or `False`
* to leave the target unmodified and return a patched copy of the target
*
* @return the JSON value resulting from applying this patch to the target
*/
Doc apply(Doc target, Boolean inPlace = False) {
return merge(target, patch);
return merge(target, patch, inPlace);
}

/**
* Perform a merge as described by the pseudo code in RFC 7396.
*
* define MergePatch(Target, Patch):
* if Patch is an Object:
* if Target is not an Object:
* Target = {} # Ignore the contents and set it to an empty Object
* for each Name/Value pair in Patch:
* if Value is null:
* if Name exists in Target:
* remove the Name/Value pair from Target
* else:
* Target[Name] = MergePatch(Target[Name], Value)
* return Target
* else:
* return Patch
*
* * If the `patch` parameter is not a `JsonObject` the `patch` parameter is returned as the result.
*
* * If the target `Doc` is not a `JsonObject` it is ignored and the merge will be applied to
* a new empty `JsonObject`.
*
* * If the target `Doc` is a mutable `JsonObject` and the `inPlace` parameter is `True` the merge will be
* applied directly to the target.
*
* * A `Null` value for a key in the `patch` will cause the corresponding entry in the target to be removed.
* Any `Null` value in the `patch` will not appear in the merged result.
*
* @param doc that target JSON value to apply the patch to
* @param patch the JSON value representing the patch to apply
* @param inPlace (optional) `True` to modify the target in place (if applicable), or `False`
* to leave the target unmodified and return a patched copy of the target
*
* @return the JSON value resulting from applying this patch to the target
*/
private Doc merge(Doc doc, Doc patch, Boolean inPlace = False) {
if (patch.is(JsonObject)) {
JsonObject target;

if (doc.is(JsonObject)) {
target = doc;
if (doc.is(immutable) || !inPlace) {
// we can make in place true as we are making a new target so there is
// no point continually copying target elements from here on
inPlace = True;
target = json.newObject();
target.putAll(doc);
} else {
target = doc;
}
} else {
target = json.newObject();
// we can make in place true as we are making a new target so there is
// no point continually copying target elements from here on
inPlace = True;
target = json.newObject();
}

JsonObjectBuilder builder = new JsonObjectBuilder(target);
for (Map.Entry<String, Doc> entry : patch.entries) {
String key = entry.key;
Doc value = entry.value;
for ((String key, Doc value) : patch) {
if (value == Null) {
target.remove(key);
} else {
if (Doc targetValue := target.get(key)) {
merge(key, merge(targetValue, value, inPlace));
} else {
merge(key, merge(json.newObject(), value, True));
}
target[key] = merge(target[key], value, inPlace);
}
}
return builder.build();
if (doc.is(immutable)) {
// The mutability of the result will match the mutability of the original doc parameter
target.makeImmutable();
}
return target;
}
return patch;
}
Expand All @@ -73,10 +114,10 @@ class JsonMergePatch(Doc patch) {
}

/**
* Generate a JSON Merge Patch from the source and target {@code JsonValue}.
* Generate a JSON Merge Patch from the source and target `JsonValue`.
*
* @param source the source
* @param target the target
* @param source the source
* @param target the target
*
* @return a JSON Patch which when applied to the source, yields the target
*/
Expand Down
10 changes: 5 additions & 5 deletions lib_json/src/main/x/json/JsonObjectBuilder.x
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class JsonObjectBuilder
/**
* Create a JSON object builder.
*
* @param template an optional `Map<String, Doc>` to use to populate
* the builder with an initial set of values
* @param factory a factory to create a new mutable `JsonArray`
* @param template (optional) an optional `Map<String, Doc>` to use to populate the builder
* with an initial set of values
* @param factory (optional) a factory to create a new mutable `JsonArray`
*/
construct(JsonObject? template = Null, Factory factory = () -> json.newObject()) {
this.factory = factory;
Expand Down Expand Up @@ -63,7 +63,7 @@ class JsonObjectBuilder
JsonObjectBuilder add(String key, JsonBuilder builder) = add(key, builder.build());

/**
* Add all the values contained in the `Map`
* Add all the values contained in the `Map`.
*
* @param map the map of values to add
*
Expand All @@ -75,7 +75,7 @@ class JsonObjectBuilder
}

/**
* Add all the values contained in the `JsonObject`
* Add all the values contained in the `JsonObject`.
*
* @param map the map of values to add
*
Expand Down
Loading

0 comments on commit 7b09e59

Please sign in to comment.