json-merge 1.1.2 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,45 +1,61 @@
1
- [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-rb Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-rb-i]][🖼️kettle-rb]
2
-
3
- [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
4
- [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
5
- [🖼️ruby-lang-i]: https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg
6
- [🖼️ruby-lang]: https://www.ruby-lang.org/
7
- [🖼️kettle-rb-i]: https://logos.galtzo.com/assets/images/kettle-rb/avatar-192px.svg
8
- [🖼️kettle-rb]: https://github.com/kettle-rb
1
+ <a href="https://github.com/structuredmerge"><img alt="structuredmerge Logo by GitHub" src="https://github.com/structuredmerge.png?size=192" width="14%" align="right"/></a>
9
2
 
10
3
  # ☯️ Json::Merge
11
4
 
12
- [![Version][👽versioni]][👽dl-rank] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
5
+ [![Version][👽versioni]][👽version] [![Ruby Users Forum][✉️ruby-forum-top-img]][✉️ruby-forum] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Total downloads][👽dl-ranki]][👽dl-rank] [![CI Current][🚎11-c-wfi]][🚎11-c-wf]
13
6
 
14
- `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know on Discord][✉️discord-invite] or [RubyForum][✉️ruby-forum], as I may have missed the notification.
15
8
 
16
- -----
9
+ ---
17
10
 
18
11
  `if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
19
12
 
