json-merge 1.1.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db4707dba4ede9ef1ecab447fafe24788891d076c69714fc700f17a35d8f5bae
4
- data.tar.gz: 5f88a2d90a1695c3c7ffe4d4f08c83090fae455f6cd1810a29b331045f636f31
3
+ metadata.gz: e4b80810376606cc51dc2bb9b44a4cd40c59fc1f7c8d56f12fb2840d0860a5f0
4
+ data.tar.gz: dcae0b630a056f5fcc2a59d6ace275b2b649b62df5af62c287e12d80468fa78d
5
5
  SHA512:
6
- metadata.gz: d4810ca402f5af373769e6a69a73ace769f6d6f11e61c3d7a2a1b1186672387bc41f92b40fc74a327648a856d38547a60b120583fddd3329b17941b0e0ea51e9
7
- data.tar.gz: 1e04ca747b1f07f3177626e351947c9dd40cd78f810d1b285925a3c0bee0bbeecfca2891872b53b288d33ab66fb171b0f4ad3d84dc919f2ddf75b0d181b3fbb4
6
+ metadata.gz: 0002d281c55f8f0dfd5d0000d22237f5bf68495eaa724008a57efd049fe1845d32cb4318fcc00266948cc5b93855bd4315eea87bfd65bdce57386747c10d118b
7
+ data.tar.gz: 48360b4e51149e4c83111ec167ffb1279e84147db5d67e9701dab41f247c9862970df48681fedbfca6460791ef8f39918bb49b1d2ee59f9d9a74cb818ba16fc8
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,22 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.1.1] - 2026-01-26
34
+
35
+ - TAG: [v1.1.1][1.1.1t]
36
+ - COVERAGE: 95.72% -- 604/631 lines in 10 files
37
+ - BRANCH COVERAGE: 77.81% -- 235/302 branches in 10 files
38
+ - 96.63% documented
39
+
40
+ ### Added
41
+
42
+ - ConflictResolver now applies per-node-type preferences via `node_typing`.
43
+
44
+ ### Changed
45
+
46
+ - ast-merge v4.0.4
47
+ - tree_haver v5.0.2
48
+
33
49
  ## [1.1.0] - 2026-01-12
34
50
 
35
51
  - TAG: [v1.1.0][1.1.0t]
@@ -97,7 +113,9 @@ Please file a bug if you notice a violation of semantic versioning.
97
113
 
98
114
  ### Security
99
115
 
