Helper functions for document version history and diffing.
Provides utilities for computing structural diffs between TipTap JSON documents, generating human-readable change summaries, formatting version timestamps, grouping versions by day, and calculating word count deltas.
Summary
Functions
Compute a structural diff between two TipTap JSON documents.
Generate a human-readable summary of changes from a diff result.
Format a version timestamp for display.
Group versions by day for timeline display.
Calculate word count delta between two versions as a display string.
Functions
Compute a structural diff between two TipTap JSON documents.
Compares the top-level "content" arrays node-by-node and returns a list
of change maps describing additions, removals, and modifications.
Return shape
[%{type: :added | :removed | :modified, path: [integer()], ...}]Examples
iex> old = %{"content" => [%{"type" => "paragraph", "text" => "Hello"}]}
iex> new = %{"content" => [%{"type" => "paragraph", "text" => "Hello"}, %{"type" => "paragraph", "text" => "World"}]}
iex> VersionHelpers.diff_documents(old, new)
[%{type: :added, path: [1], content: %{"type" => "paragraph", "text" => "World"}}]
Generate a human-readable summary of changes from a diff result.
Examples
iex> VersionHelpers.diff_summary([%{type: :added}, %{type: :removed}])
"1 added, 1 removed"
iex> VersionHelpers.diff_summary([])
"No changes"
@spec format_version_date(DateTime.t() | NaiveDateTime.t() | nil) :: String.t()
Format a version timestamp for display.
Returns a human-readable date string such as "March 19, 2026 at 02:30 PM".
Examples
iex> VersionHelpers.format_version_date(nil)
""
iex> VersionHelpers.format_version_date(~U[2026-03-19 14:30:00Z])
"March 19, 2026 at 02:30 PM"
Group versions by day for timeline display.
Takes a list of version maps (with :created_at or "created_at" key)
and returns a list of {date, versions} tuples sorted by date descending.
Examples
iex> versions = [%{created_at: ~U[2026-03-19 10:00:00Z]}, %{created_at: ~U[2026-03-18 09:00:00Z]}]
iex> VersionHelpers.group_versions_by_day(versions)
[{~D[2026-03-19], [%{created_at: ~U[2026-03-19 10:00:00Z]}]}, {~D[2026-03-18], [%{created_at: ~U[2026-03-18 09:00:00Z]}]}]
Calculate word count delta between two versions as a display string.
Examples
iex> VersionHelpers.word_count_delta(100, 120)
"+20"
iex> VersionHelpers.word_count_delta(100, 80)
"-20"
iex> VersionHelpers.word_count_delta(100, 100)
"0"