@@ -19,12 +19,15 @@ A Git-aware conflict resolver for **JSON-first structured data**.
19
19
## Features
20
20
21
21
- ⚡ ** Primary focus on JSON** (first-class support)
22
- - 🔄 ** YAML, XML, TOML** supported via conversion
23
- - 🧩 ** Rule-based strategies** (per path/pattern)
24
- - 🗂️ Handles small configs to ** huge repos** (optimizations built-in)
25
- - 🔌 ** Pluggable matcher** abstraction (picomatch, micromatch supported out of the box with peerDependency)
26
- - 🛠️ Configurable trade-offs for ** speed vs. memory**
27
- - 🗃️ ** Planned** : extend configuration to use ** different strategies per file** (ideas and edge cases welcome!)
22
+ - 🔄 ** YAML, XML, TOML, JSON5** supported via conversion
23
+ - 🧩 ** Rule-based strategies** with path/pattern matching
24
+ - 📁 ** Multiple file parallel processing** with include/exclude patterns
25
+ - 🔌 ** Pluggable matcher** abstraction (picomatch, micromatch, or custom)
26
+ - 🛠️ ** CLI and programmatic API** support
27
+ - 📝 ** Conflict sidecar files** for unresolved conflicts
28
+ - 🔄 ** Backup and restore** functionality
29
+ - 📊 ** Configurable logging** (memory or file-based)
30
+ - 🔀 ** Git merge driver** support for seamless Git integration
28
31
29
32
## Installation
30
33
@@ -46,6 +49,24 @@ yarn add git-json-resolver
46
49
47
50
## Quick Start
48
51
52
+ ### CLI Usage
53
+
54
+ ``` bash
55
+ # Initialize config file
56
+ npx git-json-resolver --init
57
+
58
+ # Run with default config
59
+ npx git-json-resolver
60
+
61
+ # Run with options
62
+ npx git-json-resolver --include " **/*.json" --debug --sidecar
63
+
64
+ # Restore from backups
65
+ npx git-json-resolver --restore .merge-backups
66
+ ```
67
+
68
+ ### Git Integration
69
+
49
70
Add a custom merge driver to your Git config:
50
71
51
72
``` bash
@@ -57,73 +78,172 @@ Update `.gitattributes` to use it for JSON files:
57
78
58
79
``` gitattributes
59
80
*.json merge=json-resolver
81
+ *.yaml merge=json-resolver
82
+ *.yml merge=json-resolver
83
+ *.toml merge=json-resolver
84
+ *.xml merge=json-resolver
60
85
```
61
86
62
- ## Example Config
87
+ ** How it works:**
88
+
89
+ - Git automatically calls the merge driver during conflicts
90
+ - Uses same configuration and strategies as CLI mode
91
+ - Supports 3-way merge (ours, base, theirs)
92
+ - Returns proper exit codes (0 = success, 1 = conflicts)
93
+
94
+ ## Configuration
95
+
96
+ ### Programmatic API
63
97
64
98
``` ts
65
99
import { resolveConflicts } from " git-json-resolver" ;
66
100
67
- const result = resolveConflicts ({
68
- filePath: " package.json" ,
69
- rules: [
70
- { pattern: " dependencies.*" , strategy: " ours" },
71
- { pattern: " version" , strategy: " theirs" , important: true },
72
- { pattern: " scripts.build" , strategy: " manual" },
73
- ],
74
- matcher: " picomatch" , // default
75
- optimize: {
76
- cacheMatchers: true ,
77
- streamMode: false , // set true for very large repos
101
+ await resolveConflicts ({
102
+ defaultStrategy: [" merge" , " ours" ],
103
+ rules: {
104
+ " dependencies.*" : [" ours" ],
105
+ version: [" theirs!" ], // ! marks as important
106
+ " scripts.build" : [" skip" ],
78
107
},
108
+ include: [" **/*.json" , " **/*.yaml" ],
109
+ exclude: [" **/node_modules/**" ],
110
+ matcher: " picomatch" ,
111
+ debug: true ,
112
+ writeConflictSidecar: true ,
113
+ backupDir: " .merge-backups" ,
79
114
});
80
115
```
81
116
82
- ### Upcoming: File-Specific Strategies
83
-
84
- We are exploring the ability to define ** per-file strategy sets** in config, e.g.:
85
-
86
- ``` ts
87
- rulesByFile : {
88
- " package.json" : { version: [" theirs" ], dependencies: [" ours" ] },
89
- " *.config.json" : { " *" : [" merge" ] },
90
- },
117
+ ### Config File (` git-json-resolver.config.js ` )
118
+
119
+ ``` js
120
+ module .exports = {
121
+ defaultStrategy: [" merge" , " ours" ],
122
+ rules: {
123
+ // Exact path matching
124
+ " package.json" : {
125
+ version: [" theirs!" ],
126
+ dependencies: [" ours" ],
127
+ },
128
+ // Pattern matching
129
+ " *.config.json" : {
130
+ " *" : [" merge" ],
131
+ },
132
+ },
133
+ // Alternative: byStrategy format
134
+ byStrategy: {
135
+ ours: [" dependencies.*" , " devDependencies.*" ],
136
+ " theirs!" : [" version" , " name" ],
137
+ },
138
+ include: [" **/*.json" , " **/*.yaml" , " **/*.yml" ],
139
+ exclude: [" **/node_modules/**" , " **/dist/**" ],
140
+ matcher: " picomatch" ,
141
+ debug: false ,
142
+ writeConflictSidecar: false ,
143
+ loggerConfig: {
144
+ mode: " memory" , // or "stream"
145
+ logDir: " logs" ,
146
+ levels: {
147
+ stdout: [" warn" , " error" ],
148
+ file: [" info" , " warn" , " error" ],
149
+ },
150
+ },
151
+ };
91
152
```
92
153
93
- This raises interesting questions/edge cases:
94
-
95
- - How to merge file-level vs. global rules?
96
- - Should ` include/exclude ` still apply if a file is explicitly listed?
97
- - Should conflicting rules between file + global fall back to default strategy or error?
98
-
99
- We welcome ideas & edge cases here!
100
-
101
154
## Supported Strategies
102
155
156
+ - ** merge** → deep merge objects/arrays where possible
103
157
- ** ours** → take current branch value
104
158
- ** theirs** → take incoming branch value
105
- - ** manual** → mark for human resolution
106
- - ** drop** → remove the key entirely
107
- - ** custom** → user-defined resolver function
159
+ - ** base** → revert to common ancestor
160
+ - ** skip** → leave unresolved (creates conflict entry)
161
+ - ** drop** → remove the field entirely
162
+ - ** non-empty** → prefer non-empty value (ours > theirs > base)
163
+ - ** update** → update with theirs if field exists in ours
164
+ - ** concat** → concatenate arrays from both sides
165
+ - ** unique** → merge arrays and remove duplicates
166
+ - ** custom** → user-defined resolver functions
167
+
168
+ ### Strategy Priority
169
+
170
+ - Strategies marked with ` ! ` (important) are applied first
171
+ - Multiple strategies can be specified as fallbacks
172
+ - Custom strategies can be defined via ` customStrategies ` config
108
173
109
174
## Supported Formats
110
175
111
176
- ** JSON** (native)
112
- - ** YAML, XML, TOML** → converted to JSON → resolved → converted back
177
+ - ** JSON5** → via ` json5 ` peer dependency
178
+ - ** YAML** → via ` yaml ` peer dependency
179
+ - ** TOML** → via ` smol-toml ` peer dependency
180
+ - ** XML** → via ` fast-xml-parser ` peer dependency
181
+
182
+ All non-JSON formats are converted to JSON → resolved → converted back to original format.
183
+
184
+ ## CLI Options
185
+
186
+ ``` bash
187
+ # File patterns
188
+ --include " **/*.json,**/*.yaml" # Comma-separated patterns
189
+ --exclude " **/node_modules/**" # Exclusion patterns
190
+
191
+ # Matcher selection
192
+ --matcher picomatch # picomatch, micromatch, or custom
193
+
194
+ # Debug and logging
195
+ --debug # Enable verbose logging
196
+ --sidecar # Write conflict sidecar files
197
+
198
+ # Utilities
199
+ --init # Create starter config file
200
+ --restore .merge-backups # Restore from backup directory
201
+ ```
113
202
114
- ## Performance & Optimization
203
+ ## Architecture
115
204
116
- - ** Matcher caching** for repeated patterns
117
- - ** Streaming mode** for very large repos (low memory footprint)
118
- - Trade-offs are configurable via ` optimize ` field
205
+ - ** Modular design** : Separate concerns (parsing, merging, serialization)
206
+ - ** Reusable utilities** : Common merge logic extracted for maintainability
207
+ - ** Optimized bundle** : Constants over enums for better minification
208
+ - ** Comprehensive testing** : Full test coverage with vitest
209
+ - ** Type-safe** : Full TypeScript support with proper type inference
210
+
211
+ ## Advanced Features
212
+
213
+ ### Pattern Matching
214
+
215
+ - ** Exact paths** : ` "package.json" ` , ` "src.config.database.host" `
216
+ - ** Field matching** : ` "[version]" ` → matches any ` version ` field
217
+ - ** Glob patterns** : ` "dependencies.*" ` , ` "**.config.**" `
218
+ - ** Wildcards** : ` "*.json" ` , ` "src/**/*.config.js" `
219
+
220
+ ### Custom Strategies
221
+
222
+ ``` ts
223
+ import { StrategyStatus } from " git-json-resolver" ;
224
+
225
+ const config = {
226
+ customStrategies: {
227
+ " semantic-version" : ({ ours , theirs }) => {
228
+ // Custom logic for semantic version resolution
229
+ if (isNewerVersion (theirs , ours )) {
230
+ return { status: StrategyStatus .OK , value: theirs };
231
+ }
232
+ return { status: StrategyStatus .CONTINUE };
233
+ },
234
+ },
235
+ rules: {
236
+ version: [" semantic-version" , " theirs" ],
237
+ },
238
+ };
239
+ ```
119
240
120
- ## Roadmap
241
+ ### Logging & Debugging
121
242
122
- - [ ] Richer strategies via plugins (e.g., semantic version resolver)
123
- - [ ] CLI UX improvements
124
- - [ ] Pluggable format converters customizations
125
- - [ ] VSCode integration for previewing merge resolutions
126
- - [ ] ** Per-file strategies support** (current RFC)
243
+ - ** Memory mode** : Fast, in-memory logging
244
+ - ** Stream mode** : File-based logging for large operations
245
+ - ** Per-file logs** : Separate log files for each processed file
246
+ - ** Debug mode** : Detailed conflict information and strategy traces
127
247
128
248
## Contributing
129
249
0 commit comments