toml-merge 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,16 +1,16 @@
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]. |
1
+ | 📍 NOTE |
2
+ | --- |
3
+ | RubyGems (the [GitHub org](https://github.com/rubygems/), not the website) [suffered](https://joel.drapper.me/p/ruby-central-security-measures/) a [hostile takeover](https://pup-e.com/blog/goodbye-rubygems/) in September 2025. |
4
+ | Ultimately [4 maintainers](https://www.reddit.com/r/ruby/s/gOk42POCaV) were [hard removed](https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q) and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
+ | It is a [complicated story](https://joel.drapper.me/p/ruby-central-takeover/) which is difficult to [parse quickly](https://joel.drapper.me/p/ruby-central-fact-check/). |
6
+ | Simply put - there was active policy for adding or removing maintainers/owners of [rubygems](https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196) and [bundler](https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/bundler/playbooks/TEAM_CHANGES.md), and those [policies were not followed](https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/). |
7
+ | I'm adding notes like this to gems because I [don't condone theft](https://joel.drapper.me/p/ruby-central/) 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](https://gem.coop). |
10
+ | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
11
+ | The ["Technology for Humans: Joel Draper"](https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6) podcast episode by [reinteractive](https://reinteractive.com/ruby-on-rails) is the most cogent summary I'm aware of. |
12
+ | See [here](https://github.com/gem-coop/gem.coop/issues/12), [here](https://gem.coop) and [here](https://martinemde.com/2025/10/05/announcing-gem-coop.html) for more info on what comes next. |
13
+ | What I'm doing: A (WIP) proposal for [bundler/gem scopes](https://github.com/galtzo-floss/bundle-namespace), and a (WIP) proposal for a federated [gem server](https://github.com/galtzo-floss/gem-server). |
14
14
 
15
15
  [rubygems-org]: https://github.com/rubygems/
16
16
  [draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
@@ -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][🖼️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]
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)
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,55 +42,78 @@
42
42
 
43
43
  # ☯️ Toml::Merge
44
44
 
45
- [![Version][👽versioni]][👽version] [![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]
45
+ [![Version](https://img.shields.io/gem/v/toml-merge.svg)](https://bestgems.org/gems/toml-merge) [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/kettle-rb/toml-merge.svg)](http://github.com/kettle-rb/toml-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/toml-merge.svg)](https://bestgems.org/gems/toml-merge) [![Open Source Helpers](https://www.codetriage.com/kettle-rb/toml-merge/badges/users.svg)](https://www.codetriage.com/kettle-rb/toml-merge) [![CodeCov Test Coverage](https://codecov.io/gh/kettle-rb/toml-merge/graph/badge.svg)](https://codecov.io/gh/kettle-rb/toml-merge) [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/toml-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/toml-merge?branch=main) [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/toml-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/toml-merge/metrics/code?sort=coverageRating) [![QLTY Maintainability](https://qlty.sh/gh/kettle-rb/projects/toml-merge/maintainability.svg)](https://qlty.sh/gh/kettle-rb/projects/toml-merge) [![CI Heads](https://github.com/kettle-rb/toml-merge/actions/workflows/heads.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/heads.yml) [![CI Runtime Dependencies @ HEAD](https://github.com/kettle-rb/toml-merge/actions/workflows/dep-heads.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/dep-heads.yml) [![CI Current](https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml) [![CI Truffle Ruby](https://github.com/kettle-rb/toml-merge/actions/workflows/truffle.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/truffle.yml) [![Deps Locked](https://github.com/kettle-rb/toml-merge/actions/workflows/locked_deps.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/locked_deps.yml) [![Deps Unlocked](https://github.com/kettle-rb/toml-merge/actions/workflows/unlocked_deps.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/unlocked_deps.yml) [![CI Supported](https://github.com/kettle-rb/toml-merge/actions/workflows/supported.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/supported.yml) [![CI Test Coverage](https://github.com/kettle-rb/toml-merge/actions/workflows/coverage.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/coverage.yml) [![CI Style](https://github.com/kettle-rb/toml-merge/actions/workflows/style.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/style.yml) [![CodeQL](https://github.com/kettle-rb/toml-merge/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/security/code-scanning) [![Apache SkyWalking Eyes License Compatibility Check](https://github.com/kettle-rb/toml-merge/actions/workflows/license-eye.yml/badge.svg)](https://github.com/kettle-rb/toml-merge/actions/workflows/license-eye.yml)
46
46
 
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
-
49
- ---
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).
50
48
 
49
+ -----
51
50
  `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.
52
51
 
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]
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)
54
53
 
55
54
  ## 🌻 Synopsis
56
55
 
57
56
  `toml-merge` provides intelligent merging of TOML files by parsing them into
58
57
  tree-sitter AST nodes and comparing structural elements. It supports:
59
58
 
60
- - **Smart key matching** - Keys and tables are matched by their structural signatures
61
- - **Table matching** - Tables are matched using a multi-factor scoring algorithm that considers
62
- key similarity, value overlap, and position
63
- - **Freeze blocks** - Mark sections with comments to preserve them during merges
64
- - **Configurable merge strategies** - Choose whether template or destination wins for conflicts,
65
- or use a Hash for per-node-type preferences with `node_splitter` (see [ast-merge](https://github.com/kettle-rb/ast-merge) docs)
66
- - **Full TOML support** - Works with all TOML 1.0 features including inline tables, arrays of tables, and dotted keys
59
+ - **Smart key matching** - Keys and tables are matched by their structural signatures
60
+ - **Table matching** - Tables are matched using a multi-factor scoring algorithm that considers
61
+ key similarity, value overlap, and position
62
+ - **Freeze blocks** - Mark sections with comments to preserve them during merges
63
+ - **Configurable merge strategies** - Choose whether template or destination wins for conflicts,
64
+ or use a Hash for per-node-type preferences with `node_splitter` (see [ast-merge](https://github.com/kettle-rb/ast-merge) docs)
65
+ - **Full TOML support** - Works with all TOML 1.0 features including inline tables, arrays of tables, and dotted keys
67
66
 
68
67
  ### The `*-merge` Gem Family
69
68
 
70
- This gem is part of a family of gems that provide intelligent merging for various file formats:
71
-
72
- | Gem | Format | Parser Backend(s) | Description |
73
- |-----|--------|-------------------|-------------|
74
- | [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) |
75
- | [ast-merge][ast-merge] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
76
- | [prism-merge][prism-merge] | Ruby | [Prism][prism] (via [tree_haver][tree_haver]) | Smart merge for Ruby source files |
77
- | [psych-merge][psych-merge] | YAML | [Psych][psych] (via [tree_haver][tree_haver]) | Smart merge for YAML files |
78
- | [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] (via [tree_haver][tree_haver]) | Smart merge for JSON files |
79
- | [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via [tree_haver][tree_haver]) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
80
- | [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] (via [tree_haver][tree_haver]) | Smart merge for Bash scripts |
81
- | [rbs-merge][rbs-merge] | RBS | [RBS][rbs] | Smart merge for Ruby type signatures |
82
- | [dotenv-merge][dotenv-merge] | Dotenv | internal ([dotenv][dotenv]) | Smart merge for `.env` files |
83
- | [toml-merge][toml-merge] | TOML | [tree-sitter-toml][ts-toml] (via [tree_haver][tree_haver]) | Smart merge for TOML files |
84
- | [markdown-merge][markdown-merge] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via [tree_haver][tree_haver]) | **Foundation**: Shared base for Markdown mergers with inner code block merging |
85
- | [markly-merge][markly-merge] | Markdown | [Markly][markly] (via [tree_haver][tree_haver]) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
86
- | [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] (via [tree_haver][tree_haver]) | Smart merge for Markdown (CommonMark via comrak Rust) |
69
+ 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.
70
+
71
+ | Gem | Language<br>/ Format | Parser Backend(s) | Description |
72
+ |------------------------------------------|----------------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
73
+ | [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) |
74
+ | [ast-merge][ast-merge] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
75
+ | [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
76
+ | [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
77
+ | [dotenv-merge][dotenv-merge] | Dotenv | internal | Smart merge for `.env` files |
78
+ | [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
79
+ | [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
80
+ | [markdown-merge][markdown-merge] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver) | **Foundation**: Shared base for Markdown mergers with inner code block merging |
81
+ | [markly-merge][markly-merge] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
82
+ | [prism-merge][prism-merge] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
83
+ | [psych-merge][psych-merge] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
84
+ | [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 |
85
+ | [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 |
86
+
87
+ #### Backend Platform Compatibility
88
+
89
+ tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
90
+
91
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
92
+ |------------------------------------------------|:---:|:-----:|:-----------:|-----------------------------------------------------|
93
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
94
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
95
+ | **FFI** | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
96
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
97
+ | **Prism** | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
98
+ | **Psych** | ✅ | ✅ | ✅ | YAML parsing, stdlib |
99
+ | **Citrus** | ✅ | ✅ | ✅ | Pure Ruby, no native dependencies |
100
+ | **Commonmarker** | ✅ | ❌ | ❓ | Rust extension for Markdown |
101
+ | **Markly** | ✅ | ❌ | ❓ | C extension for Markdown |
102
+
103
+ **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
104
+
105
+ **Why some backends don't work on certain platforms**:
106
+
107
+ - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
108
+ - **TruffleRuby**: Has C API emulation via Sulong/LLVM, but it doesn't expose all MRI internals that native extensions require (e.g., `RBasic.flags`, `rb_gc_writebarrier`)
109
+ - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
87
110
 
88
111
  **Example implementations** for the gem templating use case:
89
112
 
90
- | Gem | Purpose | Description |
91
- |-----|---------|-------------|
92
- | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
93
- | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
113
+ | Gem | Purpose | Description |
114
+ |--------------------------|-----------------|-----------------------------------------------|
115
+ | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
116
+ | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
94
117
 
95
118
  [tree_haver]: https://github.com/kettle-rb/tree_haver
96
119
  [ast-merge]: https://github.com/kettle-rb/ast-merge
@@ -112,47 +135,92 @@ This gem is part of a family of gems that provide intelligent merging for variou
112
135
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
113
136
  [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
114
137
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
138
+ [ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
115
139
  [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
116
- [rbs]: https://github.com/ruby/rbs
117
140
  [dotenv]: https://github.com/bkeepers/dotenv
141
+ [rbs]: https://github.com/ruby/rbs
142
+ [toml-rb]: https://github.com/emancu/toml-rb
118
143
  [markly]: https://github.com/ioquatix/markly
119
144
  [commonmarker]: https://github.com/gjtorikian/commonmarker
145
+ [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
146
+ [tree_stump]: https://github.com/joker1007/tree_stump
147
+ [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
148
+
149
+ ### Configuration
150
+
151
+ The tree-sitter TOML parser requires a shared library. Set the `TREE_SITTER_TOML_PATH` environment variable to point to your compiled `libtree-sitter-toml.so` (or `.dylib` on macOS):
152
+
153
+ ``` bash
154
+ export TREE_SITTER_TOML_PATH=/path/to/libtree-sitter-toml.so
155
+ ```
156
+
157
+ ### Basic Usage
158
+
159
+ ``` ruby
160
+ require "toml/merge"
161
+
162
+ template = <<~TOML
163
+ [package]
164
+ name = "my-app"
165
+ version = "1.0.0"
166
+
167
+ [dependencies]
168
+ serde = "1.0"
169
+ TOML
170
+
171
+ destination = <<~TOML
172
+ [package]
173
+ name = "my-app"
174
+ version = "2.0.0"
175
+ authors = ["Custom Author"]
176
+
177
+ [dev-dependencies]
178
+ tokio = "1.0"
179
+ TOML
180
+
181
+ merger = Toml::Merge::SmartMerger.new(template, destination)
182
+ result = merger.merge
120
183
 
184
+ puts result.content if result.success?
185
+ # The [package] section is merged with destination's version and authors preserved,
186
+ # [dependencies] from template is included,
187
+ # [dev-dependencies] from destination is kept
188
+ ```
121
189
 
122
190
  ## 💡 Info you can shake a stick at
123
191
 
124
- | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
125
- |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
126
- | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
127
- | 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] |
128
- | 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] |
129
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
130
- | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
131
- | 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] |
132
- | 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] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
133
- | 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] |
134
- | 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] |
135
- | `...` 💖 | [![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] |
192
+ | Tokens to Remember | [![Gem name](https://img.shields.io/badge/name-toml--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red)](https://bestgems.org/gems/toml-merge) [![Gem namespace](https://img.shields.io/badge/namespace-Toml::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white)](https://github.com/kettle-rb/toml-merge) |
193
+ | --- | --- |
194
+ | 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/toml-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/toml-merge/actions/workflows/heads.yml) |
195
+ | 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/toml-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/toml-merge/actions/workflows/current.yml) |
196
+ | 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/toml-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/toml-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/toml-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/toml-merge/actions/workflows/heads.yml) |
197
+ | 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) |
198
+ | 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/toml-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/toml-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/toml-merge) [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-0.538-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) |
199
+ | 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/toml-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://toml-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/toml-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/toml-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/toml-merge/wiki) |
200
+ | 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) |
201
+ | 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) |
202
+ | 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) |
203
+ | `...` 💖 | [![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) |
136
204
 
137
205
  ### Compatibility
138
206
 
139
207
  Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
140
208
 
141
- | 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
142
- |------------------------------------------------|--------------------------------------------------------|
143
- | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
209
+ | 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
210
+ | --- | --- |
211
+ | 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2](https://github.com/appraisal-rb/appraisal2) ✨ |
144
212
 
145
213
  ### Federated DVCS
146
214
 
147
215
  <details markdown="1">
148
216
  <summary>Find this repo on federated forges (Coming soon!)</summary>
149
217
 
150
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
151
- |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------|
152
- | 🧪 [kettle-rb/toml-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
153
- | 🧊 [kettle-rb/toml-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
154
- | 🐙 [kettle-rb/toml-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
155
- | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |
218
+ | Federated [DVCS](https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/) Repository | Status | Issues | PRs | Wiki | CI | Discussions |
219
+ | --- | --- | --- | --- | --- | --- | --- |
220
+ | 🧪 [kettle-rb/toml-merge on GitLab](https://gitlab.com/kettle-rb/toml-merge/) | The Truth | [💚](https://gitlab.com/kettle-rb/toml-merge/-/issues) | [💚](https://gitlab.com/kettle-rb/toml-merge/-/merge_requests) | [💚](https://gitlab.com/kettle-rb/toml-merge/-/wikis/home) | 🐭 Tiny Matrix | ➖ |
221
+ | 🧊 [kettle-rb/toml-merge on CodeBerg](https://codeberg.org/kettle-rb/toml-merge) | An Ethical Mirror ([Donate](https://donate.codeberg.org/)) | [💚](https://codeberg.org/kettle-rb/toml-merge/issues) | [💚](https://codeberg.org/kettle-rb/toml-merge/pulls) | ➖ | ⭕️ No Matrix | ➖ |
222
+ | 🐙 [kettle-rb/toml-merge on GitHub](https://github.com/kettle-rb/toml-merge) | Another Mirror | [💚](https://github.com/kettle-rb/toml-merge/issues) | [💚](https://github.com/kettle-rb/toml-merge/pulls) | [💚](https://github.com/kettle-rb/toml-merge/wiki) | 💯 Full Matrix | [💚](https://github.com/kettle-rb/toml-merge/discussions) |
223
+ | 🎮️ [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) |
156
224
 
157
225
  </details>
158
226
 
@@ -167,31 +235,33 @@ Available as part of the Tidelift Subscription.
167
235
 
168
236
  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.
169
237
 
170
- [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
238
+ [![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-toml-merge?utm_source=rubygems-toml-merge&utm_medium=referral&utm_campaign=readme)
171
239
 
172
- - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies
173
- - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
174
- - 💡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
240
+ - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
175
241
 
176
- Alternatively:
242
+ - 💡Tidelift is part of [Sonar](https://blog.tidelift.com/tidelift-joins-sonar)
177
243
 
178
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
179
- - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
180
- - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
244
+ - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support](https://tidelift.com/subscription/pkg/rubygems-toml-merge?utm_source=rubygems-toml-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
245
+ Alternatively:
181
246
 
247
+ - [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
248
+
249
+ - [![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)
250
+
251
+ - [![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)
182
252
  </details>
183
253
 
184
254
  ## ✨ Installation
185
255
 
186
256
  Install the gem and add to the application's Gemfile by executing:
187
257
 
188
- ```console
258
+ ``` console
189
259
  bundle add toml-merge
190
260
  ```
191
261
 
192
262
  If bundler is not being used to manage dependencies, install the gem by executing:
193
263
 
194
- ```console
264
+ ``` console
195
265
  gem install toml-merge
196
266
  ```
197
267
 
@@ -200,19 +270,19 @@ gem install toml-merge
200
270
  <details markdown="1">
201
271
  <summary>For Medium or High Security Installations</summary>
202
272
 
203
- This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
204
- [stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
273
+ This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512](https://gitlab.com/kettle-rb/toml-merge/-/tree/main/checksums) checksums by
274
+ [stone\_checksums](https://github.com/galtzo-floss/stone_checksums). Be sure the gem you install hasn’t been tampered with
205
275
  by following the instructions below.
206
276
 
207
277
  Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
208
278
 
209
- ```console
279
+ ``` console
210
280
  gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
211
281
  ```
212
282
 
213
283
  You only need to do that once. Then proceed to install with:
214
284
 
215
- ```console
285
+ ``` console
216
286
  gem install toml-merge -P HighSecurity
217
287
  ```
218
288
 
@@ -220,7 +290,7 @@ The `HighSecurity` trust profile will verify signed gems, and not allow the inst
220
290
 
221
291
  If you want to up your security game full-time:
222
292
 
223
- ```console
293
+ ``` console
224
294
  bundle config set --global trust-policy MediumSecurity
225
295
  ```
226
296
 
@@ -234,26 +304,69 @@ NOTE: Be prepared to track down certs for signed gems and add them the same way
234
304
 
235
305
  ### Parser Backend Options
236
306
 
237
- `toml-merge` uses [tree_haver][tree_haver] for parsing, which supports multiple backends:
307
+ `toml-merge` uses [tree\_haver](https://github.com/kettle-rb/tree_haver) for parsing, which supports multiple backends:
238
308
 
239
309
  **Tree-sitter backend** (default, requires native library):
240
- - Set the `TREE_SITTER_TOML_PATH` environment variable to point to your compiled `libtree-sitter-toml.so` (or `.dylib` on macOS):
241
-
242
- ```bash
310
+ - Set the `TREE_SITTER_TOML_PATH` environment variable to point to your compiled `libtree-sitter-toml.so` (or `.dylib` on macOS):
311
+ <!-- end list -->
312
+ ``` bash
243
313
  export TREE_SITTER_TOML_PATH=/path/to/libtree-sitter-toml.so
244
314
  ```
245
315
 
246
- **Citrus backend** (pure Ruby, no native dependencies):
247
- - Alternative option using the [citrus](https://github.com/mjackson/citrus) and [toml-rb](https://github.com/emancu/toml-rb) gems
248
- - No compilation or system dependencies required
249
- - Ideal for environments where native extensions are problematic
250
- - Configure via tree_haver's backend selection
316
+ ### 💎 Ruby Interface Gems (Tree-sitter Backend)
317
+
318
+ If using the tree-sitter backend, you also need a Ruby gem that provides bindings to
319
+ tree-sitter. Choose **one** of the following based on your Ruby implementation:
320
+
321
+ | Gem | Ruby Support | Description |
322
+ | --- | --- | --- |
323
+ | [ruby\_tree\_sitter](https://github.com/Faveod/ruby_tree_sitter) | MRI only | C extension bindings (recommended for MRI) |
324
+ | [tree\_stump](https://github.com/nickstenning/tree_stump) | MRI (maybe JRuby) | Rust-based bindings via Rutie |
325
+ | [ffi](https://github.com/ffi/ffi) | MRI, JRuby, TruffleRuby | Generic FFI bindings (used by tree\_haver's FFI backend) |
326
+
327
+ [ruby_tree_sitter]: https://github.com/Faveod/ruby_tree_sitter
328
+ [tree_stump]: https://github.com/nickstenning/tree_stump
329
+ [ffi-gem]: https://github.com/ffi/ffi
330
+
331
+ #### For MRI Ruby (Recommended)
332
+
333
+ ``` console
334
+ gem install ruby_tree_sitter
335
+ ```
336
+
337
+ Or add to your Gemfile:
251
338
 
252
- For more details on backend configuration, see the [tree_haver documentation][tree_haver].
339
+ ``` ruby
340
+ gem "ruby_tree_sitter", "~> 2.0"
341
+ ```
342
+
343
+ #### For JRuby or TruffleRuby
344
+
345
+ ``` console
346
+ gem install ffi
347
+ ```
348
+
349
+ Or add to your Gemfile:
350
+
351
+ ``` ruby
352
+ gem "ffi"
353
+ ```
354
+
355
+ The `tree_haver` gem (a dependency of toml-merge) will automatically detect and use
356
+ the appropriate backend based on which gems are available.
357
+
358
+ **Note:** The `ruby_tree_sitter` gem only compiles on MRI Ruby. For JRuby or TruffleRuby,
359
+ you must use the FFI backend or the Citrus backend (below).
253
360
 
361
+ **Citrus backend** (pure Ruby, no native dependencies):
362
+ - Alternative option using the [citrus](https://github.com/mjackson/citrus) and [toml-rb](https://github.com/emancu/toml-rb) gems
363
+ - No compilation or system dependencies required
364
+ - Ideal for environments where native extensions are problematic
365
+ - Configure via tree\_haver's backend selection
366
+ For more details on backend configuration, see the [tree\_haver documentation](https://github.com/kettle-rb/tree_haver).
254
367
  ### Merge Options
255
368
 
256
- ```ruby
369
+ ``` ruby
257
370
  merger = Toml::Merge::SmartMerger.new(
258
371
  template_content,
259
372
  dest_content,
@@ -282,7 +395,7 @@ merger = Toml::Merge::SmartMerger.new(
282
395
 
283
396
  ### Simple Merge
284
397
 
285
- ```ruby
398
+ ``` ruby
286
399
  require "toml/merge"
287
400
 
288
401
  # Template defines the structure
@@ -290,7 +403,7 @@ template = <<~TOML
290
403
  [package]
291
404
  name = "my-app"
292
405
  version = "1.0.0"
293
-
406
+
294
407
  [dependencies]
295
408
  serde = "1.0"
296
409
  tokio = "1.0"
@@ -302,7 +415,7 @@ destination = <<~TOML
302
415
  name = "my-app"
303
416
  version = "2.0.0"
304
417
  authors = ["Custom Author"]
305
-
418
+
306
419
  [dev-dependencies]
307
420
  criterion = "0.5"
308
421
  TOML
@@ -316,7 +429,7 @@ puts result.content
316
429
 
317
430
  Freeze blocks protect sections from being overwritten during merge:
318
431
 
319
- ```toml
432
+ ``` toml
320
433
  [package]
321
434
  name = "my-app"
322
435
 
@@ -334,7 +447,7 @@ Content between `# toml-merge:freeze` and `# toml-merge:unfreeze` markers is pre
334
447
 
335
448
  ### Adding Template-Only Tables
336
449
 
337
- ```ruby
450
+ ``` ruby
338
451
  merger = Toml::Merge::SmartMerger.new(
339
452
  template,
340
453
  destination,
@@ -349,29 +462,29 @@ result = merger.merge
349
462
  While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
350
463
  Raising a monthly budget of... "dollars" would make the project more sustainable.
351
464
 
352
- We welcome both individual and corporate sponsors! We also offer a
465
+ We welcome both individual and corporate sponsors\! We also offer a
353
466
  wide array of funding channels to account for your preferences
354
- (although currently [Open Collective][🖇osc] is our preferred funding platform).
467
+ (although currently [Open Collective](https://opencollective.com/kettle-rb) is our preferred funding platform).
355
468
 
356
469
  **If you're working in a company that's making significant use of kettle-rb tools we'd
357
470
  appreciate it if you suggest to your company to become a kettle-rb sponsor.**
358
471
 
359
472
  You can support the development of kettle-rb tools via
360
- [GitHub Sponsors][🖇sponsor],
361
- [Liberapay][⛳liberapay],
362
- [PayPal][🖇paypal],
363
- [Open Collective][🖇osc]
364
- and [Tidelift][🏙️entsup-tidelift].
365
-
366
- | 📍 NOTE |
367
- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
473
+ [GitHub Sponsors](https://github.com/sponsors/pboling),
474
+ [Liberapay](https://liberapay.com/pboling/donate),
475
+ [PayPal](https://www.paypal.com/paypalme/peterboling),
476
+ [Open Collective](https://opencollective.com/kettle-rb)
477
+ and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-toml-merge?utm_source=rubygems-toml-merge&utm_medium=referral&utm_campaign=readme).
478
+
479
+ | 📍 NOTE |
480
+ | --- |
368
481
  | If doing a sponsorship in the form of donation is problematic for your company <br/> from an accounting standpoint, we'd recommend the use of Tidelift, <br/> where you can get a support-like subscription instead. |
369
482
 
370
483
  ### Open Collective for Individuals
371
484
 
372
- Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/kettle-rb#backer)]
485
+ Support us with a monthly donation and help us continue our activities. \[[Become a backer](https://opencollective.com/kettle-rb#backer)\]
373
486
 
374
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
487
+ NOTE: [kettle-readme-backers](https://github.com/kettle-rb/toml-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
375
488
 
376
489
  <!-- OPENCOLLECTIVE-INDIVIDUALS:START -->
377
490
  No backers yet. Be the first!
@@ -379,9 +492,9 @@ No backers yet. Be the first!
379
492
 
380
493
  ### Open Collective for Organizations
381
494
 
382
- 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)]
495
+ 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)\]
383
496
 
384
- NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
497
+ NOTE: [kettle-readme-backers](https://github.com/kettle-rb/toml-merge/blob/main/exe/kettle-readme-backers) updates this list every day, automatically.
385
498
 
386
499
  <!-- OPENCOLLECTIVE-ORGANIZATIONS:START -->
387
500
  No sponsors yet. Be the first!
@@ -395,50 +508,50 @@ I’m driven by a passion to foster a thriving open-source community – a space
395
508
 
396
509
  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`.
397
510
 
398
- 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.
511
+ 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.
399
512
 
400
- **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
513
+ **[Floss-Funding.dev](https://floss-funding.dev): 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
401
514
 
402
- [![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]
515
+ [![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)
403
516
 
404
517
  ## 🔐 Security
405
518
 
406
- See [SECURITY.md][🔐security].
519
+ See [SECURITY.md](SECURITY.md).
407
520
 
408
521
  ## 🤝 Contributing
409
522
 
410
523
  If you need some ideas of where to help, you could work on adding more code coverage,
411
- or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
524
+ or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues](https://github.com/kettle-rb/toml-merge/issues), or [PRs](https://github.com/kettle-rb/toml-merge/pulls),
412
525
  or use the gem and think about how it could be better.
413
526
 
414
- We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
527
+ 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.
415
528
 
416
- See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
529
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more detailed instructions.
417
530
 
418
531
  ### 🚀 Release Instructions
419
532
 
420
- See [CONTRIBUTING.md][🤝contributing].
533
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
421
534
 
422
535
  ### Code Coverage
423
536
 
424
- [![Coverage Graph][🏀codecov-g]][🏀codecov]
537
+ [![Coverage Graph](https://codecov.io/gh/kettle-rb/toml-merge/graphs/tree.svg)](https://codecov.io/gh/kettle-rb/toml-merge)
425
538
 
426
- [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
539
+ [![Coveralls Test Coverage](https://coveralls.io/repos/github/kettle-rb/toml-merge/badge.svg?branch=main)](https://coveralls.io/github/kettle-rb/toml-merge?branch=main)
427
540
 
428
- [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
541
+ [![QLTY Test Coverage](https://qlty.sh/gh/kettle-rb/projects/toml-merge/coverage.svg)](https://qlty.sh/gh/kettle-rb/projects/toml-merge/metrics/code?sort=coverageRating)
429
542
 
430
543
  ### 🪇 Code of Conduct
431
544
 
432
545
  Everyone interacting with this project's codebases, issue trackers,
433
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
546
+ 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).
434
547
 
435
548
  ## 🌈 Contributors
436
549
 
437
- [![Contributors][🖐contributors-img]][🖐contributors]
550
+ [![Contributors](https://contrib.rocks/image?repo=kettle-rb/toml-merge)](https://github.com/kettle-rb/toml-merge/graphs/contributors)
438
551
 
439
- Made with [contributors-img][🖐contrib-rocks].
552
+ Made with [contributors-img](https://contrib.rocks).
440
553
 
441
- Also see GitLab Contributors: [https://gitlab.com/kettle-rb/toml-merge/-/graphs/main][🚎contributors-gl]
554
+ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/toml-merge/-/graphs/main>
442
555
 
443
556
  <details>
444
557
  <summary>⭐️ Star History</summary>
@@ -455,23 +568,23 @@ Also see GitLab Contributors: [https://gitlab.com/kettle-rb/toml-merge/-/graphs/
455
568
 
456
569
  ## 📌 Versioning
457
570
 
458
- This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
571
+ 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).
459
572
  Violations of this scheme should be reported as bugs.
460
573
  Specifically, if a minor or patch version is released that breaks backward compatibility,
461
574
  a new version should be immediately released that restores compatibility.
462
575
  Breaking changes to the public API will only be introduced with new major versions.
463
576
 
464
577
  > dropping support for a platform is both obviously and objectively a breaking change <br/>
465
- >—Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
578
+ > —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716](https://github.com/semver/semver/issues/716#issuecomment-869336139)
466
579
 
467
- I understand that policy doesn't work universally ("exceptions to every rule!"),
580
+ I understand that policy doesn't work universally ("exceptions to every rule\!"),
468
581
  but it is the policy here.
469
582
  As such, in many cases it is good to specify a dependency on this library using
470
- the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
583
+ the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision.
471
584
 
472
585
  For example:
473
586
 
474
- ```ruby
587
+ ``` ruby
475
588
  spec.add_dependency("toml-merge", "~> 1.0")
476
589
  ```
477
590
 
@@ -484,23 +597,22 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
484
597
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
485
598
  read this article from the creator of SemVer:
486
599
 
487
- - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
488
-
600
+ - ["Major Version Numbers are Not Sacred"](https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html)
489
601
  </details>
490
602
 
491
- See [CHANGELOG.md][📌changelog] for a list of releases.
603
+ See [CHANGELOG.md](CHANGELOG.md) for a list of releases.
492
604
 
493
605
  ## 📄 License
494
606
 
495
607
  The gem is available as open source under the terms of
496
- the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
497
- See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
608
+ the [MIT License](LICENSE.txt) [![License: MIT](https://img.shields.io/badge/License-MIT-259D6C.svg)](https://opensource.org/licenses/MIT).
609
+ 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).
498
610
 
499
611
  ### © Copyright
500
612
 
501
613
  <ul>
502
614
  <li>
503
- Copyright (c) 2025 Peter H. Boling, of
615
+ Copyright (c) 2025-2026 Peter H. Boling, of
504
616
  <a href="https://discord.gg/3qme4XHNKN">
505
617
  Galtzo.com
506
618
  <picture>
@@ -521,11 +633,11 @@ Please consider sponsoring me or the project.
521
633
 
522
634
  To join the community or get help 👇️ Join the Discord.
523
635
 
524
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
636
+ [![Live Chat on Discord](https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord)](https://discord.gg/3qme4XHNKN)
525
637
 
526
- To say "thanks!" ☝️ Join the Discord or 👇️ send money.
638
+ To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
527
639
 
528
- [![Sponsor kettle-rb/toml-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]
640
+ [![Sponsor kettle-rb/toml-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)
529
641
 
530
642
  ### Please give the project a star ⭐ ♥.
531
643
 
@@ -690,7 +802,7 @@ Thanks for RTFM. ☺️
690
802
  [📌gitmoji]: https://gitmoji.dev
691
803
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
692
804
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
693
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.538-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
805
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.637-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
694
806
  [🔐security]: SECURITY.md
695
807
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
696
808
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -710,3 +822,41 @@ Thanks for RTFM. ☺️
710
822
  [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
711
823
  [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
712
824
  [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
825
+
826
+
827
+ The `*-merge` gem family provides intelligent, AST-based merging for various file formats. At the foundation is [tree\_haver](https://github.com/kettle-rb/tree_haver), which provides a unified cross-Ruby parsing API that works seamlessly across MRI, JRuby, and TruffleRuby.
828
+
829
+
830
+
831
+ | Gem | Purpose | Description |
832
+ | --- | --- | --- |
833
+ | [kettle-dev](https://github.com/kettle-rb/kettle-dev) | Gem Development | Gem templating tool using `*-merge` gems |
834
+ | [kettle-jem](https://github.com/kettle-rb/kettle-jem) | Gem Templating | Gem template library with smart merge support |
835
+
836
+ [tree_haver]: https://github.com/kettle-rb/tree_haver
837
+ [ast-merge]: https://github.com/kettle-rb/ast-merge
838
+ [prism-merge]: https://github.com/kettle-rb/prism-merge
839
+ [psych-merge]: https://github.com/kettle-rb/psych-merge
840
+ [json-merge]: https://github.com/kettle-rb/json-merge
841
+ [jsonc-merge]: https://github.com/kettle-rb/jsonc-merge
842
+ [bash-merge]: https://github.com/kettle-rb/bash-merge
843
+ [rbs-merge]: https://github.com/kettle-rb/rbs-merge
844
+ [dotenv-merge]: https://github.com/kettle-rb/dotenv-merge
845
+ [toml-merge]: https://github.com/kettle-rb/toml-merge
846
+ [markdown-merge]: https://github.com/kettle-rb/markdown-merge
847
+ [markly-merge]: https://github.com/kettle-rb/markly-merge
848
+ [commonmarker-merge]: https://github.com/kettle-rb/commonmarker-merge
849
+ [kettle-dev]: https://github.com/kettle-rb/kettle-dev
850
+ [kettle-jem]: https://github.com/kettle-rb/kettle-jem
851
+ [prism]: https://github.com/ruby/prism
852
+ [psych]: https://github.com/ruby/psych
853
+ [ts-json]: https://github.com/tree-sitter/tree-sitter-json
854
+ [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
855
+ [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
856
+ [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
857
+ [dotenv]: https://github.com/bkeepers/dotenv
858
+ [rbs]: https://github.com/ruby/rbs
859
+ [toml-rb]: https://github.com/emancu/toml-rb
860
+ [markly]: https://github.com/ioquatix/markly
861
+ [commonmarker]: https://github.com/gjtorikian/commonmarker
862
+