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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +181 -1
- data/LICENSE.txt +1 -1
- data/README.md +294 -144
- data/lib/toml/merge/conflict_resolver.rb +60 -107
- data/lib/toml/merge/emitter.rb +120 -0
- data/lib/toml/merge/file_analysis.rb +122 -39
- data/lib/toml/merge/merge_result.rb +10 -4
- data/lib/toml/merge/node_type_normalizer.rb +256 -0
- data/lib/toml/merge/node_wrapper.rb +342 -177
- data/lib/toml/merge/smart_merger.rb +42 -4
- data/lib/toml/merge/table_match_refiner.rb +4 -2
- data/lib/toml/merge/version.rb +1 -1
- data/lib/toml/merge.rb +8 -33
- data.tar.gz.sig +0 -0
- metadata +22 -22
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Toml
|
|
4
|
+
module Merge
|
|
5
|
+
# Alias for the shared normalizer module from ast-merge
|
|
6
|
+
NodeTypingNormalizer = Ast::Merge::NodeTyping::Normalizer
|
|
7
|
+
|
|
8
|
+
# Normalizes backend-specific node types to canonical TOML types.
|
|
9
|
+
#
|
|
10
|
+
# Uses Ast::Merge::NodeTyping::Wrapper to wrap nodes with canonical
|
|
11
|
+
# merge_type, allowing portable merge rules across backends.
|
|
12
|
+
#
|
|
13
|
+
# ## Thread Safety
|
|
14
|
+
#
|
|
15
|
+
# All backend registration and lookup operations are thread-safe via
|
|
16
|
+
# the shared Ast::Merge::NodeTyping::Normalizer module.
|
|
17
|
+
#
|
|
18
|
+
# ## Backends
|
|
19
|
+
#
|
|
20
|
+
# Currently supports:
|
|
21
|
+
# - `:tree_sitter` - tree-sitter-toml grammar (via ruby_tree_sitter, tree_stump, FFI)
|
|
22
|
+
# - `:citrus` - toml-rb gem with Citrus parser
|
|
23
|
+
#
|
|
24
|
+
# ## Extensibility
|
|
25
|
+
#
|
|
26
|
+
# New backends can be registered at runtime:
|
|
27
|
+
#
|
|
28
|
+
# @example Registering a new backend
|
|
29
|
+
# NodeTypeNormalizer.register_backend(:my_toml_parser, {
|
|
30
|
+
# key_value: :pair,
|
|
31
|
+
# section: :table,
|
|
32
|
+
# section_array: :array_of_tables,
|
|
33
|
+
# })
|
|
34
|
+
#
|
|
35
|
+
# ## Canonical Types
|
|
36
|
+
#
|
|
37
|
+
# The following canonical types are used for portable merge rules:
|
|
38
|
+
#
|
|
39
|
+
# ### Document Structure
|
|
40
|
+
# - `:document` - Root document node
|
|
41
|
+
# - `:table` - Table/section header `[section]`
|
|
42
|
+
# - `:array_of_tables` - Array of tables `[[section]]`
|
|
43
|
+
# - `:pair` - Key-value pair `key = value`
|
|
44
|
+
#
|
|
45
|
+
# ### Key Types
|
|
46
|
+
# - `:bare_key` - Unquoted key
|
|
47
|
+
# - `:quoted_key` - Quoted key `"key"` or `'key'`
|
|
48
|
+
# - `:dotted_key` - Dotted key `a.b.c`
|
|
49
|
+
#
|
|
50
|
+
# ### Value Types
|
|
51
|
+
# - `:string` - String values (basic or literal)
|
|
52
|
+
# - `:integer` - Integer values
|
|
53
|
+
# - `:float` - Floating point values
|
|
54
|
+
# - `:boolean` - Boolean `true`/`false`
|
|
55
|
+
# - `:array` - Array values `[1, 2, 3]`
|
|
56
|
+
# - `:inline_table` - Inline table `{ key = value }`
|
|
57
|
+
#
|
|
58
|
+
# ### Date/Time Types
|
|
59
|
+
# - `:datetime` - Date/time values (offset, local, date-only, time-only)
|
|
60
|
+
#
|
|
61
|
+
# ### Other
|
|
62
|
+
# - `:comment` - Comment lines
|
|
63
|
+
#
|
|
64
|
+
# @see Ast::Merge::NodeTyping::Wrapper
|
|
65
|
+
# @see Ast::Merge::NodeTyping::Normalizer
|
|
66
|
+
module NodeTypeNormalizer
|
|
67
|
+
extend NodeTypingNormalizer
|
|
68
|
+
|
|
69
|
+
# Configure default backend mappings.
|
|
70
|
+
# Maps backend-specific type symbols to canonical type symbols.
|
|
71
|
+
#
|
|
72
|
+
# Both tree-sitter-toml and citrus/toml-rb produce similar node types,
|
|
73
|
+
# so the mappings are largely identity mappings with some normalization.
|
|
74
|
+
configure_normalizer(
|
|
75
|
+
# tree-sitter-toml grammar node types
|
|
76
|
+
# Reference: https://github.com/tree-sitter-grammars/tree-sitter-toml
|
|
77
|
+
# All native TreeHaver backends (mri, rust, ffi) use this grammar.
|
|
78
|
+
tree_sitter: {
|
|
79
|
+
# Document structure
|
|
80
|
+
document: :document,
|
|
81
|
+
table: :table,
|
|
82
|
+
table_array_element: :array_of_tables, # tree-sitter uses this name
|
|
83
|
+
|
|
84
|
+
# Key-value pairs
|
|
85
|
+
pair: :pair,
|
|
86
|
+
|
|
87
|
+
# Key types
|
|
88
|
+
bare_key: :bare_key,
|
|
89
|
+
quoted_key: :quoted_key,
|
|
90
|
+
dotted_key: :dotted_key,
|
|
91
|
+
|
|
92
|
+
# Value types
|
|
93
|
+
string: :string,
|
|
94
|
+
basic_string: :string,
|
|
95
|
+
literal_string: :string,
|
|
96
|
+
multiline_basic_string: :string,
|
|
97
|
+
multiline_literal_string: :string,
|
|
98
|
+
integer: :integer,
|
|
99
|
+
float: :float,
|
|
100
|
+
boolean: :boolean,
|
|
101
|
+
array: :array,
|
|
102
|
+
inline_table: :inline_table,
|
|
103
|
+
|
|
104
|
+
# Date/time types
|
|
105
|
+
offset_date_time: :datetime,
|
|
106
|
+
local_date_time: :datetime,
|
|
107
|
+
local_date: :datetime,
|
|
108
|
+
local_time: :datetime,
|
|
109
|
+
|
|
110
|
+
# Other
|
|
111
|
+
comment: :comment,
|
|
112
|
+
|
|
113
|
+
# Punctuation (usually not needed for merge logic, but map them)
|
|
114
|
+
"=": :equals,
|
|
115
|
+
"[": :bracket_open,
|
|
116
|
+
"]": :bracket_close,
|
|
117
|
+
"[[": :double_bracket_open,
|
|
118
|
+
"]]": :double_bracket_close,
|
|
119
|
+
"{": :brace_open,
|
|
120
|
+
"}": :brace_close,
|
|
121
|
+
",": :comma,
|
|
122
|
+
}.freeze,
|
|
123
|
+
|
|
124
|
+
# Citrus/toml-rb backend node types
|
|
125
|
+
# These are produced by TreeHaver's Citrus adapter wrapping toml-rb
|
|
126
|
+
# Verified via examples/map_citrus_node_types.rb script
|
|
127
|
+
citrus: {
|
|
128
|
+
# Document structure
|
|
129
|
+
document: :document,
|
|
130
|
+
table: :table,
|
|
131
|
+
table_array: :array_of_tables, # Citrus produces :table_array (not :table_array_element)
|
|
132
|
+
|
|
133
|
+
# Key-value pairs
|
|
134
|
+
keyvalue: :pair, # Citrus produces :keyvalue (not :pair)
|
|
135
|
+
pair: :pair, # Keep for compatibility if TreeHaver normalizes
|
|
136
|
+
|
|
137
|
+
# Key types
|
|
138
|
+
bare_key: :bare_key,
|
|
139
|
+
quoted_key: :quoted_key,
|
|
140
|
+
dotted_key: :dotted_key,
|
|
141
|
+
key: :bare_key, # Citrus uses :key wrapper
|
|
142
|
+
stripped_key: :bare_key, # Citrus uses :stripped_key wrapper
|
|
143
|
+
|
|
144
|
+
# Value types - Citrus uses more specific type names
|
|
145
|
+
string: :string,
|
|
146
|
+
basic_string: :string,
|
|
147
|
+
literal_string: :string,
|
|
148
|
+
multiline_string: :string,
|
|
149
|
+
multiline_literal: :string,
|
|
150
|
+
integer: :integer,
|
|
151
|
+
decimal_integer: :integer,
|
|
152
|
+
hexadecimal_integer: :integer,
|
|
153
|
+
octal_integer: :integer,
|
|
154
|
+
binary_integer: :integer,
|
|
155
|
+
float: :float,
|
|
156
|
+
fractional_float: :float,
|
|
157
|
+
boolean: :boolean,
|
|
158
|
+
true: :boolean,
|
|
159
|
+
false: :boolean,
|
|
160
|
+
array: :array,
|
|
161
|
+
inline_table: :inline_table,
|
|
162
|
+
|
|
163
|
+
# Date/time types - Citrus uses specific names
|
|
164
|
+
datetime: :datetime,
|
|
165
|
+
date: :datetime,
|
|
166
|
+
time: :datetime,
|
|
167
|
+
local_date: :datetime,
|
|
168
|
+
local_time: :datetime,
|
|
169
|
+
local_datetime: :datetime,
|
|
170
|
+
offset_datetime: :datetime,
|
|
171
|
+
date_skeleton: :datetime,
|
|
172
|
+
time_skeleton: :datetime,
|
|
173
|
+
|
|
174
|
+
# Other
|
|
175
|
+
comment: :comment,
|
|
176
|
+
space: :whitespace,
|
|
177
|
+
line_break: :whitespace,
|
|
178
|
+
indent: :whitespace,
|
|
179
|
+
repeat: :whitespace,
|
|
180
|
+
unknown: :unknown,
|
|
181
|
+
|
|
182
|
+
# Punctuation
|
|
183
|
+
"=": :equals,
|
|
184
|
+
"[": :bracket_open,
|
|
185
|
+
"]": :bracket_close,
|
|
186
|
+
"[[": :double_bracket_open,
|
|
187
|
+
"]]": :double_bracket_close,
|
|
188
|
+
"{": :brace_open,
|
|
189
|
+
"}": :brace_close,
|
|
190
|
+
",": :comma,
|
|
191
|
+
}.freeze,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
class << self
|
|
195
|
+
# Default backend for TOML normalization
|
|
196
|
+
DEFAULT_BACKEND = :tree_sitter
|
|
197
|
+
|
|
198
|
+
# Get the canonical type for a backend-specific type.
|
|
199
|
+
# Overrides the shared Normalizer to default to :tree_sitter backend.
|
|
200
|
+
#
|
|
201
|
+
# @param backend_type [Symbol, String, nil] The backend's node type
|
|
202
|
+
# @param backend [Symbol] The backend identifier (defaults to :tree_sitter)
|
|
203
|
+
# @return [Symbol, nil] Canonical type (or original if no mapping)
|
|
204
|
+
def canonical_type(backend_type, backend = DEFAULT_BACKEND)
|
|
205
|
+
super(backend_type, backend)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Wrap a node with its canonical type as merge_type.
|
|
209
|
+
# Overrides the shared Normalizer to default to :tree_sitter backend.
|
|
210
|
+
#
|
|
211
|
+
# @param node [Object] The backend node to wrap (must respond to #type)
|
|
212
|
+
# @param backend [Symbol] The backend identifier (defaults to :tree_sitter)
|
|
213
|
+
# @return [Ast::Merge::NodeTyping::Wrapper] Wrapped node with canonical merge_type
|
|
214
|
+
def wrap(node, backend = DEFAULT_BACKEND)
|
|
215
|
+
super(node, backend)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Check if a type is a table type (regular or array of tables)
|
|
219
|
+
#
|
|
220
|
+
# @param type [Symbol, String] The type to check
|
|
221
|
+
# @return [Boolean]
|
|
222
|
+
def table_type?(type)
|
|
223
|
+
canonical = type.to_sym
|
|
224
|
+
%i[table array_of_tables].include?(canonical)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Check if a type is a value type (string, integer, etc.)
|
|
228
|
+
#
|
|
229
|
+
# @param type [Symbol, String] The type to check
|
|
230
|
+
# @return [Boolean]
|
|
231
|
+
def value_type?(type)
|
|
232
|
+
canonical = type.to_sym
|
|
233
|
+
%i[string integer float boolean array inline_table datetime].include?(canonical)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Check if a type is a key type
|
|
237
|
+
#
|
|
238
|
+
# @param type [Symbol, String] The type to check
|
|
239
|
+
# @return [Boolean]
|
|
240
|
+
def key_type?(type)
|
|
241
|
+
canonical = type.to_sym
|
|
242
|
+
%i[bare_key quoted_key dotted_key].include?(canonical)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Check if a type is a container type (can have children)
|
|
246
|
+
#
|
|
247
|
+
# @param type [Symbol, String] The type to check
|
|
248
|
+
# @return [Boolean]
|
|
249
|
+
def container_type?(type)
|
|
250
|
+
canonical = type.to_sym
|
|
251
|
+
%i[document table array_of_tables array inline_table].include?(canonical)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|