@@ -163,6 +163,11 @@ defmodule Jsonpatch do
163163 @ doc """
164164 Creates a patch from the difference of a source map to a destination map or list.
165165
166+ ## Options
167+
168+ * `:ancestor_path` - Sets the initial ancestor path for the diff operation.
169+ Defaults to `""` (root). Useful when you need to diff starting from a nested path.
170+
166171 ## Examples
167172
168173 iex> source = %{"name" => "Bob", "married" => false, "hobbies" => ["Elixir", "Sport", "Football"]}
@@ -175,20 +180,30 @@ defmodule Jsonpatch do
175180 %{path: "/hobbies/0", value: "Elixir!", op: "replace"},
176181 %{path: "/age", value: 33, op: "add"}
177182 ]
183+
184+ iex> source = %{"a" => 1, "b" => 2}
185+ iex> destination = %{"a" => 3, "c" => 4}
186+ iex> Jsonpatch.diff(source, destination, ancestor_path: "/nested")
187+ [
188+ %{path: "/nested/b", op: "remove"},
189+ %{path: "/nested/c", value: 4, op: "add"},
190+ %{path: "/nested/a", value: 3, op: "replace"}
191+ ]
178192 """
179- @ spec diff ( Types . json_container ( ) , Types . json_container ( ) ) :: [ Jsonpatch . t ( ) ]
180- def diff ( source , destination )
193+ @ spec diff ( Types . json_container ( ) , Types . json_container ( ) , Types . opts_diff ( ) ) :: [ Jsonpatch . t ( ) ]
194+ def diff ( source , destination , opts \\ [ ] ) do
195+ opts = Keyword . validate! ( opts , ancestor_path: "" )
181196
182- def diff ( % { } = source , % { } = destination ) do
183- do_map_diff ( destination , source )
184- end
197+ cond do
198+ is_map ( source ) and is_map ( destination ) ->
199+ do_map_diff ( destination , source , opts [ :ancestor_path ] )
185200
186- def diff ( source , destination ) when is_list ( source ) and is_list ( destination ) do
187- do_list_diff ( destination , source )
188- end
201+ is_list ( source ) and is_list ( destination ) ->
202+ do_list_diff ( destination , source , opts [ :ancestor_path ] )
189203
190- def diff ( _ , _ ) do
191- [ ]
204+ true ->
205+ [ ]
206+ end
192207 end
193208
194209 defguardp are_unequal_maps ( val1 , val2 ) when val1 != val2 and is_map ( val2 ) and is_map ( val1 )
@@ -214,7 +229,7 @@ defmodule Jsonpatch do
214229 patches
215230 end
216231
217- defp do_map_diff ( % { } = destination , % { } = source , ancestor_path \\ "" , patches \\ [ ] ) do
232+ defp do_map_diff ( % { } = destination , % { } = source , ancestor_path , patches \\ [ ] ) do
218233 # entrypoint for map diff, let's convert the map to a list of {k, v} tuples
219234 destination
220235 |> Map . to_list ( )
@@ -245,7 +260,7 @@ defmodule Jsonpatch do
245260 do_map_diff ( rest , source , ancestor_path , patches , [ key | checked_keys ] )
246261 end
247262
248- defp do_list_diff ( destination , source , ancestor_path \\ "" , patches \\ [ ] , idx \\ 0 )
263+ defp do_list_diff ( destination , source , ancestor_path , patches \\ [ ] , idx \\ 0 )
249264
250265 defp do_list_diff ( [ ] , [ ] , _path , patches , _idx ) , do: patches
251266
0 commit comments