json-merge 1.1.0 → 1.1.2

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: 38f954bb103511024a69c2d85caa277ff1de782b88cd1c9b77ff0ae4809b6568
4
+ data.tar.gz: 5beaadc8745638f82acac95e7d62be37dbfce579a250cde95cc9efafa329463c
5
5
  SHA512:
6
- metadata.gz: d4810ca402f5af373769e6a69a73ace769f6d6f11e61c3d7a2a1b1186672387bc41f92b40fc74a327648a856d38547a60b120583fddd3329b17941b0e0ea51e9
7
- data.tar.gz: 1e04ca747b1f07f3177626e351947c9dd40cd78f810d1b285925a3c0bee0bbeecfca2891872b53b288d33ab66fb171b0f4ad3d84dc919f2ddf75b0d181b3fbb4
6
+ metadata.gz: 3b6b6dc2287465a4789a78bdc32cbbb317924ead1bf24305642946b21a5b1dece510e829cde881f2c23d1f3a31d31a789812bfe23fc7dc38e6f7729ce9953837
7
+ data.tar.gz: 210cfe2fa6b47a09f0949feddf641e57a499c939df837de420df8f0e7f0c4401b778922f6f1aa7a41ef9e645c2fe1a5be2330617deeaa7abb4ee15e1922e94db
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,45 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.1.2] - 2026-02-19
34
+
35
+ - TAG: [v1.1.2][1.1.2t]
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
+ - AGENTS.md
43
+
44
+ ### Changed
45
+
46
+ - appraisal2 v3.0.6
47
+ - kettle-test v1.0.10
48
+ - stone_checksums v1.0.3
49
+ - [ast-merge v4.0.6](https://github.com/kettle-rb/ast-merge/releases/tag/v4.0.6)
50
+ - [tree_haver v5.0.5](https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.5)
51
+ - tree_stump v0.2.0
52
+ - fork no longer required, updates all applied upstream
53
+ - Updated documentation on hostile takeover of RubyGems
54
+ - https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo
55
+
56
+ ## [1.1.1] - 2026-01-26
57
+
58
+ - TAG: [v1.1.1][1.1.1t]
59
+ - COVERAGE: 95.72% -- 604/631 lines in 10 files
60
+ - BRANCH COVERAGE: 77.81% -- 235/302 branches in 10 files
61
+ - 96.63% documented
62
+
63
+ ### Added
64
+
65
+ - ConflictResolver now applies per-node-type preferences via `node_typing`.
66
+
67
+ ### Changed
68
+
69
+ - Upgrade to [ast-merge v4.0.4](https://github.com/kettle-rb/ast-merge/releases/tag/v4.0.4)
70
+ - Upgrade to [tree_haver v5.0.2](https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.2)
71
+
33
72
  ## [1.1.0] - 2026-01-12
34
73
 
35
74
  - TAG: [v1.1.0][1.1.0t]
@@ -49,9 +88,9 @@ Please file a bug if you notice a violation of semantic versioning.
49
88
 
50
89
  ### Changed
51
90
 
52
- - ast-merge v4.0.2
91
+ - Upgrade to [ast-merge v4.0.2](https://github.com/kettle-rb/ast-merge/releases/tag/v4.0.2)
53
92
  - Includes Ast::Merge::EmitterBase
54
- - tree_haver v5.0.1
93
+ - Upgrade to [tree_haver v5.0.1](https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.1)
55
94
  - Many Backend improvements
56
95
  - Many error handling improvements
57
96
  - **Simplified dependency_tags.rb**: Removed redundant debug code
@@ -97,7 +136,13 @@ Please file a bug if you notice a violation of semantic versioning.
97
136
 
98
137
  ### Security
99
138
 
100
- [Unreleased]: https://github.com/kettle-rb/json-merge/compare/v1.1.0...HEAD
139
+ [Unreleased]: https://github.com/kettle-rb/json-merge/compare/v1.1.2...HEAD
140
+ [1.1.3]: https://github.com/kettle-rb/json-merge/compare/v1.1.2...v1.1.3
141
+ [1.1.3t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.3
142
+ [1.1.2]: https://github.com/kettle-rb/json-merge/compare/v1.1.1...v1.1.2
143
+ [1.1.2t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.2
144
+ [1.1.1]: https://github.com/kettle-rb/json-merge/compare/v1.1.0...v1.1.1
145
+ [1.1.1t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.1
101
146
  [1.1.0]: https://github.com/kettle-rb/json-merge/compare/v1.0.0...v1.1.0
102
147
  [1.1.0t]: https://github.com/kettle-rb/json-merge/releases/tag/v1.1.0
103
148
  [1.0.0]: https://github.com/kettle-rb/json-merge/compare/f1cc25b1d9b79c598270e3aa203fa56787e6c6fc...v1.0.0
data/README.md CHANGED
@@ -1,37 +1,4 @@
1
- | 📍 NOTE |
2
- | --- |
3
- | RubyGems (the [GitHub org][rubygems-org], not the website) [suffered][draper-security] a [hostile takeover][ellen-takeover] in September 2025. |
4
- | Ultimately [4 maintainers][simi-removed] were [hard removed][martin-removed] and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
- | It is a [complicated story][draper-takeover] which is difficult to [parse quickly][draper-lies]. |
6
- | Simply put - there was active policy for adding or removing maintainers/owners of [rubygems][rubygems-maint-policy] and [bundler][bundler-maint-policy], and those [policies were not followed][policy-fail]. |
7
- | I'm adding notes like this to gems because I [don't condone theft][draper-theft] of repositories or gems from their rightful owners. |
8
- | If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
9
- | Disenfranchised former-maintainers have started [gem.coop][gem-coop]. |
10
- | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
11
- | The ["Technology for Humans: Joel Draper"][reinteractive-podcast] podcast episode by [reinteractive][reinteractive] is the most cogent summary I'm aware of. |
12
- | See [here][gem-naming], [here][gem-coop] and [here][martin-ann] for more info on what comes next. |
13
- | What I'm doing: A (WIP) proposal for [bundler/gem scopes][gem-scopes], and a (WIP) proposal for a federated [gem server][gem-server]. |
14
-
15
- [rubygems-org]: https://github.com/rubygems/
16
- [draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
17
- [draper-takeover]: https://joel.drapper.me/p/ruby-central-takeover/
18
- [ellen-takeover]: https://pup-e.com/blog/goodbye-rubygems/
19
- [simi-removed]: https://www.reddit.com/r/ruby/s/gOk42POCaV
20
- [martin-removed]: https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q
21
- [draper-lies]: https://joel.drapper.me/p/ruby-central-fact-check/
22
- [draper-theft]: https://joel.drapper.me/p/ruby-central/
23
- [reinteractive]: https://reinteractive.com/ruby-on-rails
24
- [gem-coop]: https://gem.coop
25
- [gem-naming]: https://github.com/gem-coop/gem.coop/issues/12
26
- [martin-ann]: https://martinemde.com/2025/10/05/announcing-gem-coop.html
27
- [gem-scopes]: https://github.com/galtzo-floss/bundle-namespace
28
- [gem-server]: https://github.com/galtzo-floss/gem-server
29
- [reinteractive-podcast]: https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6
30
- [bundler-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/bundler/playbooks/TEAM_CHANGES.md
31
- [rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
32
- [policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
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)
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]
35
2
 
36
3
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
37
4
  [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
@@ -42,20 +9,28 @@
42
9
 
43
10
  # ☯️ Json::Merge
44
11
 
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)
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]
46
13
 
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).
14
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
48
15
 
49
16
  -----
17
+
50
18
  `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
19
 
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)
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]
21
+
22
+ <details>
23
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
24
+
25
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
26
+
27
+ </details>
53
28
 
54
29
  ## 🌻 Synopsis
55
30
 
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.
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.
57
32
 
58
- For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) gem.
33
+ For JSONC (JSON with Comments) support, see the [jsonc-merge][jsonc-merge] gem.
59
34
 
60
35
  ### Key Features
61
36
 
@@ -68,9 +43,10 @@ For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com
68
43
  - **Customizable**:
69
44
  - `signature_generator` - callable custom signature generators
70
45
  - `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)
46
+ - `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge][ast-merge] docs)
72
47
  - `add_template_only_nodes` - setting to retain nodes that do not exist in destination
73
48
  - `match_refiners` - array of refiners for fuzzy matching (e.g., `ObjectMatchRefiner`)
49
+
74
50
  ### Supported Node Types
75
51
 
76
52
  | Node Type | Signature Format | Matching Behavior |
@@ -85,7 +61,7 @@ For JSONC (JSON with Comments) support, see the [jsonc-merge](https://github.com
85
61
 
86
62
  ### Example
87
63
 
88
- ``` ruby
64
+ ```ruby
89
65
  require "json/merge"
90
66
 
91
67
  template = File.read("template.json")
@@ -101,37 +77,38 @@ File.write("merged.json", result.to_json)
101
77
 
102
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.
103
79
 
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 |
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 |
119
95
 
120
96
  #### Backend Platform Compatibility
121
97
 
122
98
  tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
123
99
 
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 |
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]) |
135
112
 
136
113
  **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
137
114
 
@@ -225,6 +202,7 @@ tree_haver supports multiple parsing backends, but not all backends work on all
225
202
  [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
226
203
  [prism]: https://github.com/ruby/prism
227
204
  [psych]: https://github.com/ruby/psych
205
+ [ffi]: https://github.com/ffi/ffi
228
206
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
229
207
  [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
230
208
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
@@ -239,21 +217,23 @@ tree_haver supports multiple parsing backends, but not all backends work on all
239
217
  [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
240
218
  [tree_stump]: https://github.com/joker1007/tree_stump
241
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
242
222
 
243
223
  ## 💡 Info you can shake a stick at
244
224
 
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) |
225
+ | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
246
226
  | --- | --- |
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) |
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] |
232
+ | 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] |
234
+ | 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
+ | 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] |
257
237
 
258
238
  ### Compatibility
259
239
 
@@ -261,25 +241,25 @@ Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRu
261
241
 
262
242
  | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
263
243
  | --- | --- |
264
- | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2](https://github.com/appraisal-rb/appraisal2) ✨ |
244
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
265
245
 
266
246
  ### Federated DVCS
267
247
 
268
248
  <details markdown="1">
269
249
  <summary>Find this repo on federated forges (Coming soon!)</summary>
270
250
 
271
- | Federated [DVCS](https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/) Repository | Status | Issues | PRs | Wiki | CI | Discussions |
251
+ | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
272
252
  | --- | --- | --- | --- | --- | --- | --- |
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) |
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] |
277
257
 
278
258
  </details>
279
259
 
280
260
  [gh-discussions]: https://github.com/kettle-rb/json-merge/discussions
281
261
 
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)
262
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/json-merge)][🏙️entsup-tidelift]
283
263
 
284
264
  Available as part of the Tidelift Subscription.
285
265
 
@@ -288,33 +268,34 @@ Available as part of the Tidelift Subscription.
288
268
 
289
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.
290
270
 
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)
271
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
292
272
 
293
273
  - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
294
274
 
295
- - 💡Tidelift is part of [Sonar](https://blog.tidelift.com/tidelift-joins-sonar)
275
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
296
276
 
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
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
298
278
  Alternatively:
299
279
 
300
- - [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
280
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
281
+
282
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
301
283
 
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)
284
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
303
285
 
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
286
  </details>
306
287
 
307
288
  ## ✨ Installation
308
289
 
309
290
  Install the gem and add to the application's Gemfile by executing:
310
291
 
311
- ``` console
292
+ ```console
312
293
  bundle add json-merge
313
294
  ```
314
295
 
315
296
  If bundler is not being used to manage dependencies, install the gem by executing:
316
297
 
317
- ``` console
298
+ ```console
318
299
  gem install json-merge
319
300
  ```
320
301
 
@@ -323,19 +304,19 @@ gem install json-merge
323
304
  <details markdown="1">
324
305
  <summary>For Medium or High Security Installations</summary>
325
306
 
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
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
328
309
  by following the instructions below.
329
310
 
330
311
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
331
312
 
332
- ``` console
313
+ ```console
333
314
  gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
334
315
  ```
335
316
 
336
317
  You only need to do that once. Then proceed to install with:
337
318
 
338
- ``` console
319
+ ```console
339
320
  gem install json-merge -P HighSecurity
340
321
  ```
341
322
 
@@ -343,7 +324,7 @@ The `HighSecurity` trust profile will verify signed gems, and not allow the inst
343
324
 
344
325
  If you want to up your security game full-time:
345
326
 
346
- ``` console
327
+ ```console
347
328
  bundle config set --global trust-policy MediumSecurity
348
329
  ```
349
330
 
@@ -358,14 +339,15 @@ NOTE: Be prepared to track down certs for signed gems and add them the same way
358
339
  This gem requires the `tree-sitter-json` parser library to be installed on your system.
359
340
  The parser is a native shared library (`.so` on Linux, `.dylib` on macOS) that provides
360
341
  JSON syntax parsing capabilities. For JSONC (JSON with Comments) support, use the
361
- [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) gem instead.
342
+ [jsonc-merge][jsonc-merge] gem instead.
362
343
 
363
344
  #### Option 1: Pre-built Binaries (Recommended)
364
345
 
365
346
  Download pre-built parsers from [Faveod/tree-sitter-parsers](https://github.com/Faveod/tree-sitter-parsers/releases):
366
347
 
367
348
  **Linux (x64):**
368
- ``` console
349
+
350
+ ```console
369
351
  # Download and extract
370
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
371
353
  tar -xzf parsers.tar.gz
@@ -381,13 +363,15 @@ export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.s
381
363
  ```
382
364
 
383
365
  **Debian/Ubuntu (amd64):**
384
- ``` console
366
+
367
+ ```console
385
368
  curl -Lo parsers.deb https://github.com/Faveod/tree-sitter-parsers/releases/download/v4.10/tree-sitter-parsers-4.10-amd64.deb
386
369
  sudo dpkg -i parsers.deb
387
370
  ```
388
371
 
389
372
  **macOS (Apple Silicon):**
390
- ``` console
373
+
374
+ ```console
391
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
392
376
  tar -xzf parsers.tar.gz
393
377
 
@@ -399,7 +383,7 @@ export TREE_SITTER_JSON_PATH="$HOME/.local/lib/tree-sitter/libtree-sitter-json.d
399
383
 
400
384
  #### Option 2: Build from Source
401
385
 
402
- ``` console
386
+ ```console
403
387
  git clone https://github.com/tree-sitter/tree-sitter-json.git
404
388
  cd tree-sitter-json
405
389
  make
@@ -413,7 +397,8 @@ sudo cp libtree-sitter-json.dylib /usr/local/lib/ # macOS
413
397
  Some package managers provide tree-sitter parsers:
414
398
 
415
399
  **Fedora Atomic (Silverblue, Kinoite, Bazzite, Aurora, etc.):**
416
- ``` console
400
+
401
+ ```console
417
402
  # Install via rpm-ostree (requires reboot)
418
403
  rpm-ostree install libtree-sitter-json
419
404
 
@@ -423,12 +408,14 @@ export TREE_SITTER_JSON_PATH="/usr/lib64/libtree-sitter-json.so"
423
408
  ```
424
409
 
425
410
  **Fedora (traditional):**
426
- ``` console
411
+
412
+ ```console
427
413
  sudo dnf install libtree-sitter-json
428
414
  ```
429
415
 
430
416
  **Arch Linux:**
431
- ``` console
417
+
418
+ ```console
432
419
  # Check AUR for tree-sitter-json
433
420
  yay -S tree-sitter-json
434
421
  ```
@@ -438,16 +425,18 @@ yay -S tree-sitter-json
438
425
  If the parser is not in a standard location (`/usr/lib/`, `/usr/lib64/`, `/usr/local/lib/`),
439
426
  set the `TREE_SITTER_JSON_PATH` environment variable to point to the parser library:
440
427
 
441
- ``` console
428
+ ```console
442
429
  export TREE_SITTER_JSON_PATH="/path/to/libtree-sitter-json.so"
443
430
  ```
444
431
 
445
432
  **Note:** Some distributions install the library with a version number suffix
446
433
  (e.g., `libtree-sitter-json.so.14` instead of `libtree-sitter-json.so`).
447
434
  If the gem can't find the parser, check for versioned files and either:
435
+
448
436
  - Set `TREE_SITTER_JSON_PATH` to the full versioned path, or
449
437
  - Create a symlink: `sudo ln -s /usr/lib64/libtree-sitter-json.so.14 /usr/lib64/libtree-sitter-json.so`
450
438
  Add this to your shell profile (`.bashrc`, `.zshrc`, etc.) for persistence.
439
+
451
440
  ### 💎 Ruby Interface Gems
452
441
 
453
442
  In addition to the tree-sitter parser library, you need a Ruby gem that provides
@@ -455,9 +444,9 @@ bindings to tree-sitter. Choose **one** of the following based on your Ruby impl
455
444
 
456
445
  | Gem | Ruby Support | Description |
457
446
  | --- | --- | --- |
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) |
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) |
461
450
 
462
451
  [ruby_tree_sitter]: https://github.com/Faveod/ruby_tree_sitter
463
452
  [tree_stump]: https://github.com/nickstenning/tree_stump
@@ -465,25 +454,25 @@ bindings to tree-sitter. Choose **one** of the following based on your Ruby impl
465
454
 
466
455
  #### For MRI Ruby (Recommended)
467
456
 
468
- ``` console
457
+ ```console
469
458
  gem install ruby_tree_sitter
470
459
  ```
471
460
 
472
461
  Or add to your Gemfile:
473
462
 
474
- ``` ruby
463
+ ```ruby
475
464
  gem "ruby_tree_sitter", "~> 2.0"
476
465
  ```
477
466
 
478
467
  #### For JRuby or TruffleRuby
479
468
 
480
- ``` console
469
+ ```console
481
470
  gem install ffi
482
471
  ```
483
472
 
484
473
  Or add to your Gemfile:
485
474
 
486
- ``` ruby
475
+ ```ruby
487
476
  gem "ffi"
488
477
  ```
489
478
 
@@ -499,7 +488,7 @@ you must use the FFI backend.
499
488
 
500
489
  Control which version to use when nodes have matching signatures but different content:
501
490
 
502
- ``` ruby
491
+ ```ruby
503
492
  # Use template version (for config updates)
504
493
  merger = Json::Merge::SmartMerger.new(
505
494
  template,
@@ -519,7 +508,7 @@ merger = Json::Merge::SmartMerger.new(
519
508
 
520
509
  Control whether to add nodes that only exist in the template:
521
510
 
522
- ``` ruby
511
+ ```ruby
523
512
  # Add template-only nodes
524
513
  merger = Json::Merge::SmartMerger.new(
525
514
  template,
@@ -536,8 +525,10 @@ When JSON object properties (key-value pairs) don't match by exact key name, the
536
525
  - Similar key names (e.g., `databaseUrl` vs `database_url`)
537
526
  - Keys with typos or different naming conventions (camelCase vs snake\_case)
538
527
  - Array elements with similar structure or content
528
+
539
529
  <!-- end list -->
540
- ``` ruby
530
+
531
+ ```ruby
541
532
  # Enable object fuzzy matching
542
533
  merger = Json::Merge::SmartMerger.new(
543
534
  template,
@@ -556,7 +547,7 @@ merger = Json::Merge::SmartMerger.new(
556
547
  | `key_weight` | 0.7 | Weight for key name similarity |
557
548
  | `value_weight` | 0.3 | Weight for value similarity |
558
549
 
559
- ``` ruby
550
+ ```ruby
560
551
  # Custom weights for key-centric matching
561
552
  refiner = Json::Merge::ObjectMatchRefiner.new(
562
553
  threshold: 0.6,
@@ -569,7 +560,7 @@ refiner = Json::Merge::ObjectMatchRefiner.new(
569
560
 
570
561
  Enable debug logging to see merge decisions:
571
562
 
572
- ``` bash
563
+ ```bash
573
564
  export JSON_MERGE_DEBUG=1
574
565
  ```
575
566
 
@@ -577,7 +568,7 @@ export JSON_MERGE_DEBUG=1
577
568
 
578
569
  ### Merging Two JSON Files
579
570
 
580
- ``` ruby
571
+ ```ruby
581
572
  require "json/merge"
582
573
 
583
574
  template_content = File.read("template.json")
@@ -591,7 +582,7 @@ File.write("merged.json", result.to_json)
591
582
 
592
583
  ### Analyzing a JSON File
593
584
 
594
- ``` ruby
585
+ ```ruby
595
586
  require "json/merge"
596
587
 
597
588
  source = File.read("config.json")
@@ -609,7 +600,7 @@ end
609
600
  When property names differ between template and destination (e.g., naming convention changes),
610
601
  use the `ObjectMatchRefiner`:
611
602
 
612
- ``` ruby
603
+ ```ruby
613
604
  require "json/merge"
614
605
 
615
606
  template = <<~JSON
@@ -649,7 +640,7 @@ result = merger.merge
649
640
 
650
641
  The `ObjectMatchRefiner` also handles array elements with similar structure:
651
642
 
652
- ``` ruby
643
+ ```ruby
653
644
  template = <<~JSON
654
645
  {
655
646
  "users": [
@@ -685,17 +676,17 @@ Raising a monthly budget of... "dollars" would make the project more sustainable
685
676
 
686
677
  We welcome both individual and corporate sponsors\! We also offer a
687
678
  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).
679
+ (although currently [Open Collective][🖇osc] is our preferred funding platform).
689
680
 
690
681
  **If you're working in a company that's making significant use of kettle-rb tools we'd
691
682
  appreciate it if you suggest to your company to become a kettle-rb sponsor.**
692
683
 
693
684
  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).
685
+ [GitHub Sponsors][🖇sponsor],
686
+ [Liberapay][⛳liberapay],
687
+ [PayPal][🖇paypal],
688
+ [Open Collective][🖇osc]
689
+ and [Tidelift][🏙️entsup-tidelift].
699
690
 
700
691
  | 📍 NOTE |
701
692
  | --- |
@@ -703,22 +694,22 @@ and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-json-merge?utm_sou
703
694
 
704
695
  ### Open Collective for Individuals
705
696
 
706
- Support us with a monthly donation and help us continue our activities. \[[Become a backer](https://opencollective.com/kettle-rb#backer)\]
697
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
707
698
 
708
- NOTE: [kettle-readme-backers](https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
699
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
709
700
 
710
701
  <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
711
- No backers yet. Be the first\!
702
+ No backers yet. Be the first!
712
703
  <!-- OPENCOLLECTIVE-INDIVIDUALS:END -->
713
704
 
714
705
  ### Open Collective for Organizations
715
706
 
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)\]
707
+ Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
717
708
 
718
- NOTE: [kettle-readme-backers](https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
709
+ NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
719
710
 
720
711
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
721
- No sponsors yet. Be the first\!
712
+ No sponsors yet. Be the first!
722
713
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:END -->
723
714
 
724
715
  [kettle-readme-backers]: https://github.com/kettle-rb/json-merge/blob/main/exe/kettle-readme-backers
@@ -729,48 +720,48 @@ I’m driven by a passion to foster a thriving open-source community – a space
729
720
 
730
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`.
731
722
 
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.
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.
733
724
 
734
- **[Floss-Funding.dev](https://floss-funding.dev): 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
725
+ **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
735
726
 
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)
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]
737
728
 
738
729
  ## 🔐 Security
739
730
 
740
- See [SECURITY.md](SECURITY.md).
731
+ See [SECURITY.md][🔐security].
741
732
 
742
733
  ## 🤝 Contributing
743
734
 
744
735
  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),
736
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
746
737
  or use the gem and think about how it could be better.
747
738
 
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.
739
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
749
740
 
750
- See [CONTRIBUTING.md](CONTRIBUTING.md) for more detailed instructions.
741
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
751
742
 
752
743
  ### 🚀 Release Instructions
753
744
 
754
- See [CONTRIBUTING.md](CONTRIBUTING.md).
745
+ See [CONTRIBUTING.md][🤝contributing].
755
746
 
756
747
  ### Code Coverage
757
748
 
758
- [![Coverage Graph](https://codecov.io/gh/kettle-rb/json-merge/graphs/tree.svg)](https://codecov.io/gh/kettle-rb/json-merge)
749
+ [![Coverage Graph][🏀codecov-g]][🏀codecov]
759
750
 
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)
751
+ [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
761
752
 
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)
753
+ [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
763
754
 
764
755
  ### 🪇 Code of Conduct
765
756
 
766
757
  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).
758
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
768
759
 
769
760
  ## 🌈 Contributors
770
761
 
771
- [![Contributors](https://contrib.rocks/image?repo=kettle-rb/json-merge)](https://github.com/kettle-rb/json-merge/graphs/contributors)
762
+ [![Contributors][🖐contributors-img]][🖐contributors]
772
763
 
773
- Made with [contributors-img](https://contrib.rocks).
764
+ Made with [contributors-img][🖐contrib-rocks].
774
765
 
775
766
  Also see GitLab Contributors: <https://gitlab.com/kettle-rb/json-merge/-/graphs/main>
776
767
 
@@ -789,23 +780,23 @@ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/json-merge/-/graphs/
789
780
 
790
781
  ## 📌 Versioning
791
782
 
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).
783
+ This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
793
784
  Violations of this scheme should be reported as bugs.
794
785
  Specifically, if a minor or patch version is released that breaks backward compatibility,
795
786
  a new version should be immediately released that restores compatibility.
796
787
  Breaking changes to the public API will only be introduced with new major versions.
797
788
 
798
789
  > 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)
790
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
800
791
 
801
792
  I understand that policy doesn't work universally ("exceptions to every rule\!"),
802
793
  but it is the policy here.
803
794
  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.
795
+ the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
805
796
 
806
797
  For example:
807
798
 
808
- ``` ruby
799
+ ```ruby
809
800
  spec.add_dependency("json-merge", "~> 1.0")
810
801
  ```
811
802
 
@@ -818,16 +809,17 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
818
809
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
819
810
  read this article from the creator of SemVer:
820
811
 
821
- - ["Major Version Numbers are Not Sacred"](https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html)
812
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
813
+
822
814
  </details>
823
815
 
824
- See [CHANGELOG.md](CHANGELOG.md) for a list of releases.
816
+ See [CHANGELOG.md][📌changelog] for a list of releases.
825
817
 
826
818
  ## 📄 License
827
819
 
828
820
  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).
821
+ the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
822
+ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
831
823
 
832
824
  ### © Copyright
833
825
 
@@ -854,11 +846,11 @@ Please consider sponsoring me or the project.
854
846
 
855
847
  To join the community or get help 👇️ Join the Discord.
856
848
 
857
- [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
849
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
858
850
 
859
851
  To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
860
852
 
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)
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]
862
854
 
863
855
  ### Please give the project a star ⭐ ♥.
864
856
 
@@ -899,7 +891,6 @@ Thanks for RTFM. ☺️
899
891
  [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
900
892
  [✉️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
893
  [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
902
-
903
894
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
904
895
  [⛳️gem-namespace]: https://github.com/kettle-rb/json-merge
905
896
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Json::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
@@ -1023,7 +1014,7 @@ Thanks for RTFM. ☺️
1023
1014
  [📌gitmoji]: https://gitmoji.dev
1024
1015
  [📌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
1016
  [🧮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
1017
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.631-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1027
1018
  [🔐security]: SECURITY.md
1028
1019
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1029
1020
  [📄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.2"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data.tar.gz.sig CHANGED
Binary file
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.2
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.5
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.5
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.6
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.6
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: version_gem
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -166,6 +166,9 @@ dependencies:
166
166
  - - "~>"
167
167
  - !ruby/object:Gem::Version
168
168
  version: '3.0'
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: 3.0.6
169
172
  type: :development
170
173
  prerelease: false
171
174
  version_requirements: !ruby/object:Gem::Requirement
@@ -173,6 +176,9 @@ dependencies:
173
176
  - - "~>"
174
177
  - !ruby/object:Gem::Version
175
178
  version: '3.0'
179
+ - - "~>"
180
+ - !ruby/object:Gem::Version
181
+ version: 3.0.6
176
182
  - !ruby/object:Gem::Dependency
177
183
  name: kettle-test
178
184
  requirement: !ruby/object:Gem::Requirement
@@ -182,7 +188,7 @@ dependencies:
182
188
  version: '1.0'
183
189
  - - ">="
184
190
  - !ruby/object:Gem::Version
185
- version: 1.0.6
191
+ version: 1.0.10
186
192
  type: :development
187
193
  prerelease: false
188
194
  version_requirements: !ruby/object:Gem::Requirement
@@ -192,7 +198,7 @@ dependencies:
192
198
  version: '1.0'
193
199
  - - ">="
194
200
  - !ruby/object:Gem::Version
195
- version: 1.0.6
201
+ version: 1.0.10
196
202
  - !ruby/object:Gem::Dependency
197
203
  name: ruby-progressbar
198
204
  requirement: !ruby/object:Gem::Requirement
@@ -216,7 +222,7 @@ dependencies:
216
222
  version: '1.0'
217
223
  - - ">="
218
224
  - !ruby/object:Gem::Version
219
- version: 1.0.2
225
+ version: 1.0.3
220
226
  type: :development
221
227
  prerelease: false
222
228
  version_requirements: !ruby/object:Gem::Requirement
@@ -226,7 +232,7 @@ dependencies:
226
232
  version: '1.0'
227
233
  - - ">="
228
234
  - !ruby/object:Gem::Version
229
- version: 1.0.2
235
+ version: 1.0.3
230
236
  - !ruby/object:Gem::Dependency
231
237
  name: gitmoji-regex
232
238
  requirement: !ruby/object:Gem::Requirement
@@ -294,10 +300,10 @@ licenses:
294
300
  - MIT
295
301
  metadata:
296
302
  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
303
+ source_code_uri: https://github.com/kettle-rb/json-merge/tree/v1.1.2
304
+ changelog_uri: https://github.com/kettle-rb/json-merge/blob/v1.1.2/CHANGELOG.md
299
305
  bug_tracker_uri: https://github.com/kettle-rb/json-merge/issues
300
- documentation_uri: https://www.rubydoc.info/gems/json-merge/1.1.0
306
+ documentation_uri: https://www.rubydoc.info/gems/json-merge/1.1.2
301
307
  funding_uri: https://github.com/sponsors/pboling
302
308
  wiki_uri: https://github.com/kettle-rb/json-merge/wiki
303
309
  news_uri: https://www.railsbling.com/tags/json-merge
@@ -326,7 +332,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
326
332
  - !ruby/object:Gem::Version
327
333
  version: '0'
328
334
  requirements: []
329
- rubygems_version: 4.0.3
335
+ rubygems_version: 4.0.5
330
336
  specification_version: 4
331
337
  summary: "☯️ Intelligent JSON file merging using tree-sitter AST analysis"
332
338
  test_files: []
metadata.gz.sig CHANGED
Binary file