ast-merge 3.0.0 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79e0b486476d9494e6e1065d71b13ef8b940bd7d5db8caffd4784231ce239ad2
4
- data.tar.gz: 941f9604854c537b087b76a253945f35dbc81f8f5b701f60dcad0ab1b9a35026
3
+ metadata.gz: 4ce2b23f374b6f178709f84a66ccbed7b997a05d170d7b1f63ede714fc844469
4
+ data.tar.gz: d0ae1bc694c669108b5ddaac372424c02f8528f3c59642ced6fb7bb1af67dcf4
5
5
  SHA512:
6
- metadata.gz: f8b51479340dd11352faac1e7ca2933481dcbf012b1fbff8176a5f425e07717848dce99f4b631cdc5562fc897e4ae2bb7af06d9380d105a6f25ab612473cd231
7
- data.tar.gz: d45e550372da739a549ba78c27fe15836a8ca17b674c88dcee958f0f58732f54b7d52d6d9b99a22ee635f2ad1862c9a2631e8cc15fb4fa3c38aca528d58142cc
6
+ metadata.gz: 41981f4b37122e224ecc1b3047156ec15871742fbca09b8203acb91c27df7acf61164871c2ee7eac07db32a12acccc7c8dda3b83b8cd7dafd8f86ade604a82a6
7
+ data.tar.gz: 29c07de568c15bc8a78b6363c438e6c7902af5f24d8d441aaa9f9417bceeedb62107f40e95a226864be3492b16373ae4493efa0ed956c780448bf4a3168980b9
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,32 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.1.0] - 2026-01-08
34
+
35
+ - TAG: [v3.1.0][3.1.0t]
36
+ - COVERAGE: 96.89% -- 2465/2544 lines in 47 files
37
+ - BRANCH COVERAGE: 89.62% -- 794/886 branches in 47 files
38
+ - 98.75% documented
39
+
40
+ ### Added
41
+
42
+ - `Ast::Merge::EmitterBase` - Abstract base class for format-specific emitters
43
+ - Provides common infrastructure for converting AST structures back to text
44
+ - Tracks indentation level with configurable `indent_size` (default: 2 spaces)
45
+ - Manages output lines collection with `#lines` accessor
46
+ - `#emit_blank_line` - Emit an empty line
47
+ - `#emit_leading_comments` - Emit comments from CommentTracker
48
+ - `#emit_raw_lines` - Emit lines without modification (preserves exact formatting)
49
+ - `#to_s` - Get output as a single string with trailing newline
50
+ - `#clear` - Reset emitter state
51
+ - `#indent` / `#dedent` - Increase/decrease indentation level
52
+ - Subclass hooks: `#initialize_subclass_state`, `#clear_subclass_state`, `#emit_tracked_comment`
53
+ - Used by jsonc-merge, json-merge, bash-merge, toml-merge, and psych-merge emitters
54
+
55
+ ### Changed
56
+
57
+ - tree_haver v4.0.0
58
+
33
59
  ## [3.0.0] - 2026-01-05
34
60
 
35
61
  - TAG: [v3.0.0][3.0.0t]
@@ -507,7 +533,9 @@ Please file a bug if you notice a violation of semantic versioning.
507
533
 
508
534
  - Initial release
509
535
 
510
- [Unreleased]: https://github.com/kettle-rb/ast-merge/compare/v3.0.0...HEAD
536
+ [Unreleased]: https://github.com/kettle-rb/ast-merge/compare/v3.1.0...HEAD
537
+ [3.1.0]: https://github.com/kettle-rb/ast-merge/compare/v3.0.0...v3.1.0
538
+ [3.1.0t]: https://github.com/kettle-rb/ast-merge/releases/tag/v3.1.0
511
539
  [3.0.0]: https://github.com/kettle-rb/ast-merge/compare/v2.0.10...v3.0.0
512
540
  [3.0.0t]: https://github.com/kettle-rb/ast-merge/releases/tag/v3.0.0
513
541
  [2.0.10]: https://github.com/kettle-rb/ast-merge/compare/v2.0.9...v2.0.10
data/README.md CHANGED
@@ -75,12 +75,36 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
75
75
  | [rbs-merge][rbs-merge] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