100
- [Unreleased]: https://github.com/kettle-rb/json-merge/compare/v1.1.0...HEAD
116
+ [Unreleased]: https://github.com/kettle-rb/json-merge/compare/v1.1.1...HEAD
117
+ [1.1.1]: https://github.com/kettle-rb/json-merge/compare/v1.1.0...v1.1.1
118
+ [1.1.1t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.1
101
119
  [1.1.0]: https://github.com/kettle-rb/json-merge/compare/v1.0.0...v1.1.0
102
120
  [1.1.0t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.0
103
121
  [1.0.0]: https://github.com/kettle-rb/json-merge/compare/f1cc25b1d9b79c598270e3aa203fa56787e6c6fc...v1.0.0
data/README.md CHANGED
@@ -31,7 +31,7 @@
31
31
  [rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
32
32
  [policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
33
33
 
34
- [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0](https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg)](https://discord.gg/3qme4XHNKN) [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5](https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg)](https://www.ruby-lang.org/) [![kettle-rb Logo by Aboling0, CC BY-SA 4.0](https://logos.galtzo.com/assets/images/kettle-rb/avatar-192px.svg)](https://github.com/kettle-rb)
34
+ [![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]
35
35
 
36
36
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
37
37
  [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
@@ -42,20 +42,21 @@
42
42
 
43
43
  # ☯️ Json::Merge
44
44
 
45
- [![Version](https://img.shields.io/gem/v/json-merge.svg)](https://bestgems.org/gems/json-merge) [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/kettle-rb/json-merge.svg)](http://github.com/kettle-rb/json-merge/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT) [![Downloads Rank](https://img.shields.io/gem/rd/json-merge.svg)](https://bestgems.org/gems/json-merge) [![Open Source Helpers](https://www.codetriage.com/kettle-rb/json-merge/badges/users.svg)](https://www.codetriage.com/kettle-rb/json-merge) [![CodeCov Test Coverage](https://codecov.io/gh/kettle-rb/json-merge/graph/badge.svg)](https://codecov.io/gh/kettle-rb/json-merge) [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/json-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/json-merge?branch=main) [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/json-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/json-merge/metrics/code?sort=coverageRating) [![QLTY Maintainability](https://qlty.sh/gh/kettle-rb/projects/json-merge/maintainability.svg)](https://qlty.sh/gh/kettle-rb/projects/json-merge) [![CI Heads](https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml) [![CI Runtime Dependencies @ HEAD](https://github.com/kettle-rb/json-merge/actions/workflows/dep-heads.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/dep-heads.yml) [![CI Current](https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/current.yml) [![CI Truffle Ruby](https://github.com/kettle-rb/json-merge/actions/workflows/truffle.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/truffle.yml) [![Deps Locked](https://github.com/kettle-rb/json-merge/actions/workflows/locked_deps.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/locked_deps.yml) [![Deps Unlocked](https://github.com/kettle-rb/json-merge/actions/workflows/unlocked_deps.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/unlocked_deps.yml) [![CI Supported](https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml) [![CI Test Coverage](https://github.com/kettle-rb/json-merge/actions/workflows/coverage.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/coverage.yml) [![CI Style](https://github.com/kettle-rb/json-merge/actions/workflows/style.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/style.yml) [![CodeQL](https://github.com/kettle-rb/json-merge/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/kettle-rb/json-merge/security/code-scanning) [![Apache SkyWalking Eyes License Compatibility Check](https://github.com/kettle-rb/json-merge/actions/workflows/license-eye.yml/badge.svg)](https://github.com/kettle-rb/json-merge/actions/workflows/license-eye.yml)
45
+ [![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]
46
46
 
47
- `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know](https://discord.gg/3qme4XHNKN), as I may have missed the [discord notification](https://discord.gg/3qme4XHNKN).
47
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
48
48
 
49
49
  -----
50
+
50
51
  `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.
51
52
 
52
- [![OpenCollective Backers](https://opencollective.com/kettle-rb/backers/badge.svg?style=flat)](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors](https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat)](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github](https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github)](https://github.com/sponsors/pboling) [![Liberapay Goal Progress](https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat)](https://liberapay.com/pboling/donate) [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal)](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee](https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat)](https://www.buymeacoffee.com/pboling) [![Donate on Polar](https://img.shields.io/badge/polar-donate-a51611.svg?style=flat)](https://polar.sh/pboling) [![Donate at ko-fi.com](https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat)](https://ko-fi.com/O5O86SNP4)
53
+ [![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]
53
54
 
54
55
  ## 🌻 Synopsis
55
56
 
56
- 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](https://github.com/kettle-rb/ast-merge), it shares the same architecture as [prism-merge](https://github.com/kettle-rb/prism-merge) for Ruby source files.
57
+ 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.
57
58
 
58
- For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) gem.
59
+ For JSONC (JSON with Comments) support, see the [jsonc-merge][jsonc-merge] gem.
59
60
 
60
61
  ### Key Features
61
62
 
@@ -68,9 +69,10 @@ For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com
68
69
  - **Customizable**:
69
70
  - `signature_generator` - callable custom signature generators
70
71
  - `preference` - setting of `:template`, `:destination`, or a Hash for per-node-type preferences
71
- - `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge](https://github.com/kettle-rb/ast-merge) docs)
72
+ - `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge][ast-merge] docs)
72
73
  - `add_template_only_nodes` - setting to retain nodes that do not exist in destination
73
74
  - `match_refiners` - array of refiners for fuzzy matching (e.g., `ObjectMatchRefiner`)
75
+
74
76
  ### Supported Node Types
75
77
 
76
78
  | Node Type | Signature Format | Matching Behavior |
@@ -85,7 +87,7 @@ For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com
85
87
 
86
88
  ### Example
87
89
 
88
- ``` ruby
90
+ ```ruby
89
91
  require "json/merge"
90
92
 
91
93
  template = File.read("template.json")
@@ -101,37 +103,38 @@ File.write("merged.json", result.to_json)
101
103
 
102
104
  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.
103
105
 
104
- | Gem | Language<br>/ Format | Parser Backend(s) | Description |
105
- |------------------------------------------|----------------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
106
- | [tree_haver][tree_haver] | Multi | MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
107
- | [ast-merge][ast-merge] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
108
- | [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
109
- | [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
110
- | [dotenv-merge][dotenv-merge] | Dotenv | internal | Smart merge for `.env` files |
111
- | [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
112
- | [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
113
- | [markdown-merge][markdown-merge] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver) | **Foundation**: Shared base for Markdown mergers with inner code block merging |
114
- | [markly-merge][markly-merge] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
115
- | [prism-merge][prism-merge] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
116
- | [psych-merge][psych-merge] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
117
- | [rbs-merge][rbs-merge] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
118
- | [toml-merge][toml-merge] | TOML | [Citrus + toml-rb][toml-rb] (default, via tree_haver), [tree-sitter-toml][ts-toml] (via tree_haver) | Smart merge for TOML files |
106
+ | Gem | Version / CI | Language<br>/ Format | Parser Backend(s) | Description |
107
+ |------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
108
+ | [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) |
109
+ | [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 |
110
+ | [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 |
111
+ | [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) |
112
+ | [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 |
113
+ | [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 |
114
+ | [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 |
115
+ | [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 |
116
+ | [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) |
117
+ | [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 |
118
+ | [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 |
119
+ | [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 |
120
+ | [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 |
119
121
 
120
122
  #### Backend Platform Compatibility
121
123
 
122
124
  tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
123
125
 
124
- | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
125
- |------------------------------------------------|:---:|:-----:|:-----------:|-----------------------------------------------------|
126
- | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
127
- | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
128
- | **FFI** | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
129
- | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
130
- | **Prism** | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
131
- | **Psych** | ✅ | ✅ | ✅ | YAML parsing, stdlib |
132
- | **Citrus** | ✅ | ✅ | ✅ | Pure Ruby, no native dependencies |
133
- | **Commonmarker** | ✅ | | | Rust extension for Markdown |
134
- | **Markly** | ✅ | ❌ | ❓ | C extension for Markdown |
126
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
127
+ |-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
128
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
129
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
130
+ | **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
131
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
132
+ | **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
133
+ | **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
134
+ | **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
135
+ | **Parslet** ([parslet][parslet]) | ✅ | | | Pure Ruby PEG parser, no native dependencies |
136
+ | **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
137
+ | **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
135
138
 
136
139
  **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
137
140
 
@@ -225,6 +228,7 @@ tree_haver supports multiple parsing backends, but not all backends work on all
225
228
  [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
226
229
  [prism]: https://github.com/ruby/prism
227
230
  [psych]: https://github.com/ruby/psych
231
+ [ffi]: https://github.com/ffi/ffi
228
232
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
229
233
  [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
230
234
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
@@ -239,21 +243,23 @@ tree_haver supports multiple parsing backends, but not all backends work on all
239
243
  [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
240
244
  [tree_stump]: https://github.com/joker1007/tree_stump
241
245
  [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
246
+ [citrus]: https://github.com/mjackson/citrus
247
+ [parslet]: https://github.com/kschiess/parslet
242
248
 
243
249
  ## 💡 Info you can shake a stick at
244
250
 
245
- | Tokens to Remember | [![Gem name](https://img.shields.io/badge/name-json--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red)](https://bestgems.org/gems/json-merge) [![Gem namespace](https://img.shields.io/badge/namespace-Json::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white)](https://github.com/kettle-rb/json-merge) |
251
+ | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
246
252
  | --- | --- |
247
- | Works with JRuby | [![JRuby 10.0 Compat](https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/json-merge/actions/workflows/current.yml) [![JRuby HEAD Compat](https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue)](https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml) |
248
- | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat](https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink)](https://github.com/kettle-rb/json-merge/actions/workflows/truffle.yml) [![Truffle Ruby 24.1 Compat](https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/json-merge/actions/workflows/current.yml) |
249
- | Works with MRI Ruby 3 | [![Ruby 3.2 Compat](https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white)](https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml) [![Ruby 3.3 Compat](https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white)](https://github.com/kettle-rb/json-merge/actions/workflows/supported.yml) [![Ruby 3.4 Compat](https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green)](https://github.com/kettle-rb/json-merge/actions/workflows/current.yml) [![Ruby HEAD Compat](https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue)](https://github.com/kettle-rb/json-merge/actions/workflows/heads.yml) |
250
- | Support & Community | [![Join Me on Daily.dev's RubyFriends](https://img.shields.io/badge/daily.dev-%F0%9F%92%8E_Ruby_Friends-0A0A0A?style=for-the-badge&logo=dailydotdev&logoColor=white)](https://app.daily.dev/squads/rubyfriends) [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN) [![Get help from me on Upwork](https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white)](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share) [![Get help from me on Codementor](https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white)](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github) |
251
- | Source | [![Source on GitLab.com](https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange)](https://gitlab.com/kettle-rb/json-merge/) [![Source on CodeBerg.org](https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue)](https://codeberg.org/kettle-rb/json-merge) [![Source on Github.com](https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green)](https://github.com/kettle-rb/json-merge) [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-4.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) |
252
- | Documentation | [![Current release on RubyDoc.info](https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white)](http://rubydoc.info/gems/json-merge) [![YARD on Galtzo.com](https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white)](https://json-merge.galtzo.com) [![Maintainer Blog](https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange)](http://www.railsbling.com/tags/json-merge) [![GitLab Wiki](https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white)](https://gitlab.com/kettle-rb/json-merge/-/wikis/home) [![GitHub Wiki](https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/kettle-rb/json-merge/wiki) |
253
- | Compliance | [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT) [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes](https://img.shields.io/badge/Apache_Compatible:_Category_A-%E2%9C%93-259D6C.svg?style=flat&logo=Apache)](https://dev.to/galtzo/how-to-check-license-compatibility-41h0) [![📄ilo-declaration-img](https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat)](https://www.ilo.org/declaration/lang--en/index.htm) [![Security Policy](https://img.shields.io/badge/security-policy-259D6C.svg?style=flat)](SECURITY.md) [![Contributor Covenant 2.1](https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg)](CODE_OF_CONDUCT.md) [![SemVer 2.0.0](https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat)](https://semver.org/spec/v2.0.0.html) |
254
- | Style | [![Enforced Code Style Linter](https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white)](https://github.com/rubocop-lts/rubocop-lts) [![Keep-A-Changelog 1.0.0](https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat)](https://keepachangelog.com/en/1.0.0/) [![Gitmoji Commits](https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square)](https://gitmoji.dev) [![Compatibility appraised by: appraisal2](https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white)](https://github.com/appraisal-rb/appraisal2) |
255
- | Maintainer 🎖️ | [![Follow Me on LinkedIn](https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling)](http://www.linkedin.com/in/peterboling) [![Follow Me on Ruby.Social](https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo)](https://ruby.social/@galtzo) [![Follow Me on Bluesky](https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white)](https://bsky.app/profile/galtzo.com) [![Contact Maintainer](https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red)](http://www.railsbling.com/contact) [![My technical writing](https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white)](https://dev.to/galtzo) |
256
- | `...` 💖 | [![Find Me on WellFound:](https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound)](https://wellfound.com/u/peter-boling) [![Find Me on CrunchBase](https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase)](https://www.crunchbase.com/person/peter-boling) [![My LinkTree](https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree)](https://linktr.ee/galtzo) [![More About Me](https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white)](https://about.me/peter.boling) [🧊](https://codeberg.org/pboling) [🐙](https://github.org/pboling) [🛖](https://sr.ht/~galtzo/) [🧪](https://gitlab.com/pboling) |
253
+ | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
254
+ | 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] |
255
+ | 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] |
256
+ | 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] |
257
+ | 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] |
258
+ | 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] |
259
+ | 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] |
260
+ | 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] |
261
+ | 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] |
262
+ | `...` 💖 | [![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] |
257
263
 
258
264
  ### Compatibility
259
265
 
@@ -261,25 +267,25 @@ Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRu
261
267
 
262
268
  | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
263
269
  | --- | --- |
264
- | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2](https://github.com/appraisal-rb/appraisal2) ✨ |
270
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
265
271
 
266
272
  ### Federated DVCS
267
273
 
268
274
  <details markdown="1">
269
275
  <summary>Find this repo on federated forges (Coming soon!)</summary>
270
276
 
271
- | Federated [DVCS](https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/) Repository | Status | Issues | PRs | Wiki | CI | Discussions |
277
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
272
278
  | --- | --- | --- | --- | --- | --- | --- |
273
- | 🧪 [kettle-rb/json-merge on GitLab](https://gitlab.com/kettle-rb/json-merge/) | The Truth | [💚](https://gitlab.com/kettle-rb/json-merge/-/issues) | [💚](https://gitlab.com/kettle-rb/json-merge/-/merge_requests) | [💚](https://gitlab.com/kettle-rb/json-merge/-/wikis/home) | 🐭 Tiny Matrix | ➖ |
274
- | 🧊 [kettle-rb/json-merge on CodeBerg](https://codeberg.org/kettle-rb/json-merge) | An Ethical Mirror ([Donate](https://donate.codeberg.org/)) | [💚](https://codeberg.org/kettle-rb/json-merge/issues) | [💚](https://codeberg.org/kettle-rb/json-merge/pulls) | ➖ | ⭕️ No Matrix | ➖ |
275
- | 🐙 [kettle-rb/json-merge on GitHub](https://github.com/kettle-rb/json-merge) | Another Mirror | [💚](https://github.com/kettle-rb/json-merge/issues) | [💚](https://github.com/kettle-rb/json-merge/pulls) | [💚](https://github.com/kettle-rb/json-merge/wiki) | 💯 Full Matrix | [💚](https://github.com/kettle-rb/json-merge/discussions) |
276
- | 🎮️ [Discord Server](https://discord.gg/3qme4XHNKN) | [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN) | [Let's](https://discord.gg/3qme4XHNKN) | [talk](https://discord.gg/3qme4XHNKN) | [about](https://discord.gg/3qme4XHNKN) | [this](https://discord.gg/3qme4XHNKN) | [library\!](https://discord.gg/3qme4XHNKN) |
279
+ | 🧪 [kettle-rb/json-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
280
+ | 🧊 [kettle-rb/json-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
281
+ | 🐙 [kettle-rb/json-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
282
+ | 🎮️ [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] |
277
283
 
278
284
  </details>
279
285
 
280
286
  [gh-discussions]: https://github.com/kettle-rb/json-merge/discussions
281
287
 
282
- ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/json-merge)](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_source=rubygems-json-merge&utm_medium=referral&utm_campaign=readme)
288
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/json-merge)][🏙️entsup-tidelift]
283
289
 
284
290
  Available as part of the Tidelift Subscription.
285
291
 
@@ -288,33 +294,34 @@ Available as part of the Tidelift Subscription.
288
294
 
289
295
  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.
290
296
 
291
- [![Get help from me on Tidelift](https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white)](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_source=rubygems-json-merge&utm_medium=referral&utm_campaign=readme)
297
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
292
298
 
293
299
  - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
294
300
 
295
- - 💡Tidelift is part of [Sonar](https://blog.tidelift.com/tidelift-joins-sonar)
301
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
296
302
 
297
- - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_source=rubygems-json-merge&utm_medium=referral&utm_campaign=readme) subscription is "[never gonna let you down](https://www.youtube.com/watch?v=dQw4w9WgXcQ)", and *supports* open source maintainers
303
+ - 💡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
298
304
  Alternatively:
299
305
 
300
- - [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
306
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
307
+
308
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
301
309
 
302
- - [![Get help from me on Upwork](https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white)](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share)
310
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
303
311
 
304
- - [![Get help from me on Codementor](https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white)](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github)
305
312
  </details>
306
313
 
307
314
  ## ✨ Installation
308
315
 
309
316
  Install the gem and add to the application's Gemfile by executing:
310
317
 
311
- ``` console
318
+ ```console
312
319
  bundle add json-merge
313
320
  ```
314
321
 
315
322
  If bundler is not being used to manage dependencies, install the gem by executing:
316
323
 
317
- ``` console
324
+ ```console
318
325
  gem install json-merge
319
326
  ```
320
327
 
@@ -323,19 +330,19 @@ gem install json-merge
323
330
  <details markdown="1">
324
331
  <summary>For Medium or High Security Installations</summary>
325
332
 
326
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512](https://gitlab.com/kettle-rb/json-merge/-/tree/main/checksums) checksums by
327
- [stone\_checksums](https://github.com/galtzo-floss/stone_checksums). Be sure the gem you install hasn’t been tampered with
333
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
334
+ [stone\_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
328
335
  by following the instructions below.
329
336
 
330
337
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
331
338
 
332
- ``` console
339
+ ```console
333
340
  gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
334
341
  ```
335
342
 
336
343
  You only need to do that once. Then proceed to install with:
337
344
 
338
- ``` console
345
+ ```console
339
346
  gem install json-merge -P HighSecurity
340
347
  ```
341
348
 
@@ -343,7 +350,7 @@ The `HighSecurity` trust profile will verify signed gems, and not allow the inst
343
350
 
344
351
  If you want to up your security game full-time:
345
352
 
346
- ``` console
353
+ ```console
347
354
  bundle config set --global trust-policy MediumSecurity
348
355
  ```
349
356
 
@@ -358,14 +365,15 @@ NOTE: Be prepared to track down certs for signed gems and add them the same way
358
365
  This gem requires the `tree-sitter-json` parser library to be installed on your system.
359
366
  The parser is a native shared library (`.so` on Linux, `.dylib` on macOS) that provides
360
367
  JSON syntax parsing capabilities. For JSONC (JSON with Comments) support, use the
361
- [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) gem instead.
368
+ [jsonc-merge][jsonc-merge] gem instead.
362
369
 
363
370
  #### Option 1: Pre-built Binaries (Recommended)
364
371
 
365
372
  Download pre-built parsers from [Faveod/tree-sitter-parsers](https://github.com/Faveod/tree-sitter-parsers/releases):
366
373
 
367
374
  **Linux (x64):**
368
- ``` console
375
+
376
+ ```console
369
377
  # Download and extract
370
378
  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
371
379
  tar -xzf parsers.tar.gz
@@ -381,13 +389,15 @@ export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.s
381
389
  ```
382
390
 
383
391
  **Debian/Ubuntu (amd64):**
384
- ``` console
392
+
393
+ ```console
385
394
  curl -Lo parsers.deb https://github.com/Faveod/tree-sitter-parsers/releases/download/v4.10/tree-sitter-parsers-4.10-amd64.deb
386
395
  sudo dpkg -i parsers.deb
387
396
  ```
388
397
 
389
398
  **macOS (Apple Silicon):**
390
- ``` console
399
+
400
+ ```console
391
401
  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
392
402
  tar -xzf parsers.tar.gz
393
403
 
@@ -399,7 +409,7 @@ export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.d
399
409
 
400
410
  #### Option 2: Build from Source
401
411
 
402
- ``` console
412
+ ```console
403
413
  git clone https://github.com/tree-sitter/tree-sitter-json.git
404
414
  cd tree-sitter-json
405
415
  make
@@ -413,7 +423,8 @@ sudo cp libtree-sitter-json.dylib /usr/local/lib/ # macOS
413
423
  Some package managers provide tree-sitter parsers:
414
424
 
415
425
  **Fedora Atomic (Silverblue, Kinoite, Bazzite, Aurora, etc.):**
416
- ``` console
426
+
427
+ ```console
417
428
  # Install via rpm-ostree (requires reboot)
418
429
  rpm-ostree install libtree-sitter-json
419
430
 
@@ -423,12 +434,14 @@ export TREE_SITTER_JSON_PATH="/usr/lib64/libtree-sitter-json.so"
423
434
  ```
424
435
 
425
436
  **Fedora (traditional):**
426
- ``` console
437
+
438
+ ```console
427
439
  sudo dnf install libtree-sitter-json
428
440
  ```
429
441
 
430
442
  **Arch Linux:**
431
- ``` console
443
+
444
+ ```console
432
445
  # Check AUR for tree-sitter-json
433
446
  yay -S tree-sitter-json
434
447
  ```
@@ -438,16 +451,18 @@ yay -S tree-sitter-json
438
451
  If the parser is not in a standard location (`/usr/lib/`, `/usr/lib64/`, `/usr/local/lib/`),
439
452
  set the `TREE_SITTER_JSON_PATH` environment variable to point to the parser library:
440
453
 
441
- ``` console
454
+ ```console
442
455
  export TREE_SITTER_JSON_PATH="/path/to/libtree-sitter-json.so"
443
456
  ```
444
457
 
445
458
  **Note:** Some distributions install the library with a version number suffix
446
459
  (e.g., `libtree-sitter-json.so.14` instead of `libtree-sitter-json.so`).
447
460
  If the gem can't find the parser, check for versioned files and either:
461
+
448
462
  - Set `TREE_SITTER_JSON_PATH` to the full versioned path, or
449
463
  - Create a symlink: `sudo ln -s /usr/lib64/libtree-sitter-json.so.14 /usr/lib64/libtree-sitter-json.so`
450
464
  Add this to your shell profile (`.bashrc`, `.zshrc`, etc.) for persistence.
465
+
451
466
  ### 💎 Ruby Interface Gems
452
467
 
453
468
  In addition to the tree-sitter parser library, you need a Ruby gem that provides
@@ -455,9 +470,9 @@ bindings to tree-sitter. Choose **one** of the following based on your Ruby impl
455
470
 
456
471
  | Gem | Ruby Support | Description |
457
472
  | --- | --- | --- |
458
- | [ruby\_tree\_sitter](https://github.com/Faveod/ruby_tree_sitter) | MRI only | C extension bindings (recommended for MRI) |
459
- | [tree\_stump](https://github.com/nickstenning/tree_stump) | MRI (maybe JRuby) | Rust-based bindings via Rutie |
460
- | [ffi](https://github.com/ffi/ffi) | MRI, JRuby, TruffleRuby | Generic FFI bindings (used by tree\_haver's FFI backend) |
473
+ | [ruby\_tree\_sitter][ruby_tree_sitter] | MRI only | C extension bindings (recommended for MRI) |
474
+ | [tree\_stump][tree_stump] | MRI (maybe JRuby) | Rust-based bindings via Rutie |
475
+ | [ffi][ffi] | MRI, JRuby, TruffleRuby | Generic FFI bindings (used by tree\_haver's FFI backend) |
461
476
 
462
477
  [ruby_tree_sitter]: https://github.com/Faveod/ruby_tree_sitter
463
478
  [tree_stump]: https://github.com/nickstenning/tree_stump
@@ -465,25 +480,25 @@ bindings to tree-sitter. Choose **one** of the following based on your Ruby impl
465
480
 
466
481
  #### For MRI Ruby (Recommended)
467
482
 
468
- ``` console
483
+ ```console
469
484
  gem install ruby_tree_sitter
470
485
  ```
471
486
 
472
487
  Or add to your Gemfile:
473
488
 
474
- ``` ruby
489
+ ```ruby
475
490
  gem "ruby_tree_sitter", "~> 2.0"
476
491
  ```
477
492
 
478
493
  #### For JRuby or TruffleRuby
479
494
 
480
- ``` console
495
+ ```console
481
496
  gem install ffi
482
497
  ```
483
498
 
484
499
  Or add to your Gemfile:
485
500
 
486
- ``` ruby
501
+ ```ruby
487
502
  gem "ffi"
488
503
  ```
489
504
 
@@ -499,7 +514,7 @@ you must use the FFI backend.
499
514
 
500
515
  Control which version to use when nodes have matching signatures but different content:
501
516
 
502
- ``` ruby
517
+ ```ruby
503
518
  # Use template version (for config updates)
504
519
  merger = Json::Merge::SmartMerger.new(
505
520
  template,
@@ -519,7 +534,7 @@ merger = Json::Merge::SmartMerger.new(
519
534
 
520
535
  Control whether to add nodes that only exist in the template:
521
536
 
522
- ``` ruby
537
+ ```ruby
523
538
  # Add template-only nodes
524
539
  merger = Json::Merge::SmartMerger.new(
525
540
  template,
@@ -536,8 +551,10 @@ When JSON object properties (key-value pairs) don't match by exact key name, the
536
551
  - Similar key names (e.g., `databaseUrl` vs `database_url`)
537
552
  - Keys with typos or different naming conventions (camelCase vs snake\_case)
538
553
  - Array elements with similar structure or content
554
+
539
555
  <!-- end list -->
540
- ``` ruby
556
+
557
+ ```ruby
541
558
  # Enable object fuzzy matching
542
559
  merger = Json::Merge::SmartMerger.new(
543
560
  template,
@@ -556,7 +573,7 @@ merger = Json::Merge::SmartMerger.new(
556
573
  | `key_weight` | 0.7 | Weight for key name similarity |
557
574
  | `value_weight` | 0.3 | Weight for value similarity |
558
575
 
559
- ``` ruby
576
+ ```ruby
560
577
  # Custom weights for key-centric matching
561
578
  refiner = Json::Merge::ObjectMatchRefiner.new(
562
579
  threshold: 0.6,
@@ -569,7 +586,7 @@ refiner = Json::Merge::ObjectMatchRefiner.new(
569
586
 
570
587
  Enable debug logging to see merge decisions:
571
588
 
572
- ``` bash
589
+ ```bash
573
590
  export JSON_MERGE_DEBUG=1
574
591
  ```
575
592
 
@@ -577,7 +594,7 @@ export JSON_MERGE_DEBUG=1
577
594
 
578
595
  ### Merging Two JSON Files
579
596
 
580
- ``` ruby
597
+ ```ruby
581
598
  require "json/merge"
582
599
 
583
600
  template_content = File.read("template.json")
@@ -591,7 +608,7 @@ File.write("merged.json", result.to_json)
591
608
 
592
609
  ### Analyzing a JSON File
593
610
 
594
- ``` ruby
611
+ ```ruby
595
612
  require "json/merge"
596
613
 
597
614
  source = File.read("config.json")
@@ -609,7 +626,7 @@ end
609
626
  When property names differ between template and destination (e.g., naming convention changes),
610
627
  use the `ObjectMatchRefiner`:
611
628
 
612
- ``` ruby
629
+ ```ruby
613
630
  require "json/merge"
614
631
 
615
632
  template = <<~JSON
@@ -649,7 +666,7 @@ result = merger.merge
649
666
 
650
667
  The `ObjectMatchRefiner` also handles array elements with similar structure:
651
668
 
652
- ``` ruby
669
+ ```ruby
653
670
  template = <<~JSON
654
671
  {
655
672
  "users": [
@@ -685,17 +702,17 @@ Raising a monthly budget of... "dollars" would make the project more sustainable
685
702
 
686
703
  We welcome both individual and corporate sponsors\! We also offer a
687
704
  wide array of funding channels to account for your preferences
688
- (although currently [Open Collective](https://opencollective.com/kettle-rb) is our preferred funding platform).
705
+ (although currently [Open Collective][🖇osc] is our preferred funding platform).
689
706
 
690
707
  **If you're working in a company that's making significant use of kettle-rb tools we'd
691
708
  appreciate it if you suggest to your company to become a kettle-rb sponsor.**
692
709
 
693
710
  You can support the development of kettle-rb tools via
694
- [GitHub Sponsors](https://github.com/sponsors/pboling),
695
- [Liberapay](https://liberapay.com/pboling/donate),
696
- [PayPal](https://www.paypal.com/paypalme/peterboling),
697
- [Open Collective](https://opencollective.com/kettle-rb)
698
- and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_source=rubygems-json-merge&utm_medium=referral&utm_campaign=readme).
711
+ [GitHub Sponsors][🖇sponsor],
712
+ [Liberapay][⛳liberapay],
713
+ [PayPal][🖇paypal],
714
+ [Open Collective][🖇osc]
715
+ and [Tidelift][🏙️entsup-tidelift].
699
716
 
700
717
  | 📍 NOTE |
701
718
  | --- |
@@ -703,22 +720,22 @@ and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_sou
703
720
 
704
721
  ### Open Collective for Individuals
705
722
 
706
- Support us with a monthly donation and help us continue our activities. \[[Become a backer](https://opencollective.com/kettle-rb#backer)\]
723
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
707
724
 
708
- NOTE: [kettle-readme-backers](https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
725
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
709
726
 
710
727
  <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
711
- No backers yet. Be the first\!
728
+ No backers yet. Be the first!
712
729
  <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
713
730
 
714
731
  ### Open Collective for Organizations
715
732
 
716
- Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor](https://opencollective.com/kettle-rb#sponsor)\]
733
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
717
734
 
718
- NOTE: [kettle-readme-backers](https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
735
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
719
736
 
720
737
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
721
- No sponsors yet. Be the first\!
738
+ No sponsors yet. Be the first!
722
739
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
723
740
 
724
741
  [kettle-readme-backers]: https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers
@@ -729,48 +746,48 @@ I’m driven by a passion to foster a thriving open-source community – a space
729
746
 
730
747
  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`.
731
748
 
732
- I’m developing a new library, [floss\_funding](https://github.com/galtzo-floss/floss_funding), 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.
749
+ 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.
733
750
 
734
- **[Floss-Funding.dev](https://floss-funding.dev): 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
751
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
735
752
 
736
- [![OpenCollective Backers](https://opencollective.com/kettle-rb/backers/badge.svg?style=flat)](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors](https://opencollective.com/kettle-rb/sponsors/badge.svg?style=flat)](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github](https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github)](https://github.com/sponsors/pboling) [![Liberapay Goal Progress](https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat)](https://liberapay.com/pboling/donate) [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal)](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee](https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat)](https://www.buymeacoffee.com/pboling) [![Donate on Polar](https://img.shields.io/badge/polar-donate-a51611.svg?style=flat)](https://polar.sh/pboling) [![Donate to my FLOSS efforts at ko-fi.com](https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat)](https://ko-fi.com/O5O86SNP4) [![Donate to my FLOSS efforts using Patreon](https://img.shields.io/badge/patreon-donate-a51611.svg?style=flat)](https://patreon.com/galtzo)
753
+ [![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]
737
754
 
738
755
  ## 🔐 Security
739
756
 
740
- See [SECURITY.md](SECURITY.md).
757
+ See [SECURITY.md][🔐security].
741
758
 
742
759
  ## 🤝 Contributing
743
760
 
744
761
  If you need some ideas of where to help, you could work on adding more code coverage,
745
- or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues](https://github.com/kettle-rb/json-merge/issues), or [PRs](https://github.com/kettle-rb/json-merge/pulls),
762
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
746
763
  or use the gem and think about how it could be better.
747
764
 
748
- We [![Keep A Changelog](https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat)](https://keepachangelog.com/en/1.0.0/) so if you make changes, remember to update it.
765
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
749
766
 
750
- See [CONTRIBUTING.md](CONTRIBUTING.md) for more detailed instructions.
767
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
751
768
 
752
769
  ### 🚀 Release Instructions
753
770
 
754
- See [CONTRIBUTING.md](CONTRIBUTING.md).
771
+ See [CONTRIBUTING.md][🤝contributing].
755
772
 
756
773
  ### Code Coverage
757
774
 
758
- [![Coverage Graph](https://codecov.io/gh/kettle-rb/json-merge/graphs/tree.svg)](https://codecov.io/gh/kettle-rb/json-merge)
775
+ [![Coverage Graph][🏀codecov-g]][🏀codecov]
759
776
 
760
- [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/json-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/json-merge?branch=main)
777
+ [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
761
778
 
762
- [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/json-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/json-merge/metrics/code?sort=coverageRating)
779
+ [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
763
780
 
764
781
  ### 🪇 Code of Conduct
765
782
 
766
783
  Everyone interacting with this project's codebases, issue trackers,
767
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1](https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg)](CODE_OF_CONDUCT.md).
784
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
768
785
 
769
786
  ## 🌈 Contributors
770
787
 
771
- [![Contributors](https://contrib.rocks/image?repo=kettle-rb/json-merge)](https://github.com/kettle-rb/json-merge/graphs/contributors)
788
+ [![Contributors][🖐contributors-img]][🖐contributors]
772
789
 
773
- Made with [contributors-img](https://contrib.rocks).
790
+ Made with [contributors-img][🖐contrib-rocks].
774
791
 
775
792
  Also see GitLab Contributors: <https://gitlab.com/kettle-rb/json-merge/-/graphs/main>
776
793
 
@@ -789,23 +806,23 @@ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/json-merge/-/graphs/
789
806
 
790
807
  ## 📌 Versioning
791
808
 
792
- This Library adheres to [![Semantic Versioning 2.0.0](https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat)](https://semver.org/spec/v2.0.0.html).
809
+ This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
793
810
  Violations of this scheme should be reported as bugs.
794
811
  Specifically, if a minor or patch version is released that breaks backward compatibility,
795
812
  a new version should be immediately released that restores compatibility.
796
813
  Breaking changes to the public API will only be introduced with new major versions.
797
814
 
798
815
  > dropping support for a platform is both obviously and objectively a breaking change <br/>
799
- > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716](https://github.com/semver/semver/issues/716#issuecomment-869336139)
816
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
800
817
 
801
818
  I understand that policy doesn't work universally ("exceptions to every rule\!"),
802
819
  but it is the policy here.
803
820
  As such, in many cases it is good to specify a dependency on this library using
804
- the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision.
821
+ the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
805
822
 
806
823
  For example:
807
824
 
808
- ``` ruby
825
+ ```ruby
809
826
  spec.add_dependency("json-merge", "~> 1.0")
810
827
  ```
811
828
 
@@ -818,16 +835,17 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
818
835
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
819
836
  read this article from the creator of SemVer:
820
837
 
821
- - ["Major Version Numbers are Not Sacred"](https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html)
838
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
839
+
822
840
  </details>
823
841
 
824
- See [CHANGELOG.md](CHANGELOG.md) for a list of releases.
842
+ See [CHANGELOG.md][📌changelog] for a list of releases.
825
843
 
826
844
  ## 📄 License
827
845
 
828
846
  The gem is available as open source under the terms of
829
- the [MIT License](LICENSE.txt) [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT).
830
- See [LICENSE.txt](LICENSE.txt) for the official [Copyright Notice](https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year).
847
+ the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
848
+ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
831
849
 
832
850
  ### © Copyright
833
851
 
@@ -854,11 +872,11 @@ Please consider sponsoring me or the project.
854
872
 
855
873
  To join the community or get help 👇️ Join the Discord.
856
874
 
857
- [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
875
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
858
876
 
859
877
  To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
860
878
 
861
- [![Sponsor kettle-rb/json-merge on Open Source Collective](https://img.shields.io/opencollective/all/kettle-rb?style=for-the-badge)](https://opencollective.com/kettle-rb) 💌 [![Sponsor me on GitHub Sponsors](https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github)](https://github.com/sponsors/pboling) 💌 [![Sponsor me on Liberapay](https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611)](https://liberapay.com/pboling/donate) 💌 [![Donate on PayPal](https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A)](https://www.paypal.com/paypalme/peterboling)
879
+ [![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]
862
880
 
863
881
  ### Please give the project a star ⭐ ♥.
864
882
 
@@ -899,7 +917,6 @@ Thanks for RTFM. ☺️
899
917
  [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
900
918
  [✉️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
901
919
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
902
-
903
920
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
904
921
  [⛳️gem-namespace]: https://github.com/kettle-rb/json-merge
905
922
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Json::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
@@ -1023,7 +1040,7 @@ Thanks for RTFM. ☺️
1023
1040
  [📌gitmoji]: https://gitmoji.dev
1024
1041
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1025
1042
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1026
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.615-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1043
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.631-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1027
1044
  [🔐security]: SECURITY.md
1028
1045
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1029
1046
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -13,14 +13,16 @@ module Json
13
13
  #
14
14
  # @param template_analysis [FileAnalysis] Analyzed template file
15
15
  # @param dest_analysis [FileAnalysis] Analyzed destination file
16
- # @param preference [Symbol] Which version to prefer when
16
+ # @param preference [Symbol, Hash] Which version to prefer when
17
17
  # nodes have matching signatures:
18
18
  # - :destination (default) - Keep destination version (customizations)
19
19
  # - :template - Use template version (updates)
20
20
  # @param add_template_only_nodes [Boolean] Whether to add nodes only in template
21
21
  # @param match_refiner [#call, nil] Optional match refiner for fuzzy matching
22
22
  # @param options [Hash] Additional options for forward compatibility
23
- def initialize(template_analysis, dest_analysis, preference: :destination, add_template_only_nodes: false, match_refiner: nil, **options)
23
+ # @param node_typing [Hash{Symbol,String => #call}, nil] Node typing configuration
24
+ # for per-node-type preferences
25
+ def initialize(template_analysis, dest_analysis, preference: :destination, add_template_only_nodes: false, match_refiner: nil, node_typing: nil, **options)
24
26
  super(
25
27
  strategy: :batch,
26
28
  preference: preference,
@@ -30,6 +32,7 @@ module Json
30
32
  match_refiner: match_refiner,
31
33
  **options
32
34
  )
35
+ @node_typing = node_typing
33
36
  @emitter = Emitter.new
34
37
  end
35
38
 
@@ -168,14 +171,14 @@ module Json
168
171
 
169
172
  # Emit closing brace
170
173
  @emitter.emit_nested_object_end
171
- elsif @preference == :destination
174
+ elsif preference_for_pair(template_node, dest_node) == :destination
172
175
  # Values are not both objects, or one/both are arrays - use preference and emit
173
176
  # Arrays are always replaced, not merged
174
177
  emit_node(dest_node, dest_analysis)
175
178
  else
176
179
  emit_node(template_node, template_analysis)
177
180
  end
178
- elsif @preference == :destination
181
+ elsif preference_for_pair(template_node, dest_node) == :destination
179
182
  # Leaf nodes or mismatched types - use preference
180
183
  emit_node(dest_node, dest_analysis)
181
184
  else
@@ -215,6 +218,32 @@ module Json
215
218
  end
216
219
  end
217
220
 
221
+ def preference_for_pair(template_node, dest_node)
222
+ return @preference unless @preference.is_a?(Hash)
223
+
224
+ typed_template = apply_node_typing(template_node)
225
+ typed_dest = apply_node_typing(dest_node)
226
+
227
+ if Ast::Merge::NodeTyping.typed_node?(typed_template)
228
+ merge_type = Ast::Merge::NodeTyping.merge_type_for(typed_template)
229
+ return @preference.fetch(merge_type) { default_preference } if merge_type
230
+ end
231
+
232
+ if Ast::Merge::NodeTyping.typed_node?(typed_dest)
233
+ merge_type = Ast::Merge::NodeTyping.merge_type_for(typed_dest)
234
+ return @preference.fetch(merge_type) { default_preference } if merge_type
235
+ end
236
+
237
+ default_preference
238
+ end
239
+
240
+ def apply_node_typing(node)
241
+ return node unless @node_typing
242
+ return node unless node
243
+
244
+ Ast::Merge::NodeTyping.process(node, @node_typing)
245
+ end
246
+
218
247
  # Emit a single node to the emitter
219
248
  # @param node [NodeWrapper] Node to emit
220
249
  # @param analysis [FileAnalysis] Analysis for accessing source
@@ -120,6 +120,7 @@ module Json
120
120
  preference: @preference,
121
121
  add_template_only_nodes: @add_template_only_nodes,
122
122
  match_refiner: @match_refiner,
123
+ node_typing: @node_typing,
123
124
  )
124
125
  end
125
126
 
@@ -5,7 +5,7 @@ module Json
5
5
  # Version information for Json::Merge
6
6
  module Version
7
7
  # Current version of the json-merge gem
8
- VERSION = "1.1.0"
8
+ VERSION = "1.1.1"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data.tar.gz.sig CHANGED
@@ -1 +1 @@
1
- 5k����R�WG���&�W#5s �l� �� ��v����jJ[fp���"s��Q��<�X��$29:y�jH��M�i�����ˏ�ޚm��_��nZ�7E{B��W�k�F6�Zl&�eפ j)\ıJo�:(A9� �ٹ��q��_^�~��@#��~��?7V�z���@�AKɧ%3H���N$ �D��^��j|���2޳
1
+ i��v�dk��c-�\'��șh\V
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -46,7 +46,7 @@ dependencies:
46
46
  version: '5.0'
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 5.0.1
49
+ version: 5.0.2
50
50
  type: :runtime
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
@@ -56,7 +56,7 @@ dependencies:
56
56
  version: '5.0'
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 5.0.1
59
+ version: 5.0.2
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: ast-merge
62
62
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: '4.0'
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 4.0.2
69
+ version: 4.0.4
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '4.0'
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: 4.0.2
79
+ version: 4.0.4
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: version_gem
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -294,10 +294,10 @@ licenses:
294
294
  - MIT
295
295
  metadata:
296
296
  homepage_uri: https://json-merge.galtzo.com/
297
- source_code_uri: https://github.com/kettle-rb/json-merge/tree/v1.1.0
298
- changelog_uri: https://github.com/kettle-rb/json-merge/blob/v1.1.0/CHANGELOG.md
297
+ source_code_uri: https://github.com/kettle-rb/json-merge/tree/v1.1.1
298
+ changelog_uri: https://github.com/kettle-rb/json-merge/blob/v1.1.1/CHANGELOG.md
299
299
  bug_tracker_uri: https://github.com/kettle-rb/json-merge/issues
300
- documentation_uri: https://www.rubydoc.info/gems/json-merge/1.1.0
300
+ documentation_uri: https://www.rubydoc.info/gems/json-merge/1.1.1
301
301
  funding_uri: https://github.com/sponsors/pboling
302
302
  wiki_uri: https://github.com/kettle-rb/json-merge/wiki
303
303
  news_uri: https://www.railsbling.com/tags/json-merge
metadata.gz.sig CHANGED
Binary file