20
- [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
13
+ [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
21
14
 
22
- <details>
23
- <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
15
+ <details markdown="1">
16
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
24
17
 
25
18
  I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
26
19
 
27
20
  </details>
28
21
 
29
- ## 🌻 Synopsis
22
+ ## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
23
+
24
+ Json::Merge intelligently merges two versions of a JSON, JSONC, or JSON5 file using the StructuredMerge Ruby stack. It is built on [ast-merge][ast-merge] and [tree_haver][tree_haver], with parser capability reported through the shared backend registry.
25
+
26
+ JSONC and JSON5 use the same `Json::Merge` API as JSON; use `require "json/merge"` for all three dialects.
27
+
28
+ ### JSONC Support
29
+
30
+ The JSON merge provider supports JSON, JSONC, and JSON5 dialects through `Json::Merge`. Pass JSONC content to the same merger API used for JSON.
30
31
 
31
- Json::Merge is a standalone Ruby module that intelligently merges two versions of a JSON file using tree-sitter AST analysis. It's like a smart "git merge" specifically designed for JSON configuration files. Built on top of [ast-merge][ast-merge], it shares the same architecture as [prism-merge][prism-merge] for Ruby source files.
32
+ JSONC-specific behavior:
32
33
 
33
- For JSONC (JSON with Comments) support, see the [jsonc-merge][jsonc-merge] gem.
34
+ - **Single API**: JSON and JSONC both use `Json::Merge`
35
+ - **Comment-Aware**: Preserves `//` and `/* */` comments when the parser exposes them
36
+ - **Trailing Commas**: Accepts trailing commas in JSONC objects and arrays
37
+ - **JSONC Boundaries**: Rejects JSON5-only syntax such as unquoted keys,
38
+ single-quoted strings, and JSON5 numeric literals
39
+ - **Freeze Blocks**: Uses the `json-merge` freeze token by default, with a custom token available when needed
40
+
41
+ ### JSON5 Support
42
+
43
+ JSON5 uses the same structural merge engine with `dialect: :json5`. It accepts
44
+ JSON5 syntax, including comments, trailing commas, unquoted object keys,
45
+ single-quoted strings, hexadecimal and signed numeric literals, `Infinity`, and
46
+ `NaN`. JSONC remains intentionally narrower: it accepts comments and trailing
47
+ commas, but rejects the JSON5-only forms.
34
48
 
35
49
  ### Key Features
36
50
 
37
- - **Tree-Sitter Powered**: Uses tree-sitter-json for accurate AST parsing
51
+ - **Tree-Sitter Powered**: Uses tree-sitter-json for strict JSON and the
52
+ normalized JSON5 tree for JSONC and JSON5 syntax
53
+ - **JSONC-Aware**: Preserves `//` and `/* */` comments when the parser exposes them
38
54
  - **Intelligent**: Matches objects and arrays by structural signatures
39
55
  - **Fuzzy Property Matching**: `ObjectMatchRefiner` matches similar property names
40
56
  (e.g., `databaseUrl` ↔ `database_url`) using Levenshtein distance for naming convention differences
41
57
  - **Full Provenance**: Tracks origin of every node
42
- - **Standalone**: Minimal dependencies - just `ast-merge` and `ruby_tree_sitter`
58
+ - **StructuredMerge Native**: Depends on `ast-merge` and `tree_haver`; parser availability comes from registered backend providers
43
59
  - **Customizable**:
44
60
  - `signature_generator` - callable custom signature generators
45
61
  - `preference` - setting of `:template`, `:destination`, or a Hash for per-node-type preferences
@@ -73,215 +89,47 @@ result = merger.merge
73
89
  File.write("merged.json", result.to_json)
74
90
  ```
75
91
 
76
- ### The `*-merge` Gem Family
77
-
78
- The `*-merge` gem family provides intelligent, AST-based merging for various file formats. At the foundation is [tree_haver][tree_haver], which provides a unified cross-Ruby parsing API that works seamlessly across MRI, JRuby, and TruffleRuby.
79
-
80
- | Gem | Version / CI | Language<br>/ Format | Parser Backend(s) | Description |
81
- |------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
82
- | [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] <br/> [![CI][tree_haver-ci-i]][tree_haver-ci] | Multi | Supported Backends: MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
83
- | [ast-merge][ast-merge] | [![Version][ast-merge-gem-i]][ast-merge-gem] <br/> [![CI][ast-merge-ci-i]][ast-merge-ci] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
84
- | [bash-merge][bash-merge] | [![Version][bash-merge-gem-i]][bash-merge-gem] <br/> [![CI][bash-merge-ci-i]][bash-merge-ci] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
85
- | [commonmarker-merge][commonmarker-merge] | [![Version][commonmarker-merge-gem-i]][commonmarker-merge-gem] <br/> [![CI][commonmarker-merge-ci-i]][commonmarker-merge-ci] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
86
- | [dotenv-merge][dotenv-merge] | [![Version][dotenv-merge-gem-i]][dotenv-merge-gem] <br/> [![CI][dotenv-merge-ci-i]][dotenv-merge-ci] | Dotenv | internal | Smart merge for `.env` files |
87
- | [json-merge][json-merge] | [![Version][json-merge-gem-i]][json-merge-gem] <br/> [![CI][json-merge-ci-i]][json-merge-ci] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
88
- | [jsonc-merge][jsonc-merge] | [![Version][jsonc-merge-gem-i]][jsonc-merge-gem] <br/> [![CI][jsonc-merge-ci-i]][jsonc-merge-ci] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
89
- | [markdown-merge][markdown-merge] | [![Version][markdown-merge-gem-i]][markdown-merge-gem] <br/> [![CI][markdown-merge-ci-i]][markdown-merge-ci] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver), [Parslet][parslet] | **Foundation**: Shared base for Markdown mergers with inner code block merging |
90
- | [markly-merge][markly-merge] | [![Version][markly-merge-gem-i]][markly-merge-gem] <br/> [![CI][markly-merge-ci-i]][markly-merge-ci] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
91
- | [prism-merge][prism-merge] | [![Version][prism-merge-gem-i]][prism-merge-gem] <br/> [![CI][prism-merge-ci-i]][prism-merge-ci] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
92
- | [psych-merge][psych-merge] | [![Version][psych-merge-gem-i]][psych-merge-gem] <br/> [![CI][psych-merge-ci-i]][psych-merge-ci] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
93
- | [rbs-merge][rbs-merge] | [![Version][rbs-merge-gem-i]][rbs-merge-gem] <br/> [![CI][rbs-merge-ci-i]][rbs-merge-ci] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
94
- | [toml-merge][toml-merge] | [![Version][toml-merge-gem-i]][toml-merge-gem] <br/> [![CI][toml-merge-ci-i]][toml-merge-ci] | TOML | [Parslet + toml][toml], [Citrus + toml-rb][toml-rb], [tree-sitter-toml][ts-toml] (all via tree_haver) | Smart merge for TOML files |
95
-
96
- #### Backend Platform Compatibility
97
-
98
- tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
99
-
100
- | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
101
- |-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
102
- | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
103
- | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
104
- | **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
105
- | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
106
- | **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
107
- | **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
108
- | **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
109
- | **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
110
- | **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
111
- | **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
112
-
113
- **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
114
-
115
- **Why some backends don't work on certain platforms**:
116
-
117
- - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
118
- - **TruffleRuby**: Has C API emulation via Sulong/LLVM, but it doesn't expose all MRI internals that native extensions require (e.g., `RBasic.flags`, `rb_gc_writebarrier`)
119
- - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
120
-
121
- **Example implementations** for the gem templating use case:
122
-
123
- | Gem | Purpose | Description |
124
- |--------------------------|-----------------|-----------------------------------------------|
125
- | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
126
- | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
127
-
128
- [tree_haver]: https://github.com/kettle-rb/tree_haver
129
- [ast-merge]: https://github.com/kettle-rb/ast-merge
130
- [prism-merge]: https://github.com/kettle-rb/prism-merge
131
- [psych-merge]: https://github.com/kettle-rb/psych-merge
132
- [json-merge]: https://github.com/kettle-rb/json-merge
133
- [jsonc-merge]: https://github.com/kettle-rb/jsonc-merge
134
- [bash-merge]: https://github.com/kettle-rb/bash-merge
135
- [rbs-merge]: https://github.com/kettle-rb/rbs-merge
136
- [dotenv-merge]: https://github.com/kettle-rb/dotenv-merge
137
- [toml-merge]: https://github.com/kettle-rb/toml-merge
138
- [markdown-merge]: https://github.com/kettle-rb/markdown-merge
139
- [markly-merge]: https://github.com/kettle-rb/markly-merge
140
- [commonmarker-merge]: https://github.com/kettle-rb/commonmarker-merge
141
- [kettle-dev]: https://github.com/kettle-rb/kettle-dev
142
- [kettle-jem]: https://github.com/kettle-rb/kettle-jem
143
- [tree_haver-gem]: https://bestgems.org/gems/tree_haver
144
- [ast-merge-gem]: https://bestgems.org/gems/ast-merge
145
- [prism-merge-gem]: https://bestgems.org/gems/prism-merge
146
- [psych-merge-gem]: https://bestgems.org/gems/psych-merge
147
- [json-merge-gem]: https://bestgems.org/gems/json-merge
148
- [jsonc-merge-gem]: https://bestgems.org/gems/jsonc-merge
149
- [bash-merge-gem]: https://bestgems.org/gems/bash-merge
150
- [rbs-merge-gem]: https://bestgems.org/gems/rbs-merge
151
- [dotenv-merge-gem]: https://bestgems.org/gems/dotenv-merge
152
- [toml-merge-gem]: https://bestgems.org/gems/toml-merge
153
- [markdown-merge-gem]: https://bestgems.org/gems/markdown-merge
154
- [markly-merge-gem]: https://bestgems.org/gems/markly-merge
155
- [commonmarker-merge-gem]: https://bestgems.org/gems/commonmarker-merge
156
- [kettle-dev-gem]: https://bestgems.org/gems/kettle-dev
157
- [kettle-jem-gem]: https://bestgems.org/gems/kettle-jem
158
- [tree_haver-gem-i]: https://img.shields.io/gem/v/tree_haver.svg
159
- [ast-merge-gem-i]: https://img.shields.io/gem/v/ast-merge.svg
160
- [prism-merge-gem-i]: https://img.shields.io/gem/v/prism-merge.svg
161
- [psych-merge-gem-i]: https://img.shields.io/gem/v/psych-merge.svg
162
- [json-merge-gem-i]: https://img.shields.io/gem/v/json-merge.svg
163
- [jsonc-merge-gem-i]: https://img.shields.io/gem/v/jsonc-merge.svg
164
- [bash-merge-gem-i]: https://img.shields.io/gem/v/bash-merge.svg
165
- [rbs-merge-gem-i]: https://img.shields.io/gem/v/rbs-merge.svg
166
- [dotenv-merge-gem-i]: https://img.shields.io/gem/v/dotenv-merge.svg
167
- [toml-merge-gem-i]: https://img.shields.io/gem/v/toml-merge.svg
168
- [markdown-merge-gem-i]: https://img.shields.io/gem/v/markdown-merge.svg
169
- [markly-merge-gem-i]: https://img.shields.io/gem/v/markly-merge.svg
170
- [commonmarker-merge-gem-i]: https://img.shields.io/gem/v/commonmarker-merge.svg
171
- [kettle-dev-gem-i]: https://img.shields.io/gem/v/kettle-dev.svg
172
- [kettle-jem-gem-i]: https://img.shields.io/gem/v/kettle-jem.svg
173
- [tree_haver-ci-i]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml/badge.svg
174
- [ast-merge-ci-i]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml/badge.svg
175
- [prism-merge-ci-i]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml/badge.svg
176
- [psych-merge-ci-i]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml/badge.svg
177
- [json-merge-ci-i]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg
178
- [jsonc-merge-ci-i]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml/badge.svg
179
- [bash-merge-ci-i]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml/badge.svg
180
- [rbs-merge-ci-i]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml/badge.svg
181
- [dotenv-merge-ci-i]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml/badge.svg
182
- [toml-merge-ci-i]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml/badge.svg
183
- [markdown-merge-ci-i]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml/badge.svg
184
- [markly-merge-ci-i]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml/badge.svg
185
- [commonmarker-merge-ci-i]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml/badge.svg
186
- [kettle-dev-ci-i]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml/badge.svg
187
- [kettle-jem-ci-i]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml/badge.svg
188
- [tree_haver-ci]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml
189
- [ast-merge-ci]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml
190
- [prism-merge-ci]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml
191
- [psych-merge-ci]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml
192
- [json-merge-ci]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml
193
- [jsonc-merge-ci]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml
194
- [bash-merge-ci]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml
195
- [rbs-merge-ci]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml
196
- [dotenv-merge-ci]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml
197
- [toml-merge-ci]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml
198
- [markdown-merge-ci]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml
199
- [markly-merge-ci]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml
200
- [commonmarker-merge-ci]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml
201
- [kettle-dev-ci]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml
202
- [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
203
- [prism]: https://github.com/ruby/prism
204
- [psych]: https://github.com/ruby/psych
205
- [ffi]: https://github.com/ffi/ffi
206
- [ts-json]: https://github.com/tree-sitter/tree-sitter-json
207
- [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
208
- [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
209
- [ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
210
- [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
211
- [dotenv]: https://github.com/bkeepers/dotenv
212
- [rbs]: https://github.com/ruby/rbs
213
- [toml-rb]: https://github.com/emancu/toml-rb
214
- [toml]: https://github.com/jm/toml
215
- [markly]: https://github.com/ioquatix/markly
216
- [commonmarker]: https://github.com/gjtorikian/commonmarker
217
- [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
218
- [tree_stump]: https://github.com/joker1007/tree_stump
219
- [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
220
- [citrus]: https://github.com/mjackson/citrus
221
- [parslet]: https://github.com/kschiess/parslet
92
+ [ast-merge]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/ast-merge
93
+ [tree_haver]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/tree_haver
222
94
 
223
95
  ## 💡 Info you can shake a stick at
224
96
 
225
- | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
226
- | --- | --- |
227
- | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
228
- | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
229
- | Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
230
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
231
- | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-4.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)][🧮kloc] |
97
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
98
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
99
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf]|
100
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Get help from RubyForum][✉️ruby-forum-img]][✉️ruby-forum] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
101
+ | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on GitHub.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
232
102
  | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
233
- | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img][📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
103
+ | Compliance | [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Apache license compatibility: Category X][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
234
104
  | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
235
105
  | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
236
- | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
106
+ | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
237
107
 
238
108
  ### Compatibility
239
109
 
240
- Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
110
+ Compatible with MRI Ruby 4.0.0+, and concordant releases of JRuby, and TruffleRuby.
111
+ CI workflows and Appraisals are generated for MRI Ruby 4.0.0+.
112
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
113
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
114
+ not practical for the current toolchain.
241
115
 
242
- | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
243
- | --- | --- |
244
- | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
116
+ <a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
245
117
 
246
- ### Federated DVCS
118
+ The _amazing_ test matrix is powered by the kettle-dev stack.
247
119
 
248
120
  <details markdown="1">
249
- <summary>Find this repo on federated forges (Coming soon!)</summary>
250
-
251
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
252
- | --- | --- | --- | --- | --- | --- | --- |
253
- | 🧪 [kettle-rb/json-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
254
- | 🧊 [kettle-rb/json-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
255
- | 🐙 [kettle-rb/json-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
256
- | 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] | [Let's][🖼️galtzo-discord] | [talk][🖼️galtzo-discord] | [about][🖼️galtzo-discord] | [this][🖼️galtzo-discord] | [library\!][🖼️galtzo-discord] |
257
-
258
- </details>
259
-
260
- [gh-discussions]: https://github.com/kettle-rb/json-merge/discussions
261
-
262
- ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/json-merge)][🏙️entsup-tidelift]
263
-
264
- Available as part of the Tidelift Subscription.
265
-
266
- <details markdown="1">
267
- <summary>Need enterprise-level guarantees?</summary>
268
-
269
- The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
270
-
271
- [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
272
-
273
- - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
274
-
275
- - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
276
-
277
- - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
278
- Alternatively:
279
-
280
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
281
-
282
- - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
283
-
284
- - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
121
+ <summary>How kettle-dev manages complexity in tests</summary>
122
+
123
+ | Gem | Source | Role | Total downloads |
124
+ |-----|--------|------|---------------------|
125
+ | [appraisal2](https://clickgems.clickhouse.com/dashboard/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Total downloads for appraisal2](https://img.shields.io/gem/dt/appraisal2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2) |
126
+ | [appraisal2-rubocop](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Total downloads for appraisal2-rubocop](https://img.shields.io/gem/dt/appraisal2-rubocop.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) |
127
+ | [kettle-dev](https://clickgems.clickhouse.com/dashboard/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [![Total downloads for kettle-dev](https://img.shields.io/gem/dt/kettle-dev.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-dev) |
128
+ | [kettle-jem](https://clickgems.clickhouse.com/dashboard/kettle-jem) | [GitHub](https://github.com/kettle-dev/kettle-jem) | Appraisals & CI workflow templates | [![Total downloads for kettle-jem](https://img.shields.io/gem/dt/kettle-jem.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-jem) |
129
+ | [kettle-soup-cover](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Total downloads for kettle-soup-cover](https://img.shields.io/gem/dt/kettle-soup-cover.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) |
130
+ | [kettle-test](https://clickgems.clickhouse.com/dashboard/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Total downloads for kettle-test](https://img.shields.io/gem/dt/kettle-test.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-test) |
131
+ | [rubocop-lts](https://clickgems.clickhouse.com/dashboard/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Total downloads for rubocop-lts](https://img.shields.io/gem/dt/rubocop-lts.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/rubocop-lts) |
132
+ | [turbo_tests2](https://clickgems.clickhouse.com/dashboard/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Total downloads for turbo_tests2](https://img.shields.io/gem/dt/turbo_tests2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/turbo_tests2) |
285
133
 
286
134
  </details>
287
135
 
@@ -299,189 +147,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
299
147
  gem install json-merge
300
148
  ```
301
149
 
302
- ### 🔒 Secure Installation
303
-
304
- <details markdown="1">
305
- <summary>For Medium or High Security Installations</summary>
306
-
307
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
308
- [stone\_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
309
- by following the instructions below.
310
-
311
- Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
312
-
313
- ```console
314
- gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
315
- ```
316
-
317
- You only need to do that once. Then proceed to install with:
318
-
319
- ```console
320
- gem install json-merge -P HighSecurity
321
- ```
322
-
323
- The `HighSecurity` trust profile will verify signed gems, and not allow the installation of unsigned dependencies.
324
-
325
- If you want to up your security game full-time:
326
-
327
- ```console
328
- bundle config set --global trust-policy MediumSecurity
329
- ```
330
-
331
- `MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed.
332
-
333
- NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.
334
-
335
- </details>
336
-
337
- ### 🌳 Tree-Sitter Parser Installation
338
-
339
- This gem requires the `tree-sitter-json` parser library to be installed on your system.
340
- The parser is a native shared library (`.so` on Linux, `.dylib` on macOS) that provides
341
- JSON syntax parsing capabilities. For JSONC (JSON with Comments) support, use the
342
- [jsonc-merge][jsonc-merge] gem instead.
343
-
344
- #### Option 1: Pre-built Binaries (Recommended)
345
-
346
- Download pre-built parsers from [Faveod/tree-sitter-parsers](https://github.com/Faveod/tree-sitter-parsers/releases):
347
-
348
- **Linux (x64):**
349
-
350
- ```console
351
- # Download and extract
352
- curl -Lo parsers.tar.gz https://github.com/Faveod/tree-sitter-parsers/releases/download/v4.10/tree-sitter-parsers-4.10-linux-x64.tar.gz
353
- tar -xzf parsers.tar.gz
354
-
355
- # Install system-wide (requires sudo)
356
- sudo cp libtree-sitter-json.so /usr/lib/
357
- sudo ldconfig
358
-
359
- # Or install locally and set environment variable
360
- mkdir -p ~/.local/lib/tree-sitter
361
- cp libtree-sitter-json.so ~/.local/lib/tree-sitter/
362
- export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.so"
363
- ```
364
-
365
- **Debian/Ubuntu (amd64):**
366
-
367
- ```console
368
- curl -Lo parsers.deb https://github.com/Faveod/tree-sitter-parsers/releases/download/v4.10/tree-sitter-parsers-4.10-amd64.deb
369
- sudo dpkg -i parsers.deb
370
- ```
371
-
372
- **macOS (Apple Silicon):**
373
-
374
- ```console
375
- curl -Lo parsers.tar.gz https://github.com/Faveod/tree-sitter-parsers/releases/download/v4.10/tree-sitter-parsers-4.10-macos-arm64.tar.gz
376
- tar -xzf parsers.tar.gz
377
-
378
- # Install to a location and set environment variable
379
- mkdir -p ~/.local/lib/tree-sitter
380
- cp libtree-sitter-json.dylib ~/.local/lib/tree-sitter/
381
- export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.dylib"
382
- ```
383
-
384
- #### Option 2: Build from Source
385
-
386
- ```console
387
- git clone https://github.com/tree-sitter/tree-sitter-json.git
388
- cd tree-sitter-json
389
- make
390
- sudo cp libtree-sitter-json.so /usr/lib/ # Linux
391
- # or
392
- sudo cp libtree-sitter-json.dylib /usr/local/lib/ # macOS
393
- ```
394
-
395
- #### Option 3: Package Manager
396
-
397
- Some package managers provide tree-sitter parsers:
398
-
399
- **Fedora Atomic (Silverblue, Kinoite, Bazzite, Aurora, etc.):**
400
-
401
- ```console
402
- # Install via rpm-ostree (requires reboot)
403
- rpm-ostree install libtree-sitter-json
404
-
405
- # The library will be installed to /usr/lib64/libtree-sitter-json.so
406
- # You may need to set the environment variable:
407
- export TREE_SITTER_JSON_PATH="/usr/lib64/libtree-sitter-json.so"
408
- ```
409
-
410
- **Fedora (traditional):**
411
-
412
- ```console
413
- sudo dnf install libtree-sitter-json
414
- ```
415
-
416
- **Arch Linux:**
417
-
418
- ```console
419
- # Check AUR for tree-sitter-json
420
- yay -S tree-sitter-json
421
- ```
422
-
423
- #### Environment Variable
424
-
425
- If the parser is not in a standard location (`/usr/lib/`, `/usr/lib64/`, `/usr/local/lib/`),
426
- set the `TREE_SITTER_JSON_PATH` environment variable to point to the parser library:
427
-
428
- ```console
429
- export TREE_SITTER_JSON_PATH="/path/to/libtree-sitter-json.so"
430
- ```
431
-
432
- **Note:** Some distributions install the library with a version number suffix
433
- (e.g., `libtree-sitter-json.so.14` instead of `libtree-sitter-json.so`).
434
- If the gem can't find the parser, check for versioned files and either:
435
-
436
- - Set `TREE_SITTER_JSON_PATH` to the full versioned path, or
437
- - Create a symlink: `sudo ln -s /usr/lib64/libtree-sitter-json.so.14 /usr/lib64/libtree-sitter-json.so`
438
- Add this to your shell profile (`.bashrc`, `.zshrc`, etc.) for persistence.
439
-
440
- ### 💎 Ruby Interface Gems
441
-
442
- In addition to the tree-sitter parser library, you need a Ruby gem that provides
443
- bindings to tree-sitter. Choose **one** of the following based on your Ruby implementation:
444
-
445
- | Gem | Ruby Support | Description |
446
- | --- | --- | --- |
447
- | [ruby\_tree\_sitter][ruby_tree_sitter] | MRI only | C extension bindings (recommended for MRI) |
448
- | [tree\_stump][tree_stump] | MRI (maybe JRuby) | Rust-based bindings via Rutie |
449
- | [ffi][ffi] | MRI, JRuby, TruffleRuby | Generic FFI bindings (used by tree\_haver's FFI backend) |
450
-
451
- [ruby_tree_sitter]: https://github.com/Faveod/ruby_tree_sitter
452
- [tree_stump]: https://github.com/nickstenning/tree_stump
453
- [ffi]: https://github.com/ffi/ffi
454
-
455
- #### For MRI Ruby (Recommended)
456
-
457
- ```console
458
- gem install ruby_tree_sitter
459
- ```
460
-
461
- Or add to your Gemfile:
462
-
463
- ```ruby
464
- gem "ruby_tree_sitter", "~> 2.0"
465
- ```
466
-
467
- #### For JRuby or TruffleRuby
468
-
469
- ```console
470
- gem install ffi
471
- ```
472
-
473
- Or add to your Gemfile:
474
-
475
- ```ruby
476
- gem "ffi"
477
- ```
478
-
479
- The `tree_haver` gem (a dependency of json-merge) will automatically detect and use
480
- the appropriate backend based on which gems are available.
481
-
482
- **Note:** The `ruby_tree_sitter` gem only compiles on MRI Ruby. For JRuby or TruffleRuby,
483
- you must use the FFI backend.
484
-
485
150
  ## ⚙️ Configuration
486
151
 
487
152
  ### Signature Match Preference
@@ -564,6 +229,39 @@ Enable debug logging to see merge decisions:
564
229
  export JSON_MERGE_DEBUG=1
565
230
  ```
566
231
 
232
+ ### JSONC and JSON5 Options
233
+
234
+ JSONC and JSON5 files use the same options as JSON files. Set `dialect` when
235
+ constructing a direct merger:
236
+
237
+ ```ruby
238
+ merger = Json::Merge::SmartMerger.new(
239
+ template_content,
240
+ dest_content,
241
+ # Which version to prefer when nodes match
242
+ # :destination (default) - keep destination values
243
+ # :template - use template values
244
+ preference: :destination,
245
+
246
+ # Whether to add template-only nodes to the result
247
+ # false (default) - only include properties that exist in destination
248
+ # true - include all template properties
249
+ add_template_only_nodes: false,
250
+
251
+ # :json (strict), :jsonc (comments and trailing commas), or :json5
252
+ dialect: :jsonc,
253
+
254
+ # Token for freeze block markers
255
+ # Default: "json-merge"
256
+ # Looks for: // json-merge:freeze / // json-merge:unfreeze
257
+ freeze_token: "json-merge",
258
+
259
+ # Custom signature generator (optional)
260
+ # Receives a node, returns a signature array or nil
261
+ signature_generator: ->(node) { [:pair, node.key] if node.type == :pair },
262
+ )
263
+ ```
264
+
567
265
  ## 🔧 Basic Usage
568
266
 
569
267
  ### Merging Two JSON Files
@@ -669,62 +367,64 @@ merger = Json::Merge::SmartMerger.new(
669
367
  # Array elements with matching IDs or similar structure are paired
670
368
  ```
671
369
 
672
- ## 🦷 FLOSS Funding
673
-
674
- While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
675
- Raising a monthly budget of... "dollars" would make the project more sustainable.
676
-
677
- We welcome both individual and corporate sponsors\! We also offer a
678
- wide array of funding channels to account for your preferences
679
- (although currently [Open Collective][🖇osc] is our preferred funding platform).
680
-
681
- **If you're working in a company that's making significant use of kettle-rb tools we'd
682
- appreciate it if you suggest to your company to become a kettle-rb sponsor.**
370
+ ### Merging JSONC Files
683
371
 
684
- You can support the development of kettle-rb tools via
685
- [GitHub Sponsors][🖇sponsor],
686
- [Liberapay][⛳liberapay],
687
- [PayPal][🖇paypal],
688
- [Open Collective][🖇osc]
689
- and [Tidelift][🏙️entsup-tidelift].
372
+ ```ruby
373
+ require "json/merge"
690
374
 
691
- | 📍 NOTE |
692
- | --- |
693
- | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
375
+ template = File.read("template.jsonc")
376
+ destination = File.read("destination.jsonc")
694
377
 
695
- ### Open Collective for Individuals
378
+ merger = Json::Merge::SmartMerger.new(template, destination)
379
+ result = merger.merge
696
380
 
697
- Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
381
+ File.write("merged.jsonc", result)
382
+ ```
698
383
 
699
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
384
+ ### Merging JSON5 Files
700
385
 
701
- <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
702
- No backers yet. Be the first!
703
- <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
386
+ ```ruby
387
+ require "json/merge"
704
388
 
705
- ### Open Collective for Organizations
389
+ template = File.read("template.json5")
390
+ destination = File.read("destination.json5")
706
391
 
707
- Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
392
+ merger = Json::Merge::SmartMerger.new(template, destination, dialect: :json5)
393
+ result = merger.merge
708
394
 
709
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
395
+ File.write("merged.json5", result)
396
+ ```
710
397
 
711
- <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
712
- No sponsors yet. Be the first!
713
- <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
398
+ ### JSONC Freeze Blocks
714
399
 
715
- [kettle-readme-backers]: https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers
400
+ Freeze blocks protect sections from being overwritten during merge:
716
401
 
717
- ### Another way to support open-source
402
+ ```jsonc
403
+ {
404
+ "name": "my-app",
718
405
 
719
- I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).
406
+ // json-merge:freeze Secret configuration
407
+ "api_key": "my_production_api_key",
408
+ "api_secret": "super_secret_value",
409
+ // json-merge:unfreeze
720
410
 
721
- If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`.
411
+ "debug": false
412
+ }
413
+ ```
722
414
 
723
- I’m developing a new library, [floss\_funding][🖇floss-funding-gem], designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.
415
+ Content between `// json-merge:freeze` and `// json-merge:unfreeze` markers is preserved from the destination file, regardless of what the template contains.
724
416
 
725
- **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
417
+ ### Adding Template-Only JSONC Properties
726
418
 
727
- [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
419
+ ```ruby
420
+ merger = Json::Merge::SmartMerger.new(
421
+ template,
422
+ destination,
423
+ add_template_only_nodes: true,
424
+ )
425
+ result = merger.merge
426
+ # Result includes properties from template that do not exist in destination
427
+ ```
728
428
 
729
429
  ## 🔐 Security
730
430
 
@@ -733,83 +433,41 @@ See [SECURITY.md][🔐security].
733
433
  ## 🤝 Contributing
734
434
 
735
435
  If you need some ideas of where to help, you could work on adding more code coverage,
736
- or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
436
+ or if it is already 💯 (see [below](#code-coverage)) check [issues][🤝gh-issues] or [PRs][🤝gh-pulls],
737
437
  or use the gem and think about how it could be better.
738
438
 
739
439
  We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
740
440
 
741
441
  See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
742
442
 
743
- ### 🚀 Release Instructions
744
-
745
- See [CONTRIBUTING.md][🤝contributing].
746
-
747
443
  ### Code Coverage
748
444
 
749
- [![Coverage Graph][🏀codecov-g]][🏀codecov]
750
-
751
- [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
752
-
753
- [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
754
-
755
- ### 🪇 Code of Conduct
756
-
757
- Everyone interacting with this project's codebases, issue trackers,
758
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
759
-
760
- ## 🌈 Contributors
761
-
762
- [![Contributors][🖐contributors-img]][🖐contributors]
763
-
764
- Made with [contributors-img][🖐contrib-rocks].
765
-
766
- Also see GitLab Contributors: <https://gitlab.com/kettle-rb/json-merge/-/graphs/main>
767
-
768
- <details>
769
- <summary>⭐️ Star History</summary>
770
-
771
- <a href="https://star-history.com/#kettle-rb/json-merge&Date">
772
- <picture>
773
- <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=kettle-rb/json-merge&type=Date&theme=dark" />
774
- <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=kettle-rb/json-merge&type=Date" />
775
- <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=kettle-rb/json-merge&type=Date" />
776
- </picture>
777
- </a>
445
+ <details markdown="1">
446
+ <summary>Coverage service badges</summary>
778
447
 
779
448
  </details>
780
449
 
781
450
  ## 📌 Versioning
782
451
 
783
- This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
784
- Violations of this scheme should be reported as bugs.
785
- Specifically, if a minor or patch version is released that breaks backward compatibility,
786
- a new version should be immediately released that restores compatibility.
787
- Breaking changes to the public API will only be introduced with new major versions.
788
-
789
- > dropping support for a platform is both obviously and objectively a breaking change <br/>
790
- > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
791
-
792
- I understand that policy doesn't work universally ("exceptions to every rule\!"),
793
- but it is the policy here.
794
- As such, in many cases it is good to specify a dependency on this library using
795
- the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
452
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
453
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
796
454
 
797
455
  For example:
798
456
 
799
457
  ```ruby
800
- spec.add_dependency("json-merge", "~> 1.0")
458
+ spec.add_dependency("json-merge", "~> 7.0")
801
459
  ```
802
460
 
803
461
  <details markdown="1">
804
462
  <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
805
463
 
806
- SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms
807
- is a *breaking change* to an API, and for that reason the bike shedding is endless.
464
+ Dropping support for a platform can be a breaking change for affected users.
465
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
808
466
 
809
467
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
810
468
  read this article from the creator of SemVer:
811
469
 
812
- - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
470
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
813
471
 
814
472
  </details>
815
473
 
@@ -817,68 +475,19 @@ See [CHANGELOG.md][📌changelog] for a list of releases.
817
475
 
818
476
  ## 📄 License
819
477
 
820
- The gem is available as open source under the terms of
821
- the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
822
- See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
823
-
824
- ### © Copyright
825
-
826
- <ul>
827
- <li>
828
- Copyright (c) 2025 Peter H. Boling, of
829
- <a href="https://discord.gg/3qme4XHNKN">
830
- Galtzo.com
831
- <picture>
832
- <img src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px-blank.svg" alt="Galtzo.com Logo (Wordless) by Aboling0, CC BY-SA 4.0" width="24">
833
- </picture>
834
- </a>, and json-merge contributors.
835
- </li>
836
- </ul>
837
-
838
- ## 🤑 A request for help
839
-
840
- Maintainers have teeth and need to pay their dentists.
841
- After getting laid off in an RIF in March, and encountering difficulty finding a new one,
842
- I began spending most of my time building open source tools.
843
- I'm hoping to be able to pay for my kids' health insurance this month,
844
- so if you value the work I am doing, I need your support.
845
- Please consider sponsoring me or the project.
846
-
847
- To join the community or get help 👇️ Join the Discord.
848
-
849
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
850
-
851
- To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
852
-
853
- [![Sponsor kettle-rb/json-merge on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
854
-
855
- ### Please give the project a star ⭐ ♥.
478
+ The gem is available under the following licenses: [AGPL-3.0-only](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md), [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md).
479
+ See [LICENSE.md][📄license] for details.
856
480
 
857
- Thanks for RTFM. ☺️
481
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
858
482
 
859
483
  [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
860
484
  [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
861
485
  [⛳liberapay]: https://liberapay.com/pboling/donate
862
- [🖇osc-all-img]: https://img.shields.io/opencollective/all/kettle-rb
863
- [🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/kettle-rb
864
- [🖇osc-backers-img]: https://img.shields.io/opencollective/backers/kettle-rb
865
- [🖇osc-backers]: https://opencollective.com/kettle-rb#backer
866
- [🖇osc-backers-i]: https://opencollective.com/kettle-rb/backers/badge.svg?style=flat
867
- [🖇osc-sponsors]: https://opencollective.com/kettle-rb#sponsor
868
- [🖇osc-sponsors-i]: https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat
869
- [🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/kettle-rb?style=for-the-badge
870
- [🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/kettle-rb?style=for-the-badge
871
- [🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/kettle-rb?style=for-the-badge
872
- [🖇osc]: https://opencollective.com/kettle-rb
873
486
  [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
874
487
  [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
875
488
  [🖇sponsor]: https://github.com/sponsors/pboling
876
- [🖇polar-img]: https://img.shields.io/badge/polar-donate-a51611.svg?style=flat
877
- [🖇polar]: https://polar.sh/pboling
878
489
  [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
879
- [🖇kofi]: https://ko-fi.com/O5O86SNP4
880
- [🖇patreon-img]: https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat
881
- [🖇patreon]: https://patreon.com/galtzo
490
+ [🖇kofi]: https://ko-fi.com/pboling
882
491
  [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
883
492
  [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
884
493
  [🖇buyme]: https://www.buymeacoffee.com/pboling
@@ -891,19 +500,22 @@ Thanks for RTFM. ☺️
891
500
  [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
892
501
  [✉️ruby-friends-img]: https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white
893
502
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
503
+ [✉️ruby-forum-top-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=flat&logo=discourse&label=Ruby%20Users%20Forum
504
+ [✉️ruby-forum-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=for-the-badge&logo=discourse&label=Ruby%20Users%20Forum
505
+ [✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
894
506
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
895
- [⛳️gem-namespace]: https://github.com/kettle-rb/json-merge
507
+ [⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/json-merge
896
508
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Json::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
897
- [⛳️gem-name]: https://bestgems.org/gems/json-merge
509
+ [⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/json-merge
898
510
  [⛳️name-img]: https://img.shields.io/badge/name-json--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
899
- [⛳️tag-img]: https://img.shields.io/github/tag/kettle-rb/json-merge.svg
900
- [⛳️tag]: http://github.com/kettle-rb/json-merge/releases
511
+ [⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
512
+ [⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
901
513
  [🚂maint-blog]: http://www.railsbling.com/tags/json-merge
902
514
  [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
903
515
  [🚂maint-contact]: http://www.railsbling.com/contact
904
516
  [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
905
517
  [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
906
- [💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
518
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
907
519
  [💖✌️wellfound]: https://wellfound.com/u/peter-boling
908
520
  [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
909
521
  [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
@@ -932,103 +544,63 @@ Thanks for RTFM. ☺️
932
544
  [💁🏼‍♂️peterboling]: http://www.peterboling.com
933
545
  [🚂railsbling]: http://www.railsbling.com
934
546
  [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
935
- [📜src-gl]: https://gitlab.com/kettle-rb/json-merge/
547
+ [📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/json-merge
936
548
  [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
937
- [📜src-cb]: https://codeberg.org/kettle-rb/json-merge
938
- [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
939
- [📜src-gh]: https://github.com/kettle-rb/json-merge
549
+ [📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/json-merge
550
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
551
+ [📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/json-merge
940
552
  [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
941
553
  [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
942
- [📜gl-wiki]: https://gitlab.com/kettle-rb/json-merge/-/wikis/home
943
- [📜gh-wiki]: https://github.com/kettle-rb/json-merge/wiki
944
- [📜gl-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
945
- [📜gh-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
946
- [👽dl-rank]: https://bestgems.org/gems/json-merge
947
- [👽dl-ranki]: https://img.shields.io/gem/rd/json-merge.svg
948
- [👽oss-help]: https://www.codetriage.com/kettle-rb/json-merge
949
- [👽oss-helpi]: https://www.codetriage.com/kettle-rb/json-merge/badges/users.svg
950
- [👽version]: https://bestgems.org/gems/json-merge
554
+ [📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
555
+ [📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
556
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
557
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
558
+ [👽dl-rank]: https://clickgems.clickhouse.com/dashboard/json-merge
559
+ [👽dl-ranki]: https://img.shields.io/gem/dt/json-merge.svg
560
+ [👽version]: https://clickgems.clickhouse.com/dashboard/json-merge
951
561
  [👽versioni]: https://img.shields.io/gem/v/json-merge.svg
952
- [🏀qlty-mnt]: https://qlty.sh/gh/kettle-rb/projects/json-merge
953
- [🏀qlty-mnti]: https://qlty.sh/gh/kettle-rb/projects/json-merge/maintainability.svg
954
- [🏀qlty-cov]: https://qlty.sh/gh/kettle-rb/projects/json-merge/metrics/code?sort=coverageRating
955
- [🏀qlty-covi]: https://qlty.sh/gh/kettle-rb/projects/json-merge/coverage.svg
956
- [🏀codecov]: https://codecov.io/gh/kettle-rb/json-merge
957
- [🏀codecovi]: https://codecov.io/gh/kettle-rb/json-merge/graph/badge.svg
958
- [🏀coveralls]: https://coveralls.io/github/kettle-rb/json-merge?branch=main
959
- [🏀coveralls-img]: https://coveralls.io/repos/github/kettle-rb/json-merge/badge.svg?branch=main
960
- [🖐codeQL]: https://github.com/kettle-rb/json-merge/security/code-scanning
961
- [🖐codeQL-img]: https://github.com/kettle-rb/json-merge/actions/workflows/codeql-analysis.yml/badge.svg
962
- [🚎2-cov-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/coverage.yml
963
- [🚎2-cov-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/coverage.yml/badge.svg
964
- [🚎3-hd-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml
965
- [🚎3-hd-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml/badge.svg
966
- [🚎5-st-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/style.yml
967
- [🚎5-st-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/style.yml/badge.svg
968
- [🚎6-s-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml
969
- [🚎6-s-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml/badge.svg
970
- [🚎9-t-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/truffle.yml
971
- [🚎9-t-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/truffle.yml/badge.svg
972
- [🚎11-c-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml
973
- [🚎11-c-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg
974
- [🚎12-crh-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/dep-heads.yml
975
- [🚎12-crh-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/dep-heads.yml/badge.svg
976
- [🚎13-🔒️-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/locked_deps.yml
977
- [🚎13-🔒️-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/locked_deps.yml/badge.svg
978
- [🚎14-🔓️-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/unlocked_deps.yml
979
- [🚎14-🔓️-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/unlocked_deps.yml/badge.svg
980
- [🚎15-🪪-wf]: https://github.com/kettle-rb/json-merge/actions/workflows/license-eye.yml
981
- [🚎15-🪪-wfi]: https://github.com/kettle-rb/json-merge/actions/workflows/license-eye.yml/badge.svg
982
- [💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
983
- [💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
562
+ [🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
563
+ [🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
984
564
  [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
985
- [💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
986
- [💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
987
- [💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
988
- [💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
989
- [💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
990
- [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
991
- [🤝gh-issues]: https://github.com/kettle-rb/json-merge/issues
992
- [🤝gh-pulls]: https://github.com/kettle-rb/json-merge/pulls
993
- [🤝gl-issues]: https://gitlab.com/kettle-rb/json-merge/-/issues
994
- [🤝gl-pulls]: https://gitlab.com/kettle-rb/json-merge/-/merge_requests
995
- [🤝cb-issues]: https://codeberg.org/kettle-rb/json-merge/issues
996
- [🤝cb-pulls]: https://codeberg.org/kettle-rb/json-merge/pulls
565
+ [🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
566
+ [🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
567
+ [🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
568
+ [🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
569
+ [🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
570
+ [🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
997
571
  [🤝cb-donate]: https://donate.codeberg.org/
998
- [🤝contributing]: CONTRIBUTING.md
999
- [🏀codecov-g]: https://codecov.io/gh/kettle-rb/json-merge/graphs/tree.svg
572
+ [🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
1000
573
  [🖐contrib-rocks]: https://contrib.rocks
1001
- [🖐contributors]: https://github.com/kettle-rb/json-merge/graphs/contributors
1002
- [🖐contributors-img]: https://contrib.rocks/image?repo=kettle-rb/json-merge
1003
- [🚎contributors-gl]: https://gitlab.com/kettle-rb/json-merge/-/graphs/main
1004
- [🪇conduct]: CODE_OF_CONDUCT.md
574
+ [🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
575
+ [🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
576
+ [🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
1005
577
  [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
1006
578
  [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
1007
579
  [📌semver]: https://semver.org/spec/v2.0.0.html
1008
580
  [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
1009
581
  [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
1010
582
  [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
1011
- [📌changelog]: CHANGELOG.md
583
+ [📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
1012
584
  [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
1013
585
  [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
1014
586
  [📌gitmoji]: https://gitmoji.dev
1015
587
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1016
588
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1017
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.631-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1018
- [🔐security]: SECURITY.md
589
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-1.658-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
590
+ [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
1019
591
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1020
592
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
1021
- [📄license]: LICENSE.txt
1022
- [📄license-ref]: https://opensource.org/licenses/MIT
1023
- [📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
1024
- [📄license-compat]: https://dev.to/galtzo/how-to-check-license-compatibility-41h0
1025
- [📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache
593
+ [📄license]: LICENSE.md
594
+ [📄license-ref]: LICENSE.md
595
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
596
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
597
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
1026
598
  [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
1027
599
  [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
1028
600
  [🚎yard-current]: http://rubydoc.info/gems/json-merge
1029
601
  [🚎yard-head]: https://json-merge.galtzo.com
1030
602
  [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
1031
- [💎SHA_checksums]: https://gitlab.com/kettle-rb/json-merge/-/tree/main/checksums
603
+ [💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
1032
604
  [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
1033
605
  [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
1034
606
  [💎appraisal2]: https://github.com/appraisal-rb/appraisal2