76
76
  | [toml-merge][toml-merge] | TOML | [Citrus + toml-rb][toml-rb] (default, via tree_haver), [tree-sitter-toml][ts-toml] (via tree_haver) | Smart merge for TOML files |
77
77
 
78
+ #### Backend Platform Compatibility
79
+
80
+ tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
81
+
82
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
83
+ |------------------------------------------------|:---:|:-----:|:-----------:|-----------------------------------------------------|
84
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
85
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
86
+ | **FFI** | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
87
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
88
+ | **Prism** | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
89
+ | **Psych** | ✅ | ✅ | ✅ | YAML parsing, stdlib |
90
+ | **Citrus** | ✅ | ✅ | ✅ | Pure Ruby, no native dependencies |
91
+ | **Commonmarker** | ✅ | ❌ | ❓ | Rust extension for Markdown |
92
+ | **Markly** | ✅ | ❌ | ❓ | C extension for Markdown |
93
+
94
+ **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
95
+
96
+ **Why some backends don't work on certain platforms**:
97
+
98
+ - **JRuby**: Runs on the JVM; cannot load native C/Rust extensions (`.so` files)
99
+ - **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`)
100
+ - **FFI on TruffleRuby**: TruffleRuby's FFI implementation doesn't support returning structs by value, which tree-sitter's C API requires
101
+
78
102
  **Example implementations** for the gem templating use case:
79
103
 
80
- | Gem | Purpose | Description |
81
- | --- | --- | --- |
82
- | [kettle-dev](https://github.com/kettle-rb/kettle-dev) | Gem Development | Gem templating tool using `*-merge` gems |
83
- | [kettle-jem](https://github.com/kettle-rb/kettle-jem) | Gem Templating | Gem template library with smart merge support |
104
+ | Gem | Purpose | Description |
105
+ |--------------------------|-----------------|-----------------------------------------------|
106
+ | [kettle-dev][kettle-dev] | Gem Development | Gem templating tool using `*-merge` gems |
107
+ | [kettle-jem][kettle-jem] | Gem Templating | Gem template library with smart merge support |
84
108
 
85
109
  [tree_haver]: https://github.com/kettle-rb/tree_haver
86
110
  [ast-merge]: https://github.com/kettle-rb/ast-merge
@@ -100,8 +124,11 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
100
124
  [prism]: https://github.com/ruby/prism
101
125
  [psych]: https://github.com/ruby/psych
102
126
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
127
+ [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
103
128
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
129
+ [ts-rbs]: https://github.com/joker1007/tree-sitter-rbs
104
130
  [ts-toml]: https://github.com/tree-sitter-grammars/tree-sitter-toml
131
+ [dotenv]: https://github.com/bkeepers/dotenv
105
132
  [rbs]: https://github.com/ruby/rbs
106
133
  [toml-rb]: https://github.com/emancu/toml-rb
107
134
  [markly]: https://github.com/ioquatix/markly
@@ -110,10 +137,6 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
110
137
  [tree_stump]: https://github.com/joker1007/tree_stump
111
138
  [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
112
139
 
113
-
114
- [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
115
- [dotenv]: https://github.com/bkeepers/dotenv
116
-
117
140
  #### Backend Platform Compatibility
118
141
 
119
142
  tree\_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
@@ -1033,7 +1056,7 @@ Thanks for RTFM. ☺️
1033
1056
  [📌gitmoji]: https://gitmoji.dev
1034
1057
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1035
1058
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1036
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.540-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1059
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.544-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1037
1060
  [🔐security]: SECURITY.md
1038
1061
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1039
1062
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ast
4
+ module Merge
5
+ # Base class for emitters that convert AST structures back to text.
6
+ # Provides common functionality for tracking indentation, managing output lines,
7
+ # and handling comments.
8
+ #
9
+ # Subclasses implement format-specific emission methods (e.g., emit_pair for JSON,
10
+ # emit_variable_assignment for Bash, etc.)
11
+ #
12
+ # @example Implementing a custom emitter
13
+ # class MyEmitter < Ast::Merge::EmitterBase
14
+ # def emit_my_construct(data)
15
+ # add_comma_if_needed if @needs_separator
16
+ # @lines << "#{current_indent}my_syntax: #{data}"
17
+ # @needs_separator = true
18
+ # end
19
+ # end
20
+ class EmitterBase
21
+ # @return [Array<String>] Output lines
22
+ attr_reader :lines
23
+
24
+ # @return [Integer] Current indentation level
25
+ attr_reader :indent_level
26
+
27
+ # @return [Integer] Spaces per indent level
28
+ attr_reader :indent_size
29
+
30
+ # Initialize a new emitter
31
+ #
32
+ # @param indent_size [Integer] Number of spaces per indent level
33
+ # @param options [Hash] Additional options for subclasses
34
+ def initialize(indent_size: 2, **options)
35
+ @lines = []
36
+ @indent_level = 0
37
+ @indent_size = indent_size
38
+ initialize_subclass_state(**options)
39
+ end
40
+
41
+ # Hook for subclasses to initialize their own state
42
+ # @param options [Hash] Additional options
43
+ def initialize_subclass_state(**options)
44
+ # Override in subclasses if needed
45
+ end
46
+
47
+ # Emit a blank line
48
+ def emit_blank_line
49
+ @lines << ""
50
+ end
51
+
52
+ # Emit leading comments from CommentTracker
53
+ #
54
+ # @param comments [Array<Hash>] Comment hashes with :text, :indent, etc.
55
+ def emit_leading_comments(comments)
56
+ comments.each do |comment|
57
+ emit_tracked_comment(comment)
58
+ end
59
+ end
60
+
61
+ # Emit a comment from CommentTracker hash
62
+ # Subclasses should override this to handle format-specific comment syntax
63
+ #
64
+ # @param comment [Hash] Comment hash with :text, :indent, :block, etc.
65
+ def emit_tracked_comment(comment)
66
+ raise NotImplementedError, "Subclasses must implement emit_tracked_comment"
67
+ end
68
+
69
+ # Emit raw lines as-is (for preserving exact formatting)
70
+ #
71
+ # @param raw_lines [Array<String>] Lines to emit without modification
72
+ def emit_raw_lines(raw_lines)
73
+ raw_lines.each { |line| @lines << line.chomp }
74
+ end
75
+
76
+ # Get the output as a single string
77
+ # Subclasses may override to customize output format (e.g., to_json, to_yaml)
78
+ #
79
+ # @return [String]
80
+ def to_s
81
+ content = @lines.join("\n")
82
+ content += "\n" unless content.empty? || content.end_with?("\n")
83
+ content
84
+ end
85
+
86
+ # Clear the emitter state
87
+ def clear
88
+ @lines = []
89
+ @indent_level = 0
90
+ clear_subclass_state
91
+ end
92
+
93
+ # Hook for subclasses to clear their own state
94
+ def clear_subclass_state
95
+ # Override in subclasses if needed
96
+ end
97
+
98
+ # Increase indentation level
99
+ def indent
100
+ @indent_level += 1
101
+ end
102
+
103
+ # Decrease indentation level
104
+ def dedent
105
+ @indent_level -= 1 if @indent_level > 0
106
+ end
107
+
108
+ protected
109
+
110
+ # Get the current indentation string
111
+ # @return [String]
112
+ def current_indent
113
+ " " * (@indent_level * @indent_size)
114
+ end
115
+
116
+ # Add a line with current indentation
117
+ # @param content [String] Line content
118
+ def add_indented_line(content)
119
+ @lines << "#{current_indent}#{content}"
120
+ end
121
+ end
122
+ end
123
+ end
@@ -354,6 +354,15 @@ module Ast
354
354
  true
355
355
  end
356
356
 
357
+ # Node type for merge classification
358
+ # @return [Symbol] :freeze_block
359
+ def merge_type
360
+ :freeze_block
361
+ end
362
+
363
+ # Alias for compatibility
364
+ alias_method :type, :merge_type
365
+
357
366
  # Returns a stable signature for this freeze block.
358
367
  # Override in subclasses for file-type-specific normalization.
359
368
  # @return [Array] Signature array
@@ -13,6 +13,27 @@ module Ast
13
13
  # The `merge_type` attribute can then be used by other merge tools like
14
14
  # `signature_generator`, `match_refiner`, and per-node-type `preference` settings.
15
15
  #
16
+ # ## Important: Two Uses of merge_type
17
+ #
18
+ # The `merge_type` method serves two complementary purposes in the codebase:
19
+ #
20
+ # ### 1. NodeTyping-specific (gated by typed_node?)
21
+ # Wrapped nodes (Wrapper/FrozenWrapper) with custom type tagging for:
22
+ # - Per-node-type preferences (e.g., `:lint_gem` → `:template`)
23
+ # - Match refinement based on custom categories
24
+ # - Only applies when `typed_node?` returns true
25
+ # - Accessed via `NodeTyping.merge_type_for(node)`
26
+ #
27
+ # ### 2. General node classification (any node)
28
+ # Any node can implement `merge_type` for category identification:
29
+ # - FreezeNodeBase has `merge_type` → `:freeze_block`
30
+ # - GapLineNode has `merge_type` → `:gap_line`
31
+ # - Used by systems like MarkdownStructure for structural spacing rules
32
+ # - These nodes are NOT "typed nodes" (typed_node? returns false)
33
+ #
34
+ # The key distinction: **typed_node? is the gate** for NodeTyping wrapper
35
+ # semantics. A node can have `merge_type` without being a NodeTyping wrapper.
36
+ #
16
37
  # @example Basic node typing for different gem types
17
38
  # node_typing = {
18
39
  # CallNode: ->(node) {
@@ -5,7 +5,7 @@ module Ast
5
5
  # Version information for Ast::Merge
6
6
  module Version
7
7
  # Current version of the ast-merge gem
8
- VERSION = "3.0.0"
8
+ VERSION = "3.1.0"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data/lib/ast/merge.rb CHANGED
@@ -142,6 +142,7 @@ module Ast
142
142
  autoload :ConflictResolverBase, "ast/merge/conflict_resolver_base"
143
143
  autoload :ContentMatchRefiner, "ast/merge/content_match_refiner"
144
144
  autoload :DebugLogger, "ast/merge/debug_logger"
145
+ autoload :EmitterBase, "ast/merge/emitter_base"
145
146
  autoload :FileAnalyzable, "ast/merge/file_analyzable"
146
147
  autoload :Freezable, "ast/merge/freezable"
147
148
  autoload :FreezeNodeBase, "ast/merge/freeze_node_base"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ast-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -63,20 +63,20 @@ dependencies:
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '3.2'
66
+ version: '4.0'
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 3.2.5
69
+ version: 4.0.0
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: '3.2'
76
+ version: '4.0'
77
77
  - - ">="
78
78
  - !ruby/object:Gem::Version
79
- version: 3.2.5
79
+ version: 4.0.0
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: kettle-dev
82
82
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +309,7 @@ files:
309
309
  - lib/ast/merge/detector/mergeable.rb
310
310
  - lib/ast/merge/detector/toml_frontmatter.rb
311
311
  - lib/ast/merge/detector/yaml_frontmatter.rb
312
+ - lib/ast/merge/emitter_base.rb
312
313
  - lib/ast/merge/file_analyzable.rb
313
314
  - lib/ast/merge/freezable.rb
314
315
  - lib/ast/merge/freeze_node_base.rb
@@ -356,10 +357,10 @@ licenses:
356
357
  - MIT
357
358
  metadata:
358
359
  homepage_uri: https://ast-merge.galtzo.com/
359
- source_code_uri: https://github.com/kettle-rb/ast-merge/tree/v3.0.0
360
- changelog_uri: https://github.com/kettle-rb/ast-merge/blob/v3.0.0/CHANGELOG.md
360
+ source_code_uri: https://github.com/kettle-rb/ast-merge/tree/v3.1.0
361
+ changelog_uri: https://github.com/kettle-rb/ast-merge/blob/v3.1.0/CHANGELOG.md
361
362
  bug_tracker_uri: https://github.com/kettle-rb/ast-merge/issues
362
- documentation_uri: https://www.rubydoc.info/gems/ast-merge/3.0.0
363
+ documentation_uri: https://www.rubydoc.info/gems/ast-merge/3.1.0
363
364
  funding_uri: https://github.com/sponsors/pboling
364
365
  wiki_uri: https://github.com/kettle-rb/ast-merge/wiki
365
366
  news_uri: https://www.railsbling.com/tags/ast-merge
metadata.gz.sig CHANGED
Binary file