dotenv-merge 1.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.
@@ -0,0 +1,212 @@
1
+ # Type signatures for dotenv-merge gem
2
+ # Smart merge for .env files using line-based analysis
3
+
4
+ module Dotenv
5
+ module Merge
6
+ VERSION: String
7
+
8
+ # Base error class for dotenv-merge
9
+ class Error < StandardError
10
+ end
11
+
12
+ # Raised when the template file cannot be parsed
13
+ class TemplateParseError < Error
14
+ attr_reader errors: Array[String]
15
+ attr_reader content: String?
16
+
17
+ def initialize: (Array[String] errors, ?content: String?) -> void
18
+ end
19
+
20
+ # Raised when the destination file cannot be parsed
21
+ class DestinationParseError < Error
22
+ attr_reader errors: Array[String]
23
+ attr_reader content: String?
24
+
25
+ def initialize: (Array[String] errors, ?content: String?) -> void
26
+ end
27
+
28
+ # Debug logging utility for Dotenv::Merge
29
+ module DebugLogger
30
+ extend Ast::Merge::DebugLogger
31
+
32
+ def self.env_var_name: () -> String
33
+ def self.env_var_name=: (String name) -> String
34
+ def self.log_prefix: () -> String
35
+ def self.log_prefix=: (String prefix) -> String
36
+ def self.enabled?: () -> bool
37
+ def self.debug: (String message, ?Hash[Symbol, untyped] context) -> void
38
+ def self.info: (String message) -> void
39
+ def self.warning: (String message) -> void
40
+ def self.time: [T] (String operation) { () -> T } -> T
41
+ def self.extract_node_info: (untyped node) -> Hash[Symbol, untyped]
42
+ end
43
+
44
+ # Represents a single line in a dotenv file
45
+ class EnvLine
46
+ attr_reader line_number: Integer
47
+ attr_reader raw: String
48
+ attr_reader key: String?
49
+ attr_reader value: String?
50
+ attr_reader comment: String?
51
+
52
+ def initialize: (
53
+ Integer line_number,
54
+ String raw,
55
+ ?key: String?,
56
+ ?value: String?,
57
+ ?comment: String?
58
+ ) -> void
59
+
60
+ def assignment?: () -> bool
61
+ def comment?: () -> bool
62
+ def blank?: () -> bool
63
+ def signature: () -> Array[Symbol | String]
64
+ def start_line: () -> Integer
65
+ def end_line: () -> Integer
66
+ def location: () -> Ast::Merge::FreezeNode::Location
67
+ def freeze_node?: () -> bool
68
+ def slice: () -> String
69
+ def to_s: () -> String
70
+ end
71
+
72
+ # Represents a freeze block in a dotenv file
73
+ class FreezeNode < Ast::Merge::FreezeNode
74
+ InvalidStructureError: singleton(Ast::Merge::FreezeNode::InvalidStructureError)
75
+ Location: singleton(Ast::Merge::FreezeNode::Location)
76
+
77
+ attr_reader analysis: FileAnalysis
78
+ attr_reader lines: Array[EnvLine]
79
+ attr_reader reason: String?
80
+
81
+ def initialize: (
82
+ start_line: Integer,
83
+ end_line: Integer,
84
+ analysis: FileAnalysis,
85
+ ?lines: Array[EnvLine]?,
86
+ ?reason: String?,
87
+ ?pattern_type: Symbol
88
+ ) -> void
89
+
90
+ def content: () -> String
91
+ def signature: () -> Array[Symbol | String]
92
+ def env_lines: () -> Array[EnvLine]
93
+ def assignment?: () -> bool
94
+ def comment?: () -> bool
95
+ def slice: () -> String
96
+ def inspect: () -> String
97
+ end
98
+
99
+ # File analysis for dotenv files
100
+ class FileAnalysis
101
+ include Ast::Merge::FileAnalysisBase
102
+
103
+ DEFAULT_FREEZE_TOKEN: String
104
+
105
+ attr_reader source: String
106
+ attr_reader lines: Array[EnvLine]
107
+ attr_reader freeze_token: String
108
+ attr_reader signature_generator: (^(EnvLine) -> Array[Symbol | String]?)?
109
+ attr_reader statements: Array[EnvLine | FreezeNode]
110
+ attr_reader freeze_blocks: Array[FreezeNode]
111
+
112
+ def initialize: (
113
+ String source,
114
+ ?freeze_token: String,
115
+ ?signature_generator: (^(EnvLine) -> Array[Symbol | String]?)?
116
+ ) -> void
117
+
118
+ def valid?: () -> bool
119
+ def nodes: () -> Array[EnvLine | FreezeNode]
120
+ def assignment_lines: () -> Array[EnvLine]
121
+ def line_at: (Integer line_number) -> String?
122
+ def normalized_line: (Integer line_num) -> String?
123
+ def in_freeze_block?: (Integer line_num) -> bool
124
+ def freeze_block_at: (Integer line_num) -> FreezeNode?
125
+ def signature_at: (Integer index) -> Array[Symbol | String]?
126
+ def generate_signature: (EnvLine | FreezeNode node) -> Array[Symbol | String]?
127
+ def compute_node_signature: (untyped node) -> Array[Symbol | String]?
128
+
129
+ private
130
+
131
+ def parse_lines: () -> Array[EnvLine]
132
+ def extract_freeze_blocks: () -> Array[FreezeNode]
133
+ def integrate_lines_and_freeze_blocks: () -> Array[EnvLine | FreezeNode]
134
+ end
135
+
136
+ # Result of a merge operation
137
+ class MergeResult < Ast::Merge::MergeResult
138
+ DECISION_KEPT_TEMPLATE: Symbol
139
+ DECISION_KEPT_DEST: Symbol
140
+ DECISION_MERGED: Symbol
141
+ DECISION_ADDED: Symbol
142
+ DECISION_FREEZE_BLOCK: Symbol
143
+
144
+ attr_reader template_analysis: FileAnalysis
145
+ attr_reader dest_analysis: FileAnalysis
146
+ attr_reader lines: Array[String]
147
+ attr_reader provenance: Array[Hash[Symbol, untyped]]
148
+ attr_reader decisions: Array[Hash[Symbol, untyped]]
149
+
150
+ def initialize: (
151
+ ?template_analysis: FileAnalysis?,
152
+ ?dest_analysis: FileAnalysis?,
153
+ ?conflicts: Array[Hash[Symbol, untyped]],
154
+ ?frozen_blocks: Array[FreezeNode],
155
+ ?stats: Hash[Symbol, untyped]
156
+ ) -> void
157
+
158
+ def add_line: (String line, Symbol origin, ?Integer? source_line) -> void
159
+ def add_env_line: (EnvLine env_line, Symbol decision) -> void
160
+ def add_freeze_block: (FreezeNode freeze_node) -> void
161
+ def to_s: () -> String
162
+ def to_dotenv: () -> String
163
+ def content: () -> Array[String]
164
+ def content_string: () -> String
165
+ def empty?: () -> bool
166
+ end
167
+
168
+ # Smart merger for dotenv files
169
+ class SmartMerger
170
+ include Ast::Merge::MergerConfig
171
+
172
+ attr_reader template_analysis: FileAnalysis
173
+ attr_reader dest_analysis: FileAnalysis
174
+ attr_reader signature_match_preference: (Symbol | Hash[Symbol, Symbol])
175
+ attr_reader add_template_only_nodes: bool
176
+
177
+ def initialize: (
178
+ String template_content,
179
+ String dest_content,
180
+ ?signature_match_preference: (Symbol | Hash[Symbol, Symbol]),
181
+ ?add_template_only_nodes: bool,
182
+ ?freeze_token: String,
183
+ ?signature_generator: (^(EnvLine) -> Array[Symbol | String]?)?,
184
+ ?node_splitter: Hash[Symbol, untyped]?
185
+ ) -> void
186
+
187
+ def merge: () -> MergeResult
188
+
189
+ private
190
+
191
+ def perform_merge: () -> MergeResult
192
+ def merge_lines: (MergeResult result) -> void
193
+ end
194
+
195
+ # Conflict resolver for dotenv merges
196
+ class ConflictResolver
197
+ attr_reader template_analysis: FileAnalysis
198
+ attr_reader dest_analysis: FileAnalysis
199
+ attr_reader signature_match_preference: (Symbol | Hash[Symbol, Symbol])
200
+ attr_reader add_template_only_nodes: bool
201
+
202
+ def initialize: (
203
+ FileAnalysis template_analysis,
204
+ FileAnalysis dest_analysis,
205
+ ?signature_match_preference: (Symbol | Hash[Symbol, Symbol]),
206
+ ?add_template_only_nodes: bool
207
+ ) -> void
208
+
209
+ def resolve: (untyped boundary, MergeResult result) -> void
210
+ end
211
+ end
212
+ end
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,304 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotenv-merge
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter H. Boling
8
+ bindir: exe
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIEgDCCAuigAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMRUwEwYDVQQDDAxwZXRl
13
+ ci5ib2xpbmcxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkW
14
+ A2NvbTAeFw0yNTA1MDQxNTMzMDlaFw00NTA0MjkxNTMzMDlaMEMxFTATBgNVBAMM
15
+ DHBldGVyLmJvbGluZzEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
16
+ LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAruUoo0WA
17
+ uoNuq6puKWYeRYiZekz/nsDeK5x/0IEirzcCEvaHr3Bmz7rjo1I6On3gGKmiZs61
18
+ LRmQ3oxy77ydmkGTXBjruJB+pQEn7UfLSgQ0xa1/X3kdBZt6RmabFlBxnHkoaGY5
19
+ mZuZ5+Z7walmv6sFD9ajhzj+oIgwWfnEHkXYTR8I6VLN7MRRKGMPoZ/yvOmxb2DN
20
+ coEEHWKO9CvgYpW7asIihl/9GMpKiRkcYPm9dGQzZc6uTwom1COfW0+ZOFrDVBuV
21
+ FMQRPswZcY4Wlq0uEBLPU7hxnCL9nKK6Y9IhdDcz1mY6HZ91WImNslOSI0S8hRpj
22
+ yGOWxQIhBT3fqCBlRIqFQBudrnD9jSNpSGsFvbEijd5ns7Z9ZMehXkXDycpGAUj1
23
+ to/5cuTWWw1JqUWrKJYoifnVhtE1o1DZ+LkPtWxHtz5kjDG/zR3MG0Ula0UOavlD
24
+ qbnbcXPBnwXtTFeZ3C+yrWpE4pGnl3yGkZj9SMTlo9qnTMiPmuWKQDatAgMBAAGj
25
+ fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQE8uWvNbPVNRXZ
26
+ HlgPbc2PCzC4bjAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
27
+ A1UdEgQaMBiBFnBldGVyLmJvbGluZ0BnbWFpbC5jb20wDQYJKoZIhvcNAQELBQAD
28
+ ggGBAJbnUwfJQFPkBgH9cL7hoBfRtmWiCvdqdjeTmi04u8zVNCUox0A4gT982DE9
29
+ wmuN12LpdajxZONqbXuzZvc+nb0StFwmFYZG6iDwaf4BPywm2e/Vmq0YG45vZXGR
30
+ L8yMDSK1cQXjmA+ZBKOHKWavxP6Vp7lWvjAhz8RFwqF9GuNIdhv9NpnCAWcMZtpm
31
+ GUPyIWw/Cw/2wZp74QzZj6Npx+LdXoLTF1HMSJXZ7/pkxLCsB8m4EFVdb/IrW/0k
32
+ kNSfjtAfBHO8nLGuqQZVH9IBD1i9K6aSs7pT6TW8itXUIlkIUI2tg5YzW6OFfPzq
33
+ QekSkX3lZfY+HTSp/o+YvKkqWLUV7PQ7xh1ZYDtocpaHwgxe/j3bBqHE+CUPH2vA
34
+ 0V/FwdTRWcwsjVoOJTrYcff8pBZ8r2MvtAc54xfnnhGFzeRHfcltobgFxkAXdE6p
35
+ DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
36
+ L9nRqA==
37
+ -----END CERTIFICATE-----
38
+ date: 1980-01-02 00:00:00.000000000 Z
39
+ dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: ast-merge
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: version_gem
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.1'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.1.9
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '1.1'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.1.9
74
+ - !ruby/object:Gem::Dependency
75
+ name: kettle-dev
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.1'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.1'
88
+ - !ruby/object:Gem::Dependency
89
+ name: bundler-audit
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: 0.9.2
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: 0.9.2
102
+ - !ruby/object:Gem::Dependency
103
+ name: rake
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '13.0'
109
+ type: :development
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '13.0'
116
+ - !ruby/object:Gem::Dependency
117
+ name: require_bench
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1.0'
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: 1.0.4
126
+ type: :development
127
+ prerelease: false
128
+ version_requirements: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '1.0'
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: 1.0.4
136
+ - !ruby/object:Gem::Dependency
137
+ name: appraisal2
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '3.0'
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '3.0'
150
+ - !ruby/object:Gem::Dependency
151
+ name: kettle-test
152
+ requirement: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '1.0'
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: 1.0.6
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.0'
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: 1.0.6
170
+ - !ruby/object:Gem::Dependency
171
+ name: ruby-progressbar
172
+ requirement: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - "~>"
175
+ - !ruby/object:Gem::Version
176
+ version: '1.13'
177
+ type: :development
178
+ prerelease: false
179
+ version_requirements: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - "~>"
182
+ - !ruby/object:Gem::Version
183
+ version: '1.13'
184
+ - !ruby/object:Gem::Dependency
185
+ name: stone_checksums
186
+ requirement: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - "~>"
189
+ - !ruby/object:Gem::Version
190
+ version: '1.0'
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: 1.0.2
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '1.0'
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: 1.0.2
204
+ - !ruby/object:Gem::Dependency
205
+ name: gitmoji-regex
206
+ requirement: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - "~>"
209
+ - !ruby/object:Gem::Version
210
+ version: '1.0'
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ version: 1.0.3
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - "~>"
219
+ - !ruby/object:Gem::Version
220
+ version: '1.0'
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: 1.0.3
224
+ description: "☯️ Dotenv::Merge provides smart .env file merging that preserves comments,
225
+ understands variable assignments, and supports freeze blocks for protecting sensitive
226
+ configuration. Perfect for merging environment templates with local overrides."
227
+ email:
228
+ - floss@galtzo.com
229
+ executables: []
230
+ extensions: []
231
+ extra_rdoc_files:
232
+ - CHANGELOG.md
233
+ - CITATION.cff
234
+ - CODE_OF_CONDUCT.md
235
+ - CONTRIBUTING.md
236
+ - FUNDING.md
237
+ - LICENSE.txt
238
+ - README.md
239
+ - REEK
240
+ - RUBOCOP.md
241
+ - SECURITY.md
242
+ files:
243
+ - CHANGELOG.md
244
+ - CITATION.cff
245
+ - CODE_OF_CONDUCT.md
246
+ - CONTRIBUTING.md
247
+ - FUNDING.md
248
+ - LICENSE.txt
249
+ - README.md
250
+ - REEK
251
+ - RUBOCOP.md
252
+ - SECURITY.md
253
+ - lib/dotenv-merge.rb
254
+ - lib/dotenv/merge.rb
255
+ - lib/dotenv/merge/debug_logger.rb
256
+ - lib/dotenv/merge/env_line.rb
257
+ - lib/dotenv/merge/file_analysis.rb
258
+ - lib/dotenv/merge/freeze_node.rb
259
+ - lib/dotenv/merge/merge_result.rb
260
+ - lib/dotenv/merge/smart_merger.rb
261
+ - lib/dotenv/merge/version.rb
262
+ - sig/dotenv/merge.rbs
263
+ - sig/dotenv/merge/env_line.rbs
264
+ homepage: https://github.com/kettle-rb/dotenv-merge
265
+ licenses:
266
+ - MIT
267
+ metadata:
268
+ homepage_uri: https://dotenv-merge.galtzo.com/
269
+ source_code_uri: https://github.com/kettle-rb/dotenv-merge/tree/v1.0.0
270
+ changelog_uri: https://github.com/kettle-rb/dotenv-merge/blob/v1.0.0/CHANGELOG.md
271
+ bug_tracker_uri: https://github.com/kettle-rb/dotenv-merge/issues
272
+ documentation_uri: https://www.rubydoc.info/gems/dotenv-merge/1.0.0
273
+ funding_uri: https://github.com/sponsors/pboling
274
+ wiki_uri: https://github.com/kettle-rb/dotenv-merge/wiki
275
+ news_uri: https://www.railsbling.com/tags/dotenv-merge
276
+ discord_uri: https://discord.gg/3qme4XHNKN
277
+ rubygems_mfa_required: 'true'
278
+ rdoc_options:
279
+ - "--title"
280
+ - dotenv-merge - ☯️ Intelligent .env file merging using structured parsing
281
+ - "--main"
282
+ - README.md
283
+ - "--exclude"
284
+ - "^sig/"
285
+ - "--line-numbers"
286
+ - "--inline-source"
287
+ - "--quiet"
288
+ require_paths:
289
+ - lib
290
+ required_ruby_version: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - ">="
293
+ - !ruby/object:Gem::Version
294
+ version: 3.2.0
295
+ required_rubygems_version: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - ">="
298
+ - !ruby/object:Gem::Version
299
+ version: '0'
300
+ requirements: []
301
+ rubygems_version: 4.0.1
302
+ specification_version: 4
303
+ summary: "☯️ Intelligent .env file merging using structured parsing"
304
+ test_files: []
metadata.gz.sig ADDED
@@ -0,0 +1,4 @@
1
+ ���Y��qm7���jj@
2
+ K'��+{
3
+ u���[���<��:��z�,c��-����&�
4
+ ׉��$A~�M�|� r����;OGh�گR��ɺL�1�.�fp� gPM�'i��]���8mS��y