AGENTS.md - jsonc-merge Development Guide

๐ŸŽฏ Project Overview

jsonc-merge is a format-specific implementation of the *-merge gem family for JSONC (JSON with Comments) files. It provides intelligent JSONC file merging using AST analysis with tree-sitter JSONC parser.

Core Philosophy: Intelligent JSONC merging that preserves structure, comments, and formatting while applying updates from templates.

Repository: https://github.com/kettle-rb/jsonc-merge
Current Version: 1.0.1
Required Ruby: >= 3.2.0 (currently developed against Ruby 4.0.1)

๐Ÿ—๏ธ Architecture: Format-Specific Implementation

What jsonc-merge Provides

  • Jsonc::Merge::SmartMerger โ€“ JSONC-specific SmartMerger implementation
  • Jsonc::Merge::FileAnalysis โ€“ JSONC file analysis with object/array extraction
  • Jsonc::Merge::NodeWrapper โ€“ Wrapper for JSONC AST nodes
  • Jsonc::Merge::MergeResult โ€“ JSONC-specific merge result
  • Jsonc::Merge::ConflictResolver โ€“ JSONC conflict resolution
  • Jsonc::Merge::FreezeNode โ€“ JSONC freeze block support
  • Jsonc::Merge::DebugLogger โ€“ JSONC-specific debug logging

Key Dependencies

Gem Role
ast-merge (~> 4.0) Base classes and shared infrastructure
tree_haver (~> 5.0) Unified parser adapter (tree-sitter)
version_gem (~> 1.1) Version management

Parser Backend Support

jsonc-merge works with tree-sitter JSONC parser via TreeHaver:

Backend Parser Platform Notes
:mri tree-sitter-jsonc MRI only Best performance, requires native library
:rust tree-sitter-jsonc MRI only Rust implementation via tree_stump
:ffi tree-sitter-jsonc All platforms FFI binding, works on JRuby/TruffleRuby

๐Ÿ“ Project Structure

lib/jsonc/merge/
โ”œโ”€โ”€ smart_merger.rb          # Main SmartMerger implementation
โ”œโ”€โ”€ file_analysis.rb         # JSONC file analysis
โ”œโ”€โ”€ node_wrapper.rb          # AST node wrapper
โ”œโ”€โ”€ merge_result.rb          # Merge result object
โ”œโ”€โ”€ conflict_resolver.rb     # Conflict resolution
โ”œโ”€โ”€ freeze_node.rb           # Freeze block support
โ”œโ”€โ”€ debug_logger.rb          # Debug logging
โ””โ”€โ”€ version.rb

spec/jsonc/merge/
โ”œโ”€โ”€ smart_merger_spec.rb
โ”œโ”€โ”€ file_analysis_spec.rb
โ”œโ”€โ”€ node_wrapper_spec.rb
โ””โ”€โ”€ integration/

๐Ÿ”ง Development Workflows

Running Tests

# Full suite
bundle exec rspec

# Single file (disable coverage threshold check)
K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/jsonc/merge/smart_merger_spec.rb

# Specific backend tests
bundle exec rspec --tag mri_backend
bundle exec rspec --tag rust_backend
bundle exec rspec --tag ffi_backend

Coverage Reports

cd /home/pboling/src/kettle-rb/ast-merge/vendor/jsonc-merge
bin/rake coverage && bin/kettle-soup-cover -d

๐Ÿ“ Project Conventions

API Conventions

SmartMerger API

  • merge โ€“ Returns a String (the merged JSONC content)
  • merge_result โ€“ Returns a MergeResult object
  • to_s on MergeResult returns the merged content as a string

JSONC-Specific Features

Comment Support:

{
  // Line comment
  "key": "value",
  /* Block comment */
  "another": "value"
}

Freeze Blocks:

{
  "config": {
    // jsonc-merge:freeze
    "customValue": "don't override",
    "preserveThis": 42
    // jsonc-merge:unfreeze
  }
}

๐Ÿงช Testing Patterns

TreeHaver Dependency Tags

Available tags:

  • :jsonc_grammar โ€“ Requires JSONC grammar (any backend)
  • :mri_backend โ€“ Requires tree-sitter MRI backend
  • :rust_backend โ€“ Requires tree-sitter Rust backend
  • :ffi_backend โ€“ Requires tree-sitter FFI backend
  • :jsonc_parsing โ€“ Requires any JSONC parser

โœ… CORRECT:

RSpec.describe Jsonc::Merge::SmartMerger, :jsonc_grammar do
  # Skipped if no JSONC parser available
end

โŒ WRONG:

before do
  skip "Requires tree-sitter" unless tree_sitter_available?  # DO NOT DO THIS
end

๐Ÿ’ก Key Insights

  1. JSONC = JSON + Comments: Full comment support unlike plain JSON
  2. Comment preservation: Comments are associated with nodes and preserved during merge
  3. Freeze blocks use // jsonc-merge:freeze: Standard comment syntax
  4. Multi-backend support: Works with MRI, Rust, and FFI backends
  5. Backend isolation is critical: Always use TreeHaver.with_backend

๐Ÿšซ Common Pitfalls

  1. NEVER mix FFI and MRI backends โ€“ Use TreeHaver.with_backend for isolation
  2. NEVER use manual skip checks โ€“ Use dependency tags (:jsonc_grammar, :mri_backend)
  3. Do NOT load vendor gems โ€“ They are not part of this project; they do not exist in CI
  4. Use tmp/ for temporary files โ€“ Never use /tmp or other system directories

๐Ÿ”ง JSONC-Specific Notes

Comment Types

// Single-line comment
/* Multi-line
   comment */
{
  "key": "value" // Trailing comment
}

Merge Behavior

  • Objects: Matched by key name; deep merging of nested objects
  • Arrays: Can be merged or replaced based on preference
  • Comments: Preserved and associated with their nodes
  • Freeze blocks: Protect customizations from template updates