internal static IEnumerable <Operation> CalculatePatch(JToken left, JToken right, bool useIdToDetermineEquality, string path = "") { if (left.Type != right.Type) { yield return(JsonDiffer.Replace(path, "", right)); yield break; } if (left.Type == JTokenType.Array) { Operation prev = null; foreach (var operation in ProcessArray(left, right, path, useIdToDetermineEquality)) { var add = operation as AddOperation; if (prev is RemoveOperation prevRemove && add != null && add.Path == prevRemove.Path) { yield return(Replace(add.Path, "", add.Value)); prev = null; } else { if (prev != null) { yield return(prev); } prev = operation; } }
internal static IEnumerable <Operation> CalculatePatch(JToken left, JToken right, bool useIdToDetermineEquality, string path = "") { if (left.Type != right.Type) { yield return(JsonDiffer.Replace(path, "", right)); yield break; } if (left.Type == JTokenType.Array) { Operation prev = null; foreach (var operation in ProcessArray(left, right, path, useIdToDetermineEquality)) { var prevRemove = prev as RemoveOperation; var add = operation as AddOperation; if (prevRemove != null && add != null && add.Path == prevRemove.Path) { yield return(Replace(add.Path, "", add.Value)); prev = null; } else { if (prev != null) { yield return(prev); } prev = operation; } } if (prev != null) { yield return(prev); } } else if (left.Type == JTokenType.Object) { var lprops = ((IDictionary <string, JToken>)left).OrderBy(p => p.Key); var rprops = ((IDictionary <string, JToken>)right).OrderBy(p => p.Key); foreach (var removed in lprops.Except(rprops, MatchesKey.Instance)) { yield return(JsonDiffer.Remove(path, removed.Key)); } foreach (var added in rprops.Except(lprops, MatchesKey.Instance)) { yield return(JsonDiffer.Add(path, added.Key, added.Value)); } var matchedKeys = lprops.Select(x => x.Key).Intersect(rprops.Select(y => y.Key)); var zipped = matchedKeys.Select(k => new { key = k, left = left[k], right = right[k] }); foreach (var match in zipped) { string newPath = path + "/" + match.key; foreach (var patch in CalculatePatch(match.left, match.right, useIdToDetermineEquality, newPath)) { yield return(patch); } } yield break; } else { // Two values, same type, not JObject so no properties if (left.ToString() == right.ToString()) { yield break; } else { yield return(JsonDiffer.Replace(path, "", right)); } } }