dotenv-merge 1.0.0 → 1.0.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +50 -1
- data/LICENSE.txt +1 -1
- data/README.md +189 -197
- data/lib/dotenv/merge/env_line.rb +22 -15
- data/lib/dotenv/merge/file_analysis.rb +3 -1
- data/lib/dotenv/merge/merge_result.rb +3 -2
- data/lib/dotenv/merge/smart_merger.rb +123 -50
- data/lib/dotenv/merge/version.rb +1 -1
- data/lib/dotenv/merge.rb +12 -0
- data.tar.gz.sig +0 -0
- metadata +33 -7
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c982a0bec61937d370eb9b353e1da52cc960fb76e20e477922a9edbed7ec064
|
|
4
|
+
data.tar.gz: 4463c4e011c866bb24cfe3031ba2f1017372aede506f065c0c1a7aa88a5929df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e9f2c6b34e2dbb1c9f303f48a40762ff7c4c06c33cfe223f65cde1e96938e80c894c7f4571e0da6aff84052d8911ef3c1de4b2bd08eb93dc4963fd191b8e50c
|
|
7
|
+
data.tar.gz: b68ac2aa403de2eb8ca7d795bbb1a51d522cb25426c9ffea0ccea6e38819c618234c1e606f8ae7d2a9fe83361f486161b486c7e92f03184117e532a3af7f2d50
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,51 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.0.2] - 2026-02-01
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.0.2][1.0.2t]
|
|
36
|
+
- COVERAGE: 97.73% -- 345/353 lines in 8 files
|
|
37
|
+
- BRANCH COVERAGE: 83.06% -- 103/124 branches in 8 files
|
|
38
|
+
- 96.83% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Utilizes `Ast::Merge::RSpec::MergeGemRegistry` when running RSpec tests
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- Documentation cleanup
|
|
47
|
+
- Upgrade to [ast-merge v4.0.5](https://github.com/kettle-rb/ast-merge/releases/tag/v4.0.5)
|
|
48
|
+
- Upgrade to [tree_haver v5.0.3](https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.3)
|
|
49
|
+
|
|
50
|
+
## [1.0.1] - 2026-01-01
|
|
51
|
+
|
|
52
|
+
- TAG: [v1.0.1][1.0.1t]
|
|
53
|
+
- COVERAGE: 97.72% -- 343/351 lines in 8 files
|
|
54
|
+
- BRANCH COVERAGE: 83.61% -- 102/122 branches in 8 files
|
|
55
|
+
- 96.83% documented
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- `node_typing` parameter for per-node-type merge preferences
|
|
60
|
+
- Enables `preference: { default: :destination, special_type: :template }` pattern
|
|
61
|
+
- Works with custom merge_types assigned via node_typing lambdas
|
|
62
|
+
- `match_refiner` parameter for fuzzy matching support
|
|
63
|
+
- `regions` and `region_placeholder` parameters for nested content merging
|
|
64
|
+
- `EnvLine#type` method returning `"env_line"` for TreeHaver::Node protocol compatibility
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- **SmartMerger**: Added `**options` for forward compatibility
|
|
69
|
+
- Accepts additional options that may be added to base class in future
|
|
70
|
+
- Passes all options through to `SmartMergerBase`
|
|
71
|
+
- **MergeResult**: Added `**options` for forward compatibility
|
|
72
|
+
- **BREAKING**: `SmartMerger` now inherits from `Ast::Merge::SmartMergerBase`
|
|
73
|
+
- Provides standardized options API consistent with all other `*-merge` gems
|
|
74
|
+
- All keyword arguments are now explicit (no more positional-only arguments)
|
|
75
|
+
- Gains automatic support for new SmartMergerBase features
|
|
76
|
+
- Renamed `EnvLine#type` attribute to `EnvLine#line_type` to avoid conflict with TreeHaver::Node protocol
|
|
77
|
+
|
|
33
78
|
## [1.0.0] - 2025-12-12
|
|
34
79
|
|
|
35
80
|
- TAG: [v1.0.0][1.0.0t]
|
|
@@ -41,6 +86,10 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
41
86
|
|
|
42
87
|
- Initial release
|
|
43
88
|
|
|
44
|
-
[Unreleased]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.
|
|
89
|
+
[Unreleased]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.2...HEAD
|
|
90
|
+
[1.0.2]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.1...v1.0.2
|
|
91
|
+
[1.0.2t]: https://github.com/kettle-rb/dotenv-merge/releases/tag/v1.0.2
|
|
92
|
+
[1.0.1]: https://github.com/kettle-rb/dotenv-merge/compare/v1.0.0...v1.0.1
|
|
93
|
+
[1.0.1t]: https://github.com/kettle-rb/dotenv-merge/releases/tag/v1.0.1
|
|
45
94
|
[1.0.0]: https://github.com/kettle-rb/dotenv-merge/compare/a34c8f20c877a45d03b9f0b83b973614e123a92b...v1.0.0
|
|
46
95
|
[1.0.0t]: https://github.com/kettle-rb/dotenv-merge/tags/v1.0.0
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
|
|
43
43
|
# ☯️ Dotenv::Merge
|
|
44
44
|
|
|
45
|
-
[![Version][👽versioni]][👽
|
|
45
|
+
[![Version][👽versioni]][👽dl-rank] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
|
|
46
46
|
|
|
47
47
|
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
-----
|
|
50
50
|
|
|
51
51
|
`if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
|
|
52
52
|
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
## 🌻 Synopsis
|
|
56
56
|
|
|
57
|
-
Dotenv::Merge is a standalone Ruby module that intelligently merges two versions of a dotenv (`.env`) file. It's like a smart "git merge" specifically designed for environment configuration files. Built on top of [ast-merge]
|
|
57
|
+
Dotenv::Merge is a standalone Ruby module that intelligently merges two versions of a dotenv (`.env`) file. It's like a smart "git merge" specifically designed for environment configuration files. Built on top of [ast-merge][ast-merge], it shares the same architecture as [prism-merge][prism-merge] for Ruby source files.
|
|
58
58
|
|
|
59
59
|
### Key Features
|
|
60
60
|
|
|
@@ -65,16 +65,16 @@ Dotenv::Merge is a standalone Ruby module that intelligently merges two versions
|
|
|
65
65
|
- **Full Provenance**: Tracks origin of every line
|
|
66
66
|
- **Standalone**: Minimal dependencies - just `ast-merge`
|
|
67
67
|
- **Customizable**:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
- `signature_generator` - callable custom signature generators
|
|
69
|
+
- `preference` - setting of `:template`, `:destination`, or a Hash for per-node-type preferences
|
|
70
|
+
- `node_splitter` - Hash mapping node types to callables for per-node-type merge customization (see [ast-merge][ast-merge] docs)
|
|
71
|
+
- `add_template_only_nodes` - setting to retain variables that do not exist in destination
|
|
72
|
+
- `freeze_token` - customize freeze block markers (default: `"dotenv-merge"`)
|
|
73
73
|
|
|
74
74
|
### Supported Line Types
|
|
75
75
|
|
|
76
76
|
| Line Type | Format | Matching Behavior |
|
|
77
|
-
|
|
77
|
+
| --- | --- | --- |
|
|
78
78
|
| Assignment | `KEY=value` | Variables match by key name |
|
|
79
79
|
| Export | `export KEY=value` | Treated as assignment with export flag |
|
|
80
80
|
| Comment | `# comment text` | Preserved in context |
|
|
@@ -97,139 +97,59 @@ result = merger.merge
|
|
|
97
97
|
File.write("merged.env", result.to_s)
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
###
|
|
101
|
-
|
|
102
|
-
| Gem | File Type | Parser |
|
|
103
|
-
|-----|-----------|--------|
|
|
104
|
-
| [ast-merge](https://github.com/kettle-rb/ast-merge) | Text | internal |
|
|
105
|
-
| [prism-merge](https://github.com/kettle-rb/prism-merge) | Ruby | Prism |
|
|
106
|
-
| [psych-merge](https://github.com/kettle-rb/psych-merge) | YAML | Psych |
|
|
107
|
-
| [json-merge](https://github.com/kettle-rb/json-merge) | JSON | tree-sitter-json |
|
|
108
|
-
| [jsonc-merge](https://github.com/kettle-rb/jsonc-merge) | JSONC | ⚠️ [tree-sitter-jsonc](https://gitlab.com/WhyNotHugo/tree-sitter-jsonc) (PoC) |
|
|
109
|
-
| [bash-merge](https://github.com/kettle-rb/bash-merge) | Shell | tree-sitter-bash |
|
|
110
|
-
| [rbs-merge](https://github.com/kettle-rb/rbs-merge) | RBS Types | RBS |
|
|
111
|
-
| **dotenv-merge** | Dotenv | internal |
|
|
112
|
-
| [toml-merge](https://github.com/kettle-rb/toml-merge) | TOML | tree-sitter-toml |
|
|
113
|
-
| [markdown-merge](https://github.com/kettle-rb/markdown-merge) | Markdown | _base classes_ |
|
|
114
|
-
| [markly-merge](https://github.com/kettle-rb/markly-merge) | Markdown | Markly (cmark-gfm) |
|
|
115
|
-
| [commonmarker-merge](https://github.com/kettle-rb/commonmarker-merge) | Markdown | Commonmarker (Comrak) |
|
|
116
|
-
|
|
117
|
-
**Example implementations** for the gem templating use case:
|
|
118
|
-
|
|
119
|
-
| Gem | Purpose |
|
|
120
|
-
|-----|---------|
|
|
121
|
-
| [kettle-dev](https://github.com/kettle-rb/kettle-dev) | Gem templating tool |
|
|
122
|
-
| [kettle-jem](https://github.com/kettle-rb/kettle-jem) | Gem template library |
|
|
123
|
-
|
|
124
|
-
### Configuration
|
|
125
|
-
|
|
126
|
-
```ruby
|
|
127
|
-
merger = Dotenv::Merge::SmartMerger.new(
|
|
128
|
-
template_content,
|
|
129
|
-
dest_content,
|
|
130
|
-
# Which version to prefer when variables match
|
|
131
|
-
# :destination (default) - keep destination values
|
|
132
|
-
# :template - use template values
|
|
133
|
-
preference: :destination,
|
|
134
|
-
|
|
135
|
-
# Whether to add template-only variables to the result
|
|
136
|
-
# false (default) - only include variables that exist in destination
|
|
137
|
-
# true - include all template variables
|
|
138
|
-
add_template_only_nodes: false,
|
|
139
|
-
|
|
140
|
-
# Token for freeze block markers
|
|
141
|
-
# Default: "dotenv-merge"
|
|
142
|
-
# Looks for: # dotenv-merge:freeze / # dotenv-merge:unfreeze
|
|
143
|
-
freeze_token: "dotenv-merge",
|
|
144
|
-
|
|
145
|
-
# Custom signature generator (optional)
|
|
146
|
-
# Receives an EnvLine, returns a signature array or nil
|
|
147
|
-
signature_generator: ->(line) { [:env, line.key] if line.assignment? },
|
|
148
|
-
)
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Basic Usage
|
|
152
|
-
|
|
153
|
-
#### Simple Merge
|
|
154
|
-
|
|
155
|
-
```ruby
|
|
156
|
-
require "dotenv/merge"
|
|
157
|
-
|
|
158
|
-
# Template defines the structure
|
|
159
|
-
template = <<~ENV
|
|
160
|
-
# Database configuration
|
|
161
|
-
DATABASE_URL=postgres://localhost/myapp_dev
|
|
162
|
-
DATABASE_POOL=5
|
|
163
|
-
|
|
164
|
-
# API keys
|
|
165
|
-
API_KEY=your_api_key_here
|
|
166
|
-
API_SECRET=your_secret_here
|
|
167
|
-
ENV
|
|
168
|
-
|
|
169
|
-
# Destination has customizations
|
|
170
|
-
destination = <<~ENV
|
|
171
|
-
# Database configuration
|
|
172
|
-
DATABASE_URL=postgres://production.example.com/myapp
|
|
173
|
-
DATABASE_POOL=25
|
|
174
|
-
|
|
175
|
-
# Custom setting not in template
|
|
176
|
-
CUSTOM_SETTING=my_value
|
|
177
|
-
ENV
|
|
178
|
-
|
|
179
|
-
merger = Dotenv::Merge::SmartMerger.new(template, destination)
|
|
180
|
-
result = merger.merge
|
|
181
|
-
puts result
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
#### Using Freeze Blocks
|
|
185
|
-
|
|
186
|
-
Freeze blocks protect sections from being overwritten during merge:
|
|
187
|
-
|
|
188
|
-
```env
|
|
189
|
-
# Database configuration
|
|
190
|
-
DATABASE_URL=postgres://localhost/myapp_dev
|
|
191
|
-
|
|
192
|
-
# dotenv-merge:freeze Custom API credentials
|
|
193
|
-
API_KEY=my_secret_production_key
|
|
194
|
-
API_SECRET=super_secret_value
|
|
195
|
-
# dotenv-merge:unfreeze
|
|
196
|
-
|
|
197
|
-
# Other settings
|
|
198
|
-
DEBUG=false
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Content between `# dotenv-merge:freeze` and `# dotenv-merge:unfreeze` markers is preserved from the destination file, regardless of what the template contains.
|
|
100
|
+
### The `*-merge` Gem Family
|
|
202
101
|
|
|
203
|
-
|
|
102
|
+
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
|
+
|
|
104
|
+
| Gem | Version / CI | Language<br>/ Format | Parser Backend(s) | Description |
|
|
105
|
+
|------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
|
106
|
+
| [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) |
|
|
107
|
+
| [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 |
|
|
108
|
+
| [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 |
|
|
109
|
+
| [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) |
|
|
110
|
+
| [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 |
|
|
111
|
+
| [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 |
|
|
112
|
+
| [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 |
|
|
113
|
+
| [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 |
|
|
114
|
+
| [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) |
|
|
115
|
+
| [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 |
|
|
116
|
+
| [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 |
|
|
117
|
+
| [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 |
|
|
118
|
+
| [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
|
+
|
|
120
|
+
#### Backend Platform Compatibility
|
|
121
|
+
|
|
122
|
+
tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
|
|
123
|
+
|
|
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** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
|
|
129
|
+
| **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
|
|
130
|
+
| **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
|
|
131
|
+
| **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
|
|
132
|
+
| **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
|
|
133
|
+
| **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
|
|
134
|
+
| **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
|
|
135
|
+
| **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
|
|
136
|
+
|
|
137
|
+
**Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
|
|
138
|
+
|
|
139
|
+
**Why some backends don't work on certain platforms**:
|
|
140
|
+
|
|
141
|
+
- **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
|
|
142
|
+
- **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`)
|
|
143
|
+
- **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
|
|
204
144
|
|
|
205
|
-
|
|
206
|
-
merger = Dotenv::Merge::SmartMerger.new(
|
|
207
|
-
template,
|
|
208
|
-
destination,
|
|
209
|
-
add_template_only_nodes: true,
|
|
210
|
-
)
|
|
211
|
-
result = merger.merge
|
|
212
|
-
# Result includes variables from template that don't exist in destination
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### The `*-merge` Gem Family
|
|
145
|
+
**Example implementations** for the gem templating use case:
|
|
216
146
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
|
220
|
-
|
|
221
|
-
| [ast-merge][ast-merge] | Text | internal | Shared infrastructure for all `*-merge` gems |
|
|
222
|
-
| [prism-merge][prism-merge] | Ruby | [Prism][prism] | Smart merge for Ruby source files |
|
|
223
|
-
| [psych-merge][psych-merge] | YAML | [Psych][psych] | Smart merge for YAML files |
|
|
224
|
-
| [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] | Smart merge for JSON files |
|
|
225
|
-
| [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] | ⚠️ Proof of concept; Smart merge for JSON with Comments |
|
|
226
|
-
| [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] | Smart merge for Bash scripts |
|
|
227
|
-
| [rbs-merge][rbs-merge] | RBS | [RBS][rbs] | Smart merge for Ruby type signatures |
|
|
228
|
-
| [dotenv-merge][dotenv-merge] | Dotenv | internal ([dotenv][dotenv]) | Smart merge for `.env` files |
|
|
229
|
-
| [toml-merge][toml-merge] | TOML | [tree-sitter-toml][ts-toml] | Smart merge for TOML files |
|
|
230
|
-
| [markly-merge][markly-merge] | Markdown | [Markly][markly] | Smart merge for Markdown (CommonMark via libcmark-gfm) |
|
|
231
|
-
| [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] | Smart merge for Markdown (CommonMark via comrak) |
|
|
147
|
+
| Gem | Purpose | Description |
|
|
148
|
+
|--------------------------|-----------------|-----------------------------------------------|
|
|
149
|
+
| [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
|
|
150
|
+
| [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
|
|
232
151
|
|
|
152
|
+
[tree_haver]: https://github.com/kettle-rb/tree_haver
|
|
233
153
|
[ast-merge]: https://github.com/kettle-rb/ast-merge
|
|
234
154
|
[prism-merge]: https://github.com/kettle-rb/prism-merge
|
|
235
155
|
[psych-merge]: https://github.com/kettle-rb/psych-merge
|
|
@@ -239,59 +159,131 @@ This gem is part of a family of gems that provide intelligent merging for variou
|
|
|
239
159
|
[rbs-merge]: https://github.com/kettle-rb/rbs-merge
|
|
240
160
|
[dotenv-merge]: https://github.com/kettle-rb/dotenv-merge
|
|
241
161
|
[toml-merge]: https://github.com/kettle-rb/toml-merge
|
|
162
|
+
[markdown-merge]: https://github.com/kettle-rb/markdown-merge
|
|
242
163
|
[markly-merge]: https://github.com/kettle-rb/markly-merge
|
|
243
164
|
[commonmarker-merge]: https://github.com/kettle-rb/commonmarker-merge
|
|
165
|
+
[kettle-dev]: https://github.com/kettle-rb/kettle-dev
|
|
166
|
+
[kettle-jem]: https://github.com/kettle-rb/kettle-jem
|
|
167
|
+
[tree_haver-gem]: https://bestgems.org/gems/tree_haver
|
|
168
|
+
[ast-merge-gem]: https://bestgems.org/gems/ast-merge
|
|
169
|
+
[prism-merge-gem]: https://bestgems.org/gems/prism-merge
|
|
170
|
+
[psych-merge-gem]: https://bestgems.org/gems/psych-merge
|
|
171
|
+
[json-merge-gem]: https://bestgems.org/gems/json-merge
|
|
172
|
+
[jsonc-merge-gem]: https://bestgems.org/gems/jsonc-merge
|
|
173
|
+
[bash-merge-gem]: https://bestgems.org/gems/bash-merge
|
|
174
|
+
[rbs-merge-gem]: https://bestgems.org/gems/rbs-merge
|
|
175
|
+
[dotenv-merge-gem]: https://bestgems.org/gems/dotenv-merge
|
|
176
|
+
[toml-merge-gem]: https://bestgems.org/gems/toml-merge
|
|
177
|
+
[markdown-merge-gem]: https://bestgems.org/gems/markdown-merge
|
|
178
|
+
[markly-merge-gem]: https://bestgems.org/gems/markly-merge
|
|
179
|
+
[commonmarker-merge-gem]: https://bestgems.org/gems/commonmarker-merge
|
|
180
|
+
[kettle-dev-gem]: https://bestgems.org/gems/kettle-dev
|
|
181
|
+
[kettle-jem-gem]: https://bestgems.org/gems/kettle-jem
|
|
182
|
+
[tree_haver-gem-i]: https://img.shields.io/gem/v/tree_haver.svg
|
|
183
|
+
[ast-merge-gem-i]: https://img.shields.io/gem/v/ast-merge.svg
|
|
184
|
+
[prism-merge-gem-i]: https://img.shields.io/gem/v/prism-merge.svg
|
|
185
|
+
[psych-merge-gem-i]: https://img.shields.io/gem/v/psych-merge.svg
|
|
186
|
+
[json-merge-gem-i]: https://img.shields.io/gem/v/json-merge.svg
|
|
187
|
+
[jsonc-merge-gem-i]: https://img.shields.io/gem/v/jsonc-merge.svg
|
|
188
|
+
[bash-merge-gem-i]: https://img.shields.io/gem/v/bash-merge.svg
|
|
189
|
+
[rbs-merge-gem-i]: https://img.shields.io/gem/v/rbs-merge.svg
|
|
190
|
+
[dotenv-merge-gem-i]: https://img.shields.io/gem/v/dotenv-merge.svg
|
|
191
|
+
[toml-merge-gem-i]: https://img.shields.io/gem/v/toml-merge.svg
|
|
192
|
+
[markdown-merge-gem-i]: https://img.shields.io/gem/v/markdown-merge.svg
|
|
193
|
+
[markly-merge-gem-i]: https://img.shields.io/gem/v/markly-merge.svg
|
|
194
|
+
[commonmarker-merge-gem-i]: https://img.shields.io/gem/v/commonmarker-merge.svg
|
|
195
|
+
[kettle-dev-gem-i]: https://img.shields.io/gem/v/kettle-dev.svg
|
|
196
|
+
[kettle-jem-gem-i]: https://img.shields.io/gem/v/kettle-jem.svg
|
|
197
|
+
[tree_haver-ci-i]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml/badge.svg
|
|
198
|
+
[ast-merge-ci-i]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml/badge.svg
|
|
199
|
+
[prism-merge-ci-i]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml/badge.svg
|
|
200
|
+
[psych-merge-ci-i]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml/badge.svg
|
|
201
|
+
[json-merge-ci-i]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml/badge.svg
|
|
202
|
+
[jsonc-merge-ci-i]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml/badge.svg
|
|
203
|
+
[bash-merge-ci-i]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml/badge.svg
|
|
204
|
+
[rbs-merge-ci-i]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml/badge.svg
|
|
205
|
+
[dotenv-merge-ci-i]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml/badge.svg
|
|
206
|
+
[toml-merge-ci-i]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml/badge.svg
|
|
207
|
+
[markdown-merge-ci-i]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml/badge.svg
|
|
208
|
+
[markly-merge-ci-i]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml/badge.svg
|
|
209
|
+
[commonmarker-merge-ci-i]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml/badge.svg
|
|
210
|
+
[kettle-dev-ci-i]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml/badge.svg
|
|
211
|
+
[kettle-jem-ci-i]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml/badge.svg
|
|
212
|
+
[tree_haver-ci]: https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml
|
|
213
|
+
[ast-merge-ci]: https://github.com/kettle-rb/ast-merge/actions/workflows/current.yml
|
|
214
|
+
[prism-merge-ci]: https://github.com/kettle-rb/prism-merge/actions/workflows/current.yml
|
|
215
|
+
[psych-merge-ci]: https://github.com/kettle-rb/psych-merge/actions/workflows/current.yml
|
|
216
|
+
[json-merge-ci]: https://github.com/kettle-rb/json-merge/actions/workflows/current.yml
|
|
217
|
+
[jsonc-merge-ci]: https://github.com/kettle-rb/jsonc-merge/actions/workflows/current.yml
|
|
218
|
+
[bash-merge-ci]: https://github.com/kettle-rb/bash-merge/actions/workflows/current.yml
|
|
219
|
+
[rbs-merge-ci]: https://github.com/kettle-rb/rbs-merge/actions/workflows/current.yml
|
|
220
|
+
[dotenv-merge-ci]: https://github.com/kettle-rb/dotenv-merge/actions/workflows/current.yml
|
|
221
|
+
[toml-merge-ci]: https://github.com/kettle-rb/toml-merge/actions/workflows/current.yml
|
|
222
|
+
[markdown-merge-ci]: https://github.com/kettle-rb/markdown-merge/actions/workflows/current.yml
|
|
223
|
+
[markly-merge-ci]: https://github.com/kettle-rb/markly-merge/actions/workflows/current.yml
|
|
224
|
+
[commonmarker-merge-ci]: https://github.com/kettle-rb/commonmarker-merge/actions/workflows/current.yml
|
|
225
|
+
[kettle-dev-ci]: https://github.com/kettle-rb/kettle-dev/actions/workflows/current.yml
|
|
226
|
+
[kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
|
|
244
227
|
[prism]: https://github.com/ruby/prism
|
|
245
228
|
[psych]: https://github.com/ruby/psych
|
|
229
|
+
[ffi]: https://github.com/ffi/ffi
|
|
246
230
|
[ts-json]: https://github.com/tree-sitter/tree-sitter-json
|
|
247
231
|
[ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
|
|
248
232
|
[ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
|
|
233
|
+
[ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
|
|
249
234
|
[ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
|
|
250
|
-
[rbs]: https://github.com/ruby/rbs
|
|
251
235
|
[dotenv]: https://github.com/bkeepers/dotenv
|
|
252
|
-
[
|
|
236
|
+
[rbs]: https://github.com/ruby/rbs
|
|
237
|
+
[toml-rb]: https://github.com/emancu/toml-rb
|
|
238
|
+
[toml]: https://github.com/jm/toml
|
|
239
|
+
[markly]: https://github.com/ioquatix/markly
|
|
253
240
|
[commonmarker]: https://github.com/gjtorikian/commonmarker
|
|
241
|
+
[ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
|
|
242
|
+
[tree_stump]: https://github.com/joker1007/tree_stump
|
|
243
|
+
[jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
|
|
244
|
+
[citrus]: https://github.com/mjackson/citrus
|
|
245
|
+
[parslet]: https://github.com/kschiess/parslet
|
|
254
246
|
|
|
255
247
|
## 💡 Info you can shake a stick at
|
|
256
248
|
|
|
257
|
-
| Tokens to Remember | [![Gem name][⛳️name-img]][
|
|
258
|
-
|
|
259
|
-
| Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf]
|
|
260
|
-
| 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]
|
|
261
|
-
| 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]
|
|
262
|
-
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][
|
|
263
|
-
| 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
|
|
264
|
-
| 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]
|
|
265
|
-
| 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] |
|
|
266
|
-
| 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]
|
|
267
|
-
| 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]
|
|
268
|
-
| `...` 💖 | [![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]
|
|
249
|
+
| Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
|
|
250
|
+
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
251
|
+
| Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
|
|
252
|
+
| 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] |
|
|
253
|
+
| 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] |
|
|
254
|
+
| 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] |
|
|
255
|
+
| 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] [][🧮kloc] |
|
|
256
|
+
| 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] |
|
|
257
|
+
| 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] |
|
|
258
|
+
| 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] |
|
|
259
|
+
| 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] |
|
|
260
|
+
| `...` 💖 | [![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] |
|
|
269
261
|
|
|
270
262
|
### Compatibility
|
|
271
263
|
|
|
272
264
|
Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRuby.
|
|
273
265
|
|
|
274
|
-
| 🚚
|
|
266
|
+
| 🚚 *Amazing* test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
|
|
275
267
|
|------------------------------------------------|--------------------------------------------------------|
|
|
276
|
-
| 👟 Check it out
|
|
268
|
+
| 👟 Check it out\! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
|
|
277
269
|
|
|
278
270
|
### Federated DVCS
|
|
279
271
|
|
|
280
272
|
<details markdown="1">
|
|
281
273
|
<summary>Find this repo on federated forges (Coming soon!)</summary>
|
|
282
274
|
|
|
283
|
-
| Federated [DVCS][💎d-in-dvcs] Repository
|
|
284
|
-
|
|
285
|
-
| 🧪 [kettle-rb/dotenv-merge on GitLab][📜src-gl] | The Truth
|
|
286
|
-
| 🧊 [kettle-rb/dotenv-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate])
|
|
287
|
-
| 🐙 [kettle-rb/dotenv-merge on GitHub][📜src-gh] | Another Mirror
|
|
288
|
-
| 🎮️ [Discord Server][
|
|
275
|
+
| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions |
|
|
276
|
+
|---------------------------------------------------|------------------------------------------------------------------------|----------------------------|---------------------------|----------------------------|---------------------------|--------------------------------|
|
|
277
|
+
| 🧪 [kettle-rb/dotenv-merge on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
|
|
278
|
+
| 🧊 [kettle-rb/dotenv-merge on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
|
|
279
|
+
| 🐙 [kettle-rb/dotenv-merge on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
|
|
280
|
+
| 🎮️ [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] |
|
|
289
281
|
|
|
290
282
|
</details>
|
|
291
283
|
|
|
292
284
|
[gh-discussions]: https://github.com/kettle-rb/dotenv-merge/discussions
|
|
293
285
|
|
|
294
|
-
### Enterprise Support []
|
|
286
|
+
### Enterprise Support [][🏙️entsup-tidelift]
|
|
295
287
|
|
|
296
288
|
Available as part of the Tidelift Subscription.
|
|
297
289
|
|
|
@@ -302,13 +294,12 @@ The maintainers of this and thousands of other packages are working with Tidelif
|
|
|
302
294
|
|
|
303
295
|
[![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
|
|
304
296
|
|
|
305
|
-
- 💡Subscribe for support guarantees covering
|
|
297
|
+
- 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
|
|
306
298
|
- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
|
|
307
|
-
- 💡Tidelift pays maintainers to maintain the software you depend on
|
|
308
|
-
|
|
309
|
-
Alternatively:
|
|
299
|
+
- 💡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
|
|
300
|
+
Alternatively:
|
|
310
301
|
|
|
311
|
-
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][
|
|
302
|
+
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
|
|
312
303
|
- [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork]
|
|
313
304
|
- [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor]
|
|
314
305
|
|
|
@@ -334,7 +325,7 @@ gem install dotenv-merge
|
|
|
334
325
|
<summary>For Medium or High Security Installations</summary>
|
|
335
326
|
|
|
336
327
|
This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by
|
|
337
|
-
[
|
|
328
|
+
[stone\_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with
|
|
338
329
|
by following the instructions below.
|
|
339
330
|
|
|
340
331
|
Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:
|
|
@@ -381,24 +372,28 @@ merger = Dotenv::Merge::SmartMerger.new(
|
|
|
381
372
|
Control which source wins when both files have the same key:
|
|
382
373
|
|
|
383
374
|
- **`:template`** - Template values replace destination values
|
|
384
|
-
|
|
385
|
-
|
|
375
|
+
|
|
376
|
+
- Version files (`VERSION=2.0.0` should replace `VERSION=1.0.0`)
|
|
377
|
+
- API endpoint updates (`API_URL=https://new-api.example.com`)
|
|
386
378
|
|
|
387
379
|
- **`:destination`** (default) - Destination values are preserved
|
|
388
|
-
|
|
389
|
-
|
|
380
|
+
|
|
381
|
+
- Local development settings
|
|
382
|
+
- Project-specific customizations
|
|
390
383
|
|
|
391
384
|
### Template-Only Nodes
|
|
392
385
|
|
|
393
386
|
Control whether to add entries that only exist in the template:
|
|
394
387
|
|
|
395
388
|
- **`true`** - Add new entries from template
|
|
396
|
-
|
|
397
|
-
|
|
389
|
+
|
|
390
|
+
- New required environment variables
|
|
391
|
+
- New configuration options
|
|
398
392
|
|
|
399
393
|
- **`false`** (default) - Skip template-only entries
|
|
400
|
-
|
|
401
|
-
|
|
394
|
+
|
|
395
|
+
- Template has placeholder values
|
|
396
|
+
- Destination is authoritative
|
|
402
397
|
|
|
403
398
|
## 🔧 Basic Usage
|
|
404
399
|
|
|
@@ -420,15 +415,13 @@ File.write("merged.env", result)
|
|
|
420
415
|
|
|
421
416
|
Freeze blocks protect sections of your `.env` file from being modified during merges:
|
|
422
417
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
# >> FREEZE: project_secrets
|
|
418
|
+
# << FREEZE: project_secrets
|
|
419
|
+
DATABASE_URL=postgresql://localhost/myapp_dev
|
|
420
|
+
SECRET_KEY_BASE=my_local_secret_key_value
|
|
421
|
+
# >> FREEZE: project_secrets
|
|
428
422
|
|
|
429
|
-
# These entries can be updated by template
|
|
430
|
-
API_VERSION=v2
|
|
431
|
-
```
|
|
423
|
+
# These entries can be updated by template
|
|
424
|
+
API_VERSION=v2
|
|
432
425
|
|
|
433
426
|
### Adding Template-Only Entries
|
|
434
427
|
|
|
@@ -457,7 +450,7 @@ result = merger.merge
|
|
|
457
450
|
While kettle-rb tools are free software and will always be, the project would benefit immensely from some funding.
|
|
458
451
|
Raising a monthly budget of... "dollars" would make the project more sustainable.
|
|
459
452
|
|
|
460
|
-
We welcome both individual and corporate sponsors
|
|
453
|
+
We welcome both individual and corporate sponsors\! We also offer a
|
|
461
454
|
wide array of funding channels to account for your preferences
|
|
462
455
|
(although currently [Open Collective][🖇osc] is our preferred funding platform).
|
|
463
456
|
|
|
@@ -471,13 +464,13 @@ You can support the development of kettle-rb tools via
|
|
|
471
464
|
[Open Collective][🖇osc]
|
|
472
465
|
and [Tidelift][🏙️entsup-tidelift].
|
|
473
466
|
|
|
474
|
-
| 📍 NOTE
|
|
475
|
-
|
|
467
|
+
| 📍 NOTE |
|
|
468
|
+
| --- |
|
|
476
469
|
| 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. |
|
|
477
470
|
|
|
478
471
|
### Open Collective for Individuals
|
|
479
472
|
|
|
480
|
-
Support us with a monthly donation and help us continue our activities. [[Become a backer]
|
|
473
|
+
Support us with a monthly donation and help us continue our activities. \[[Become a backer][🖇osc-backers]\]
|
|
481
474
|
|
|
482
475
|
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
|
|
483
476
|
|
|
@@ -487,7 +480,7 @@ No backers yet. Be the first!
|
|
|
487
480
|
|
|
488
481
|
### Open Collective for Organizations
|
|
489
482
|
|
|
490
|
-
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]
|
|
483
|
+
Become a sponsor and get your logo on our README on GitHub with a link to your site. \[[Become a sponsor][🖇osc-sponsors]\]
|
|
491
484
|
|
|
492
485
|
NOTE: [kettle-readme-backers][kettle-readme-backers] updates this list every day, automatically.
|
|
493
486
|
|
|
@@ -503,7 +496,7 @@ I’m driven by a passion to foster a thriving open-source community – a space
|
|
|
503
496
|
|
|
504
497
|
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`.
|
|
505
498
|
|
|
506
|
-
I’m developing a new library, [
|
|
499
|
+
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.
|
|
507
500
|
|
|
508
501
|
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
509
502
|
|
|
@@ -546,7 +539,7 @@ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][
|
|
|
546
539
|
|
|
547
540
|
Made with [contributors-img][🖐contrib-rocks].
|
|
548
541
|
|
|
549
|
-
Also see GitLab Contributors:
|
|
542
|
+
Also see GitLab Contributors: <https://gitlab.com/kettle-rb/dotenv-merge/-/graphs/main>
|
|
550
543
|
|
|
551
544
|
<details>
|
|
552
545
|
<summary>⭐️ Star History</summary>
|
|
@@ -570,9 +563,9 @@ a new version should be immediately released that restores compatibility.
|
|
|
570
563
|
Breaking changes to the public API will only be introduced with new major versions.
|
|
571
564
|
|
|
572
565
|
> dropping support for a platform is both obviously and objectively a breaking change <br/>
|
|
573
|
-
|
|
566
|
+
> —Jordan Harband ([@ljharb](https://github.com/ljharb), maintainer of SemVer) [in SemVer issue 716][📌semver-breaking]
|
|
574
567
|
|
|
575
|
-
I understand that policy doesn't work universally ("exceptions to every rule
|
|
568
|
+
I understand that policy doesn't work universally ("exceptions to every rule\!"),
|
|
576
569
|
but it is the policy here.
|
|
577
570
|
As such, in many cases it is good to specify a dependency on this library using
|
|
578
571
|
the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
|
|
@@ -608,7 +601,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
|
|
|
608
601
|
|
|
609
602
|
<ul>
|
|
610
603
|
<li>
|
|
611
|
-
Copyright (c) 2025 Peter H. Boling, of
|
|
604
|
+
Copyright (c) 2025-2026 Peter H. Boling, of
|
|
612
605
|
<a href="https://discord.gg/3qme4XHNKN">
|
|
613
606
|
Galtzo.com
|
|
614
607
|
<picture>
|
|
@@ -629,9 +622,9 @@ Please consider sponsoring me or the project.
|
|
|
629
622
|
|
|
630
623
|
To join the community or get help 👇️ Join the Discord.
|
|
631
624
|
|
|
632
|
-
[![Live Chat on Discord][✉️discord-invite-img-ftb]][
|
|
625
|
+
[![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
|
|
633
626
|
|
|
634
|
-
To say "thanks
|
|
627
|
+
To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
|
|
635
628
|
|
|
636
629
|
[![Sponsor kettle-rb/dotenv-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]
|
|
637
630
|
|
|
@@ -674,7 +667,6 @@ Thanks for RTFM. ☺️
|
|
|
674
667
|
[✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
|
|
675
668
|
[✉️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
|
|
676
669
|
[✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
|
|
677
|
-
|
|
678
670
|
[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
|
|
679
671
|
[⛳️gem-namespace]: https://github.com/kettle-rb/dotenv-merge
|
|
680
672
|
[⛳️namespace-img]: https://img.shields.io/badge/namespace-Dotenv::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
|
|
@@ -798,7 +790,7 @@ Thanks for RTFM. ☺️
|
|
|
798
790
|
[📌gitmoji]: https://gitmoji.dev
|
|
799
791
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
800
792
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
801
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
793
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.353-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
802
794
|
[🔐security]: SECURITY.md
|
|
803
795
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
804
796
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -6,7 +6,8 @@ module Dotenv
|
|
|
6
6
|
# Parses and categorizes lines as assignments, comments, blank lines, or invalid.
|
|
7
7
|
#
|
|
8
8
|
# Inherits from Ast::Merge::AstNode for a normalized API across all ast-merge
|
|
9
|
-
# content nodes. This provides
|
|
9
|
+
# content nodes. This provides TreeHaver::Node protocol compatibility including
|
|
10
|
+
# #slice, #location, #unwrap, #type, #text, and other standard methods.
|
|
10
11
|
#
|
|
11
12
|
# Dotenv files follow a simple format where each line is one of:
|
|
12
13
|
# - `KEY=value` - Environment variable assignment
|
|
@@ -46,7 +47,7 @@ module Dotenv
|
|
|
46
47
|
attr_reader :line_number
|
|
47
48
|
|
|
48
49
|
# @return [Symbol, nil] The line type (:assignment, :comment, :blank, :invalid)
|
|
49
|
-
attr_reader :
|
|
50
|
+
attr_reader :line_type
|
|
50
51
|
|
|
51
52
|
# @return [String, nil] The environment variable key (for assignments)
|
|
52
53
|
attr_reader :key
|
|
@@ -64,7 +65,7 @@ module Dotenv
|
|
|
64
65
|
def initialize(raw, line_number)
|
|
65
66
|
@raw = raw
|
|
66
67
|
@line_number = line_number
|
|
67
|
-
@
|
|
68
|
+
@line_type = nil
|
|
68
69
|
@key = nil
|
|
69
70
|
@value = nil
|
|
70
71
|
@export = false
|
|
@@ -80,11 +81,17 @@ module Dotenv
|
|
|
80
81
|
super(slice: @raw, location: location)
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
# TreeHaver::Node protocol: type
|
|
85
|
+
# @return [String] "env_line"
|
|
86
|
+
def type
|
|
87
|
+
"env_line"
|
|
88
|
+
end
|
|
89
|
+
|
|
83
90
|
# Generate a unique signature for this line (used for merge matching)
|
|
84
91
|
#
|
|
85
92
|
# @return [Array<Symbol, String>, nil] Signature array [:env, key] for assignments, nil otherwise
|
|
86
93
|
def signature
|
|
87
|
-
return unless @
|
|
94
|
+
return unless @line_type == :assignment
|
|
88
95
|
|
|
89
96
|
[:env, @key]
|
|
90
97
|
end
|
|
@@ -93,28 +100,28 @@ module Dotenv
|
|
|
93
100
|
#
|
|
94
101
|
# @return [Boolean] true if the line is a valid KEY=value assignment
|
|
95
102
|
def assignment?
|
|
96
|
-
@
|
|
103
|
+
@line_type == :assignment
|
|
97
104
|
end
|
|
98
105
|
|
|
99
106
|
# Check if this line is a comment
|
|
100
107
|
#
|
|
101
108
|
# @return [Boolean] true if the line starts with #
|
|
102
109
|
def comment?
|
|
103
|
-
@
|
|
110
|
+
@line_type == :comment
|
|
104
111
|
end
|
|
105
112
|
|
|
106
113
|
# Check if this line is blank (empty or whitespace only)
|
|
107
114
|
#
|
|
108
115
|
# @return [Boolean] true if the line is blank
|
|
109
116
|
def blank?
|
|
110
|
-
@
|
|
117
|
+
@line_type == :blank
|
|
111
118
|
end
|
|
112
119
|
|
|
113
120
|
# Check if this line is invalid (unparseable)
|
|
114
121
|
#
|
|
115
122
|
# @return [Boolean] true if the line could not be parsed
|
|
116
123
|
def invalid?
|
|
117
|
-
@
|
|
124
|
+
@line_type == :invalid
|
|
118
125
|
end
|
|
119
126
|
|
|
120
127
|
# Check if this line has the export prefix
|
|
@@ -144,20 +151,20 @@ module Dotenv
|
|
|
144
151
|
#
|
|
145
152
|
# @return [String] A debug representation of this EnvLine
|
|
146
153
|
def inspect
|
|
147
|
-
"#<#{self.class.name} line=#{@line_number}
|
|
154
|
+
"#<#{self.class.name} line=#{@line_number} line_type=#{@line_type} key=#{@key.inspect}>"
|
|
148
155
|
end
|
|
149
156
|
|
|
150
157
|
private
|
|
151
158
|
|
|
152
|
-
# Parse the raw line content and set
|
|
159
|
+
# Parse the raw line content and set line_type, key, value, and export
|
|
153
160
|
#
|
|
154
161
|
# @return [void]
|
|
155
162
|
def parse!
|
|
156
163
|
stripped = @raw.strip
|
|
157
164
|
if stripped.empty?
|
|
158
|
-
@
|
|
165
|
+
@line_type = :blank
|
|
159
166
|
elsif stripped.start_with?("#")
|
|
160
|
-
@
|
|
167
|
+
@line_type = :comment
|
|
161
168
|
else
|
|
162
169
|
parse_assignment!(stripped)
|
|
163
170
|
end
|
|
@@ -178,14 +185,14 @@ module Dotenv
|
|
|
178
185
|
key_part, value_part = line.split("=", 2)
|
|
179
186
|
key_part = key_part.strip
|
|
180
187
|
if valid_key?(key_part)
|
|
181
|
-
@
|
|
188
|
+
@line_type = :assignment
|
|
182
189
|
@key = key_part
|
|
183
190
|
@value = unquote(value_part || "")
|
|
184
191
|
else
|
|
185
|
-
@
|
|
192
|
+
@line_type = :invalid
|
|
186
193
|
end
|
|
187
194
|
else
|
|
188
|
-
@
|
|
195
|
+
@line_type = :invalid
|
|
189
196
|
end
|
|
190
197
|
end
|
|
191
198
|
|
|
@@ -33,10 +33,12 @@ module Dotenv
|
|
|
33
33
|
# @param source [String] Dotenv source code to analyze
|
|
34
34
|
# @param freeze_token [String] Token for freeze block markers (default: "dotenv-merge")
|
|
35
35
|
# @param signature_generator [Proc, nil] Custom signature generator
|
|
36
|
-
|
|
36
|
+
# @param options [Hash] Additional options (forward compatibility - ignored by FileAnalysis)
|
|
37
|
+
def initialize(source, freeze_token: DEFAULT_FREEZE_TOKEN, signature_generator: nil, **options)
|
|
37
38
|
@source = source
|
|
38
39
|
@freeze_token = freeze_token
|
|
39
40
|
@signature_generator = signature_generator
|
|
41
|
+
# **options captures any additional parameters (e.g., node_typing) for forward compatibility
|
|
40
42
|
|
|
41
43
|
# Parse all lines
|
|
42
44
|
@lines = parse_lines(source)
|
|
@@ -35,8 +35,9 @@ module Dotenv
|
|
|
35
35
|
# Initialize a new merge result
|
|
36
36
|
# @param template_analysis [FileAnalysis] Analysis of the template file
|
|
37
37
|
# @param dest_analysis [FileAnalysis] Analysis of the destination file
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# @param options [Hash] Additional options for forward compatibility
|
|
39
|
+
def initialize(template_analysis, dest_analysis, **options)
|
|
40
|
+
super(template_analysis: template_analysis, dest_analysis: dest_analysis, **options)
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
# Add content from the template at the given statement index
|
|
@@ -19,78 +19,108 @@ module Dotenv
|
|
|
19
19
|
# add_template_only_nodes: true,
|
|
20
20
|
# )
|
|
21
21
|
# result = merger.merge
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
#
|
|
23
|
+
# @example With node_typing for per-node-type preferences
|
|
24
|
+
# merger = SmartMerger.new(template, dest,
|
|
25
|
+
# node_typing: { "EnvLine" => ->(n) { NodeTyping.with_merge_type(n, :secret) } },
|
|
26
|
+
# preference: { default: :destination, secret: :template })
|
|
27
|
+
class SmartMerger < ::Ast::Merge::SmartMergerBase
|
|
29
28
|
# Initialize a new SmartMerger
|
|
30
29
|
#
|
|
31
30
|
# @param template_content [String] Content of the template dotenv file
|
|
32
31
|
# @param dest_content [String] Content of the destination dotenv file
|
|
33
|
-
# @param
|
|
34
|
-
#
|
|
32
|
+
# @param signature_generator [Proc, nil] Custom signature generator
|
|
33
|
+
# @param preference [Symbol, Hash] :destination, :template, or per-type Hash
|
|
35
34
|
# @param add_template_only_nodes [Boolean] Whether to add template-only env vars
|
|
36
35
|
# (default: false)
|
|
37
36
|
# @param freeze_token [String] Token for freeze block markers
|
|
38
37
|
# (default: "dotenv-merge")
|
|
39
|
-
# @param
|
|
38
|
+
# @param match_refiner [#call, nil] Match refiner for fuzzy matching
|
|
39
|
+
# @param regions [Array<Hash>, nil] Region configurations for nested merging
|
|
40
|
+
# @param region_placeholder [String, nil] Custom placeholder for regions
|
|
41
|
+
# @param node_typing [Hash{Symbol,String => #call}, nil] Node typing configuration
|
|
42
|
+
# for per-node-type merge preferences
|
|
43
|
+
# @param options [Hash] Additional options for forward compatibility
|
|
40
44
|
def initialize(
|
|
41
45
|
template_content,
|
|
42
46
|
dest_content,
|
|
47
|
+
signature_generator: nil,
|
|
43
48
|
preference: :destination,
|
|
44
49
|
add_template_only_nodes: false,
|
|
45
|
-
freeze_token:
|
|
46
|
-
|
|
50
|
+
freeze_token: nil,
|
|
51
|
+
match_refiner: nil,
|
|
52
|
+
regions: nil,
|
|
53
|
+
region_placeholder: nil,
|
|
54
|
+
node_typing: nil,
|
|
55
|
+
**options
|
|
47
56
|
)
|
|
48
|
-
|
|
49
|
-
@add_template_only_nodes = add_template_only_nodes
|
|
50
|
-
|
|
51
|
-
# Parse template
|
|
52
|
-
@template_analysis = FileAnalysis.new(
|
|
57
|
+
super(
|
|
53
58
|
template_content,
|
|
54
|
-
freeze_token: freeze_token,
|
|
55
|
-
signature_generator: signature_generator,
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
# Parse destination
|
|
59
|
-
@dest_analysis = FileAnalysis.new(
|
|
60
59
|
dest_content,
|
|
61
|
-
freeze_token: freeze_token,
|
|
62
60
|
signature_generator: signature_generator,
|
|
61
|
+
preference: preference,
|
|
62
|
+
add_template_only_nodes: add_template_only_nodes,
|
|
63
|
+
freeze_token: freeze_token,
|
|
64
|
+
match_refiner: match_refiner,
|
|
65
|
+
regions: regions,
|
|
66
|
+
region_placeholder: region_placeholder,
|
|
67
|
+
node_typing: node_typing,
|
|
68
|
+
**options
|
|
63
69
|
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
protected
|
|
64
73
|
|
|
65
|
-
|
|
74
|
+
# @return [Class] The analysis class for dotenv files
|
|
75
|
+
def analysis_class
|
|
76
|
+
FileAnalysis
|
|
66
77
|
end
|
|
67
78
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
# @return [String] The default freeze token
|
|
80
|
+
def default_freeze_token
|
|
81
|
+
"dotenv-merge"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @return [Class, nil] No separate resolver class for dotenv
|
|
85
|
+
def resolver_class
|
|
86
|
+
nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @return [Class, nil] Result class (built with analysis args)
|
|
90
|
+
def result_class
|
|
91
|
+
nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Build the result with required analysis arguments
|
|
95
|
+
def build_result
|
|
96
|
+
MergeResult.new(@template_analysis, @dest_analysis)
|
|
73
97
|
end
|
|
74
98
|
|
|
75
|
-
#
|
|
99
|
+
# @return [Class] The template parse error class for dotenv
|
|
100
|
+
def template_parse_error_class
|
|
101
|
+
ParseError
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [Class] The destination parse error class for dotenv
|
|
105
|
+
def destination_parse_error_class
|
|
106
|
+
ParseError
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Perform the dotenv-specific merge with custom alignment logic
|
|
76
110
|
#
|
|
77
|
-
# @return [MergeResult] The merge result
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
alignment
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
process_alignment(alignment)
|
|
92
|
-
@result
|
|
93
|
-
end
|
|
111
|
+
# @return [MergeResult] The merge result
|
|
112
|
+
def perform_merge
|
|
113
|
+
alignment = align_statements
|
|
114
|
+
|
|
115
|
+
DebugLogger.debug("Alignment complete", {
|
|
116
|
+
total_entries: alignment.size,
|
|
117
|
+
matches: alignment.count { |e| e[:type] == :match },
|
|
118
|
+
template_only: alignment.count { |e| e[:type] == :template_only },
|
|
119
|
+
dest_only: alignment.count { |e| e[:type] == :dest_only },
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
process_alignment(alignment)
|
|
123
|
+
@result
|
|
94
124
|
end
|
|
95
125
|
|
|
96
126
|
private
|
|
@@ -211,8 +241,10 @@ module Dotenv
|
|
|
211
241
|
return
|
|
212
242
|
end
|
|
213
243
|
|
|
214
|
-
#
|
|
215
|
-
|
|
244
|
+
# Resolve preference (handles both Symbol and Hash preferences)
|
|
245
|
+
resolved_pref = resolve_preference(entry[:template_stmt], entry[:dest_stmt])
|
|
246
|
+
|
|
247
|
+
case resolved_pref
|
|
216
248
|
when :template
|
|
217
249
|
@result.add_from_template(entry[:template_index], decision: MergeResult::DECISION_TEMPLATE)
|
|
218
250
|
when :destination
|
|
@@ -222,6 +254,47 @@ module Dotenv
|
|
|
222
254
|
end
|
|
223
255
|
end
|
|
224
256
|
|
|
257
|
+
# Resolve preference for a matched pair
|
|
258
|
+
# @param template_stmt [Object] Template statement
|
|
259
|
+
# @param dest_stmt [Object] Destination statement
|
|
260
|
+
# @return [Symbol] :template or :destination
|
|
261
|
+
def resolve_preference(template_stmt, dest_stmt)
|
|
262
|
+
return @preference if @preference.is_a?(Symbol)
|
|
263
|
+
|
|
264
|
+
# Hash preference - check for node_typing-based merge_types
|
|
265
|
+
if @preference.is_a?(Hash)
|
|
266
|
+
# Apply node_typing if configured
|
|
267
|
+
typed_template = apply_node_typing(template_stmt)
|
|
268
|
+
apply_node_typing(dest_stmt)
|
|
269
|
+
|
|
270
|
+
# Check template merge_type first
|
|
271
|
+
if Ast::Merge::NodeTyping.typed_node?(typed_template)
|
|
272
|
+
merge_type = typed_template.merge_type
|
|
273
|
+
return @preference[merge_type] if @preference.key?(merge_type)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Fall back to default
|
|
277
|
+
return @preference[:default] || :destination
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
:destination
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Apply node typing to a statement if node_typing is configured
|
|
284
|
+
# @param stmt [Object] The statement
|
|
285
|
+
# @return [Object] The statement, possibly wrapped with merge_type
|
|
286
|
+
def apply_node_typing(stmt)
|
|
287
|
+
return stmt unless @node_typing
|
|
288
|
+
return stmt unless stmt
|
|
289
|
+
|
|
290
|
+
# Check by class name
|
|
291
|
+
type_key = stmt.class.name&.split("::")&.last
|
|
292
|
+
callable = @node_typing[type_key] || @node_typing[type_key&.to_sym]
|
|
293
|
+
return callable.call(stmt) if callable
|
|
294
|
+
|
|
295
|
+
stmt
|
|
296
|
+
end
|
|
297
|
+
|
|
225
298
|
# Process a template-only entry
|
|
226
299
|
# @param entry [Hash] Alignment entry
|
|
227
300
|
# @return [void]
|
data/lib/dotenv/merge/version.rb
CHANGED
data/lib/dotenv/merge.rb
CHANGED
|
@@ -68,6 +68,18 @@ module Dotenv
|
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# Register with ast-merge's MergeGemRegistry for RSpec dependency tags
|
|
72
|
+
# Only register if MergeGemRegistry is loaded (i.e., in test environment)
|
|
73
|
+
if defined?(Ast::Merge::RSpec::MergeGemRegistry)
|
|
74
|
+
Ast::Merge::RSpec::MergeGemRegistry.register(
|
|
75
|
+
:dotenv_merge,
|
|
76
|
+
require_path: "dotenv/merge",
|
|
77
|
+
merger_class: "Dotenv::Merge::SmartMerger",
|
|
78
|
+
test_source: "KEY=value",
|
|
79
|
+
category: :config,
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
71
83
|
Dotenv::Merge::Version.class_eval do
|
|
72
84
|
extend VersionGem::Basic
|
|
73
85
|
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dotenv-merge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -37,20 +37,46 @@ cert_chain:
|
|
|
37
37
|
-----END CERTIFICATE-----
|
|
38
38
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
39
39
|
dependencies:
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: tree_haver
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '5.0'
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 5.0.3
|
|
50
|
+
type: :runtime
|
|
51
|
+
prerelease: false
|
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - "~>"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '5.0'
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: 5.0.3
|
|
40
60
|
- !ruby/object:Gem::Dependency
|
|
41
61
|
name: ast-merge
|
|
42
62
|
requirement: !ruby/object:Gem::Requirement
|
|
43
63
|
requirements:
|
|
44
64
|
- - "~>"
|
|
45
65
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
66
|
+
version: '4.0'
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: 4.0.5
|
|
47
70
|
type: :runtime
|
|
48
71
|
prerelease: false
|
|
49
72
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
73
|
requirements:
|
|
51
74
|
- - "~>"
|
|
52
75
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
76
|
+
version: '4.0'
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: 4.0.5
|
|
54
80
|
- !ruby/object:Gem::Dependency
|
|
55
81
|
name: version_gem
|
|
56
82
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -266,10 +292,10 @@ licenses:
|
|
|
266
292
|
- MIT
|
|
267
293
|
metadata:
|
|
268
294
|
homepage_uri: https://dotenv-merge.galtzo.com/
|
|
269
|
-
source_code_uri: https://github.com/kettle-rb/dotenv-merge/tree/v1.0.
|
|
270
|
-
changelog_uri: https://github.com/kettle-rb/dotenv-merge/blob/v1.0.
|
|
295
|
+
source_code_uri: https://github.com/kettle-rb/dotenv-merge/tree/v1.0.2
|
|
296
|
+
changelog_uri: https://github.com/kettle-rb/dotenv-merge/blob/v1.0.2/CHANGELOG.md
|
|
271
297
|
bug_tracker_uri: https://github.com/kettle-rb/dotenv-merge/issues
|
|
272
|
-
documentation_uri: https://www.rubydoc.info/gems/dotenv-merge/1.0.
|
|
298
|
+
documentation_uri: https://www.rubydoc.info/gems/dotenv-merge/1.0.2
|
|
273
299
|
funding_uri: https://github.com/sponsors/pboling
|
|
274
300
|
wiki_uri: https://github.com/kettle-rb/dotenv-merge/wiki
|
|
275
301
|
news_uri: https://www.railsbling.com/tags/dotenv-merge
|
|
@@ -298,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
298
324
|
- !ruby/object:Gem::Version
|
|
299
325
|
version: '0'
|
|
300
326
|
requirements: []
|
|
301
|
-
rubygems_version: 4.0.
|
|
327
|
+
rubygems_version: 4.0.5
|
|
302
328
|
specification_version: 4
|
|
303
329
|
summary: "☯️ Intelligent .env file merging using structured parsing"
|
|
304
330
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|