Skip to content

feat: add sync operation that diffs and patches minimally#29

Merged
nathanjmcdougall merged 8 commits into
mainfrom
25-add-a-syncapply-dict-operation-that-diffs-and-patches-minimally
May 19, 2026
Merged

feat: add sync operation that diffs and patches minimally#29
nathanjmcdougall merged 8 commits into
mainfrom
25-add-a-syncapply-dict-operation-that-diffs-and-patches-minimally

Conversation

@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

Summary

Adds a sync method to Document and Editor that takes a desired Python value, diffs it against the current document content at a given path, and applies the minimal set of patches — preserving comments and formatting.

# Sync a mapping — adds missing keys, removes extra keys, updates changed values
doc2 = doc.sync('ci', value={'autofix_prs': False, 'skip': ['codespell']})

# Sync a list — uses SequenceMatcher for minimal edits
doc2 = doc.sync('repos', value=new_repos)

# No-op — returns self when value already matches
doc2 = doc.sync('ci', value=doc['ci'])
assert doc2 is doc

Design

  • Pure Python implementation on top of existing Document primitives
  • Recursive diff: mappings diffed key-by-key, lists diffed with difflib.SequenceMatcher
  • New module src/yamltrip/sync.py contains the diff logic
  • Document.sync() returns a new Document; Editor.sync() mutates in place
  • Returns self on no-op (identity preservation)
  • Missing paths created via upsert; type mismatches handled via replace

Test coverage

30 new tests covering:

  • Mapping add/remove/change (including nested)
  • List append/remove/replace/insert
  • Comment preservation on both mappings and lists
  • Edge cases: empty values, null, type mismatches, missing paths, root-level sync
  • Editor integration
  • Real-world pre-commit config scenario

Future work

  • key parameter for identity-based list matching (deferred per YAGNI)
  • Key reordering within mappings

Closes #25

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a sync operation to Document and Editor that diffs a desired Python value against the current document content at a given path and applies the minimal set of patches, preserving comments and formatting. Implements recursive mapping diffs and SequenceMatcher-based list diffs in a new yamltrip.sync module. Closes #25.

Changes:

  • New src/yamltrip/sync.py with _compute_patches and helpers for mapping/list/scalar diffing.
  • Document.sync() and Editor.sync() methods, with KeyPart extracted to a new shared _types module and import-linter layers updated accordingly.
  • 30 new tests in tests/test_sync.py and a design spec under doc/specs/.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/yamltrip/sync.py New module implementing recursive diff logic for mappings, lists (via SequenceMatcher with index-offset tracking), scalars, and type-mismatch fallback.
src/yamltrip/document.py Adds Document.sync(); delegates to upsert when path missing, returns self on no-op; switches KeyPart to import from _types.
src/yamltrip/editor.py Adds Editor.sync() thin wrapper; updates KeyPart import.
src/yamltrip/_types.py New module exposing the shared KeyPart type alias.
.importlinter Adds sync layer and _types ignore; allows yamltrip.sync -> yamltrip.
tests/test_sync.py 30 tests covering mapping/list add/remove/change, nested cases, comment preservation, type mismatch, empty/null values, path creation, Editor integration, and a pre-commit-style scenario.
doc/specs/2026-05-20-sync-operation-design.md Design document for the sync operation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@nathanjmcdougall nathanjmcdougall merged commit 9dcc3c7 into main May 19, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a sync/apply-dict operation that diffs and patches minimally

2 participants