SvEx.Plugin.Diff (SvEx v0.4.2)

Compares a meta project against its baseline (SDD R1).

The diff is the feature's definition — observed, never guessed — so this module reports what changed without interpreting it. SvEx.Plugin.Classify decides what each change means.

Summary

Functions

Partitions relative paths into added, modified and removed.

The lines meta_file adds and removes relative to baseline_file, one entry per hunk.

Functions

changes(baseline_dir, meta_dir)

@spec changes(Path.t(), Path.t()) :: %{
  added: [Path.t()],
  modified: [Path.t()],
  removed: [Path.t()]
}

Partitions relative paths into added, modified and removed.

Comparison is by content hash from SvEx.Baseline.tree/1, which prunes .git, deps and _build and placeholders phx.new's random secrets, so a regenerated meta project does not read as drift.

hunks(baseline_file, meta_file)

@spec hunks(Path.t(), Path.t()) :: [
  %{anchor: [binary()], lines: [binary()], removed: [binary()]}
]

The lines meta_file adds and removes relative to baseline_file, one entry per hunk.

Each carries the lines added, the removed lines they replace, and the anchor they followed — up to three preceding lines of unchanged text. Three, not one: a single line of context is routinely ambiguous in Elixir source, where end and a docstring's closing delimiter repeat within one file, and placing against an ambiguous anchor puts code in the wrong place silently. anchor is [] for a hunk at the start of a file.

A deletion is HELD rather than emitted, because Myers writes a replacement as {:del, old} immediately followed by {:ins, new} and the two halves belong in one hunk. A deletion followed by anything else — unchanged text, or the end of the diff — becomes a hunk of its own with lines: []. Nothing is discarded: dropping {:del, _} is what let a REWRITTEN file classify as :contributes and apply as an append, producing a file holding both the old content and the new while reporting :ok.

A deletion does not advance the context, so a replacement anchors on the unchanged text that preceded what it replaced.

Indentation is preserved deliberately: it is what tells a top-level block from an insertion inside an existing literal.