go-merge 7.0.0 → 7.1.3

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: '05906de20bc8bf7f1421bca4a76a0b70769bf77c39a1c5a95c529afaba978a62'
4
- data.tar.gz: b5988a169b45234e975361f26dbadd6acf887e8eb10dddbb2c6ee067a03e7cb4
3
+ metadata.gz: fc2818e672c1921f963df9cb173320cfe7a180ecd33a6c0a3b4d855fa76044a8
4
+ data.tar.gz: 239be77b2d5ff59d3d00d5e729f55361f13aa5c7e7d4cb0c9ff5c6c0efbeaa48
5
5
  SHA512:
6
- metadata.gz: 11df7df7c5ebc207c4908fa2341213de80cb7759f07a53d07ba05358b5e1f9aa5e06b9900887d7f838de3cb40c2d5ff04df5cdadae3f91279ca898fc1e9fb6fe
7
- data.tar.gz: 0fc22e8f3580fa233e037484812218031d0e4944984fa18b9d3e8fcac66cd47389bcf0c2f0fe674708f431a088476e4e7f1dd31d761dee0e3b0b4bc5adab1318
6
+ metadata.gz: 933ef214c37510ad01f07b2a305b06a23d7d0b8061e8d7ebb656eab06415eefe08064a5ce8d9257f72540caa3eceec8c81a052a871989eb6779dc2fb671650b9
7
+ data.tar.gz: add66ed0b4da849c4723780e316a256bc9cfcc7a9ac5bcd965ffc7f0b71f1f8cacd34a3951bdab12b4ce63d4571dc6803c1554badc03c479f88e64f05f830f04
checksums.yaml.gz.sig CHANGED
Binary file
data/LICENSE.md ADDED
@@ -0,0 +1,13 @@
1
+ # License
2
+
3
+ This project is made available under the following licenses.
4
+ Choose the option that best fits your use case:
5
+
6
+ - [AGPL-3.0-only](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md)
7
+ - [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md)
8
+
9
+ If none of the above licenses fit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
10
+
11
+ ## Copyright Notice
12
+
13
+ - Required Notice: Copyright (c) 2026 Peter H. Boling
data/README.md ADDED
@@ -0,0 +1,287 @@
1
+ <a href="https://github.com/structuredmerge"><img alt="structuredmerge Logo by GitHub" src="https://github.com/structuredmerge.png?size=192" width="14%" align="right"/></a>
2
+
3
+ # ☯️ Go::Merge
4
+
5
+ [![Version][👽versioni]][👽version] [![Ruby Users Forum][✉️ruby-forum-top-img]][✉️ruby-forum] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Total downloads][👽dl-ranki]][👽dl-rank] [![CI Current][🚎11-c-wfi]][🚎11-c-wf]
6
+
7
+ `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know on Discord][✉️discord-invite] or [RubyForum][✉️ruby-forum], as I may have missed the notification.
8
+
9
+ ---
10
+
11
+ `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.
12
+
13
+ [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
14
+
15
+ <details markdown="1">
16
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
17
+
18
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
19
+
20
+ </details>
21
+
22
+ ## 🌻 Synopsis <a href="https://discord.gg/3qme4XHNKN"><img alt="Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/galtzo-floss/avatar-128px.svg" width="8%" align="right"/></a> <a href="https://ruby-toolbox.com"><img alt="ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5" src="https://logos.galtzo.com/assets/images/ruby-lang/avatar-128px.svg" width="8%" align="right"/></a>
23
+
24
+ `Go::Merge` merges Go source files by imports and top-level declarations. It uses the shared tree-sitter language-pack backend to analyze declarations and preserves destination declarations while appending template-only declarations in source order.
25
+
26
+ ### Key Features
27
+
28
+ - Go dialect feature profile and backend capability reporting.
29
+ - Import block analysis and declaration ownership.
30
+ - Path-based declaration matching.
31
+ - Destination parse diagnostics with StructuredMerge result shape.
32
+ - Module-level APIs for fixture runners and Git integrations.
33
+
34
+ ## 💡 Info you can shake a stick at
35
+
36
+ | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] |
37
+ |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
38
+ | Works with MRI Ruby 4 | [![Ruby current Compat][💎ruby-c-i]][🚎11-c-wf]|
39
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Get help from RubyForum][✉️ruby-forum-img]][✉️ruby-forum] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
40
+ | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on GitHub.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] |
41
+ | 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] |
42
+ | Compliance | [![License: AGPL-3.0-only OR PolyForm-Small-Business-1.0.0][📄license-img]][📄license] [![Apache license compatibility: Category X][📄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] |
43
+ | 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] |
44
+ | 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] |
45
+ | `...` 💖 | [![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] |
46
+
47
+ ### Compatibility
48
+
49
+ Compatible with MRI Ruby 4.0.0+, JRuby, and TruffleRuby.
50
+ CI workflows and Appraisals are generated for MRI Ruby 4.0.0+.
51
+ This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
52
+ may be higher than the gem's runtime compatibility floor when legacy Rubies are
53
+ not practical for the current toolchain.
54
+
55
+ <a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
56
+
57
+ The _amazing_ test matrix is powered by the kettle-dev stack.
58
+
59
+ <details markdown="1">
60
+ <summary>How kettle-dev manages complexity in tests</summary>
61
+
62
+ | Gem | Source | Role | Total downloads |
63
+ |-----|--------|------|---------------------|
64
+ | [appraisal2](https://clickgems.clickhouse.com/dashboard/appraisal2) | [GitHub](https://github.com/appraisal-rb/appraisal2) | multi-dependency Appraisal matrix generation | [![Total downloads for appraisal2](https://img.shields.io/gem/dt/appraisal2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2) |
65
+ | [appraisal2-rubocop](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) | [GitHub](https://github.com/appraisal-rb/appraisal2-rubocop) | RuboCop Appraisal generator integration | [![Total downloads for appraisal2-rubocop](https://img.shields.io/gem/dt/appraisal2-rubocop.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/appraisal2-rubocop) |
66
+ | [kettle-dev](https://clickgems.clickhouse.com/dashboard/kettle-dev) | [GitHub](https://github.com/kettle-dev/kettle-dev) | development, release, and CI workflow tooling | [![Total downloads for kettle-dev](https://img.shields.io/gem/dt/kettle-dev.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-dev) |
67
+ | [kettle-jem](https://clickgems.clickhouse.com/dashboard/kettle-jem) | [GitHub](https://github.com/kettle-dev/kettle-jem) | Appraisals & CI workflow templates | [![Total downloads for kettle-jem](https://img.shields.io/gem/dt/kettle-jem.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-jem) |
68
+ | [kettle-soup-cover](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) | [GitHub](https://github.com/kettle-dev/kettle-soup-cover) | SimpleCov coverage policy and reporting | [![Total downloads for kettle-soup-cover](https://img.shields.io/gem/dt/kettle-soup-cover.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-soup-cover) |
69
+ | [kettle-test](https://clickgems.clickhouse.com/dashboard/kettle-test) | [GitHub](https://github.com/kettle-dev/kettle-test) | standard test runner and coverage harness | [![Total downloads for kettle-test](https://img.shields.io/gem/dt/kettle-test.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/kettle-test) |
70
+ | [rubocop-lts](https://clickgems.clickhouse.com/dashboard/rubocop-lts) | [GitHub](https://github.com/rubocop-lts/rubocop-lts) | Ruby-version-aware linting | [![Total downloads for rubocop-lts](https://img.shields.io/gem/dt/rubocop-lts.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/rubocop-lts) |
71
+ | [turbo_tests2](https://clickgems.clickhouse.com/dashboard/turbo_tests2) | [GitHub](https://github.com/galtzo-floss/turbo_tests2) | parallel test execution | [![Total downloads for turbo_tests2](https://img.shields.io/gem/dt/turbo_tests2.svg?style=flat-square)](https://clickgems.clickhouse.com/dashboard/turbo_tests2) |
72
+
73
+ </details>
74
+
75
+ ## ✨ Installation
76
+
77
+ Install the gem and add to the application's Gemfile by executing:
78
+
79
+ ```console
80
+ bundle add go-merge
81
+ ```
82
+
83
+ If bundler is not being used to manage dependencies, install the gem by executing:
84
+
85
+ ```console
86
+ gem install go-merge
87
+ ```
88
+
89
+ ## ⚙️ Configuration
90
+
91
+ ```ruby
92
+ profile = Go::Merge.go_backend_feature_profile
93
+ context = Go::Merge.go_plan_context
94
+ backends = Go::Merge.available_go_backends
95
+ ```
96
+
97
+ The Ruby implementation uses the shared language-pack backend. Unsupported dialects or backends return structured diagnostics.
98
+
99
+ ## 🔧 Basic Usage
100
+
101
+ ```ruby
102
+ require "go/merge"
103
+
104
+ result = Go::Merge.merge_go(
105
+ File.read("template.go"),
106
+ File.read("main.go"),
107
+ "go",
108
+ )
109
+
110
+ abort result.fetch(:diagnostics).inspect unless result.fetch(:ok)
111
+ File.write("main.go", result.fetch(:output))
112
+ ```
113
+
114
+ Most module-level merge methods return a Hash with `:ok`, `:diagnostics`, `:output`, and `:policies`. Check `:ok` before writing the result; diagnostics are structured for CI output and fixture conformance reports.
115
+
116
+ ## 🔐 Security
117
+
118
+ See [SECURITY.md][🔐security].
119
+
120
+ ## 🤝 Contributing
121
+
122
+ If you need some ideas of where to help, you could work on adding more code coverage,
123
+ check [issues][🤝gh-issues] or [PRs][🤝gh-pulls], or use the gem and think about how it could be better.
124
+
125
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
126
+
127
+ See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
128
+
129
+ ## 📌 Versioning
130
+
131
+ This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
132
+ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
133
+
134
+ For example:
135
+
136
+ ```ruby
137
+ spec.add_dependency("go-merge", "~> 7.0")
138
+ ```
139
+
140
+ <details markdown="1">
141
+ <summary>📌 Is "Platform Support" part of the public API? More details inside.</summary>
142
+
143
+ Dropping support for a platform can be a breaking change for affected users.
144
+ If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.
145
+
146
+ To get a better understanding of how SemVer is intended to work over a project's lifetime,
147
+ read this article from the creator of SemVer:
148
+
149
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
150
+
151
+ </details>
152
+
153
+ See [CHANGELOG.md][📌changelog] for a list of releases.
154
+
155
+ ## 📄 License
156
+
157
+ The gem is available under the following licenses: [AGPL-3.0-only](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/AGPL-3.0-only.md), [PolyForm-Small-Business-1.0.0](https://github.com/structuredmerge/structuredmerge-ruby/blob/main/PolyForm-Small-Business-1.0.0.md).
158
+ See [LICENSE.md][📄license] for details.
159
+
160
+ If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
161
+
162
+ [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
163
+ [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
164
+ [⛳liberapay]: https://liberapay.com/pboling/donate
165
+ [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
166
+ [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
167
+ [🖇sponsor]: https://github.com/sponsors/pboling
168
+ [🖇kofi-img]: https://img.shields.io/badge/ko--fi-%E2%9C%93-a51611.svg?style=flat
169
+ [🖇kofi]: https://ko-fi.com/pboling
170
+ [🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-%E2%9C%93-a51611.svg?style=flat
171
+ [🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
172
+ [🖇buyme]: https://www.buymeacoffee.com/pboling
173
+ [🖇paypal-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=flat&logo=paypal
174
+ [🖇paypal-bottom-img]: https://img.shields.io/badge/donate-paypal-a51611.svg?style=for-the-badge&logo=paypal&color=0A0A0A
175
+ [🖇paypal]: https://www.paypal.com/paypalme/peterboling
176
+ [🖇floss-funding.dev]: https://floss-funding.dev
177
+ [🖇floss-funding-gem]: https://github.com/galtzo-floss/floss_funding
178
+ [✉️discord-invite]: https://discord.gg/3qme4XHNKN
179
+ [✉️discord-invite-img-ftb]: https://img.shields.io/discord/1373797679469170758?style=for-the-badge&logo=discord
180
+ [✉️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
181
+ [✉️ruby-friends]: https://app.daily.dev/squads/rubyfriends
182
+ [✉️ruby-forum-top-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=flat&logo=discourse&label=Ruby%20Users%20Forum
183
+ [✉️ruby-forum-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=for-the-badge&logo=discourse&label=Ruby%20Users%20Forum
184
+ [✉️ruby-forum]: https://www.rubyforum.org/tag/structuredmerge
185
+ [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
186
+ [⛳️gem-namespace]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/go-merge
187
+ [⛳️namespace-img]: https://img.shields.io/badge/namespace-Go::Merge-3C2D2D.svg?style=square&logo=ruby&logoColor=white
188
+ [⛳️gem-name]: https://clickgems.clickhouse.com/dashboard/go-merge
189
+ [⛳️name-img]: https://img.shields.io/badge/name-go--merge-3C2D2D.svg?style=square&logo=rubygems&logoColor=red
190
+ [⛳️tag-img]: https://img.shields.io/github/tag/structuredmerge/structuredmerge-ruby.svg
191
+ [⛳️tag]: https://github.com/structuredmerge/structuredmerge-ruby/releases
192
+ [🚂maint-blog]: http://www.railsbling.com/tags/go-merge
193
+ [🚂maint-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
194
+ [🚂maint-contact]: http://www.railsbling.com/contact
195
+ [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
196
+ [💖🖇linkedin]: http://www.linkedin.com/in/peterboling
197
+ [💖🖇linkedin-img]: https://img.shields.io/badge/LinkedIn-Profile-0B66C2?style=flat&logo=newjapanprowrestling
198
+ [💖✌️wellfound]: https://wellfound.com/u/peter-boling
199
+ [💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
200
+ [💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
201
+ [💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
202
+ [💖🐘ruby-mast]: https://ruby.social/@galtzo
203
+ [💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https://ruby.social&style=flat&logo=mastodon&label=Ruby%20@galtzo
204
+ [💖🦋bluesky]: https://bsky.app/profile/galtzo.com
205
+ [💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
206
+ [💖🌳linktree]: https://linktr.ee/galtzo
207
+ [💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
208
+ [💖💁🏼‍♂️devto]: https://dev.to/galtzo
209
+ [💖💁🏼‍♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
210
+ [💖💁🏼‍♂️aboutme]: https://about.me/peter.boling
211
+ [💖💁🏼‍♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
212
+ [💖🧊berg]: https://codeberg.org/pboling
213
+ [💖🐙hub]: https://github.org/pboling
214
+ [💖🛖hut]: https://sr.ht/~galtzo/
215
+ [💖🧪lab]: https://gitlab.com/pboling
216
+ [👨🏼‍🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
217
+ [👨🏼‍🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
218
+ [👨🏼‍🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
219
+ [👨🏼‍🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
220
+ [🏙️entsup-tidelift]: https://tidelift.com/subscription/pkg/rubygems-go-merge?utm_source=rubygems-go-merge&utm_medium=referral&utm_campaign=readme
221
+ [🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
222
+ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
223
+ [💁🏼‍♂️peterboling]: http://www.peterboling.com
224
+ [🚂railsbling]: http://www.railsbling.com
225
+ [📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
226
+ [📜src-gl]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/gems/go-merge
227
+ [📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
228
+ [📜src-cb]: https://codeberg.org/structuredmerge/structuredmerge-ruby/src/branch/main/gems/go-merge
229
+ [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=GitHub&logoColor=green
230
+ [📜src-gh]: https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/go-merge
231
+ [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
232
+ [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
233
+ [📜gl-wiki]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/wikis/home
234
+ [📜gh-wiki]: https://github.com/structuredmerge/structuredmerge-ruby/wiki
235
+ [📜gl-wiki-img]: https://img.shields.io/badge/wiki-gitlab-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white
236
+ [📜gh-wiki-img]: https://img.shields.io/badge/wiki-github-943CD2.svg?style=for-the-badge&logo=github&logoColor=white
237
+ [👽dl-rank]: https://clickgems.clickhouse.com/dashboard/go-merge
238
+ [👽dl-ranki]: https://img.shields.io/gem/dt/go-merge.svg
239
+ [👽version]: https://clickgems.clickhouse.com/dashboard/go-merge
240
+ [👽versioni]: https://img.shields.io/gem/v/go-merge.svg
241
+ [🚎11-c-wf]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml
242
+ [🚎11-c-wfi]: https://github.com/structuredmerge/structuredmerge-ruby/actions/workflows/current.yml/badge.svg
243
+ [💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
244
+ [🤝gh-issues]: https://github.com/structuredmerge/structuredmerge-ruby/issues
245
+ [🤝gh-pulls]: https://github.com/structuredmerge/structuredmerge-ruby/pulls
246
+ [🤝gl-issues]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/issues
247
+ [🤝gl-pulls]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/merge_requests
248
+ [🤝cb-issues]: https://codeberg.org/structuredmerge/structuredmerge-ruby/issues
249
+ [🤝cb-pulls]: https://codeberg.org/structuredmerge/structuredmerge-ruby/pulls
250
+ [🤝cb-donate]: https://donate.codeberg.org/
251
+ [🤝contributing]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CONTRIBUTING.md
252
+ [🖐contrib-rocks]: https://contrib.rocks
253
+ [🖐contributors]: https://github.com/structuredmerge/structuredmerge-ruby/graphs/contributors
254
+ [🖐contributors-img]: https://contrib.rocks/image?repo=structuredmerge/structuredmerge-ruby
255
+ [🪇conduct]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CODE_OF_CONDUCT.md
256
+ [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
257
+ [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
258
+ [📌semver]: https://semver.org/spec/v2.0.0.html
259
+ [📌semver-img]: https://img.shields.io/badge/semver-2.0.0-259D6C.svg?style=flat
260
+ [📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
261
+ [📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
262
+ [📌changelog]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/CHANGELOG.md
263
+ [📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
264
+ [📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-34495e.svg?style=flat
265
+ [📌gitmoji]: https://gitmoji.dev
266
+ [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
267
+ [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
268
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.128-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
269
+ [🔐security]: https://github.com/structuredmerge/structuredmerge-ruby/blob/main/SECURITY.md
270
+ [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
271
+ [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
272
+ [📄license]: LICENSE.md
273
+ [📄license-ref]: LICENSE.md
274
+ [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only_OR_PolyForm--Small--Business--1.0.0-259D6C.svg
275
+ [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
276
+ [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
277
+ [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
278
+ [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
279
+ [🚎yard-current]: http://rubydoc.info/gems/go-merge
280
+ [🚎yard-head]: https://go-merge.galtzo.com
281
+ [💎stone_checksums]: https://github.com/galtzo-floss/stone_checksums
282
+ [💎SHA_checksums]: https://gitlab.com/structuredmerge/structuredmerge-ruby/-/tree/main/checksums
283
+ [💎rlts]: https://github.com/rubocop-lts/rubocop-lts
284
+ [💎rlts-img]: https://img.shields.io/badge/code_style_&_linting-rubocop--lts-34495e.svg?plastic&logo=ruby&logoColor=white
285
+ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
286
+ [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
287
+ [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Go
4
+ module Merge
5
+ # Native TreeHaver analysis of safely attributable top-level Go source.
6
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity -- one AST pass establishes ordered ownership and comment attachment
7
+ class FileAnalysis
8
+ attr_reader :source, :root_node, :declarations, :errors, :backend
9
+
10
+ def initialize(source, require_package: true)
11
+ @source = source
12
+ @require_package = require_package
13
+ @backend = TREE_SITTER_BACKEND.id.to_sym
14
+ @errors = []
15
+ parse!
16
+ rescue StandardError => e
17
+ @root_node = nil
18
+ @declarations = [].freeze
19
+ @errors = [e].freeze
20
+ end
21
+
22
+ private
23
+
24
+ def parse!
25
+ parser = TreeHaver.parser_for(:go, backend_type: :tree_sitter)
26
+ @root_node = parser.parse(source).root_node
27
+ raise TreeHaver::NotAvailable, 'Go parse returned no root node' unless root_node
28
+ raise TreeHaver::NotAvailable, 'Go parse contains syntax errors' if root_node.has_error?
29
+
30
+ wrappers = []
31
+ pending_comments = []
32
+ root_node.children.each do |node|
33
+ if node.type == 'comment'
34
+ if trailing_comment?(wrappers.last, node)
35
+ wrappers.last.attach_trailing_comment!(node)
36
+ else
37
+ pending_comments << node
38
+ end
39
+ next
40
+ end
41
+ unless NodeWrapper::DECLARATION_TYPES.include?(node.type)
42
+ pending_comments.clear
43
+ next
44
+ end
45
+
46
+ comments = attached_comments(pending_comments, node)
47
+ wrappers << NodeWrapper.new(node, source: source, leading_comments: comments)
48
+ pending_comments.clear
49
+ end
50
+ validate_package!(wrappers) if @require_package
51
+ @declarations = wrappers.freeze
52
+ end
53
+
54
+ def trailing_comment?(owner, comment)
55
+ return false unless owner
56
+
57
+ gap = source.byteslice(owner.end_byte...comment.start_byte).to_s
58
+ whitespace_only?(gap) && gap.count("\n").zero?
59
+ end
60
+
61
+ def attached_comments(comments, owner)
62
+ return [] if comments.empty?
63
+
64
+ attached = []
65
+ cursor = owner.start_byte
66
+ comments.reverse_each do |comment|
67
+ gap = source.byteslice(comment.end_byte...cursor).to_s
68
+ break unless whitespace_only?(gap) && gap.count("\n") <= 1
69
+
70
+ attached.unshift(comment)
71
+ cursor = comment.start_byte
72
+ end
73
+ attached.freeze
74
+ end
75
+
76
+ def validate_package!(wrappers)
77
+ packages = wrappers.select { |wrapper| wrapper.node.type == 'package_clause' }
78
+ raise TreeHaver::NotAvailable, 'Go source must contain exactly one package clause' unless packages.length == 1
79
+ return if wrappers.first.equal?(packages.first)
80
+
81
+ raise TreeHaver::NotAvailable, 'Go package clause must be the first owned top-level construct'
82
+ end
83
+
84
+ def whitespace_only?(value)
85
+ value.each_byte.all? { |byte| [9, 10, 13, 32].include?(byte) }
86
+ end
87
+ end
88
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
89
+ end
90
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Go
4
+ module Merge
5
+ # Structural identity and source-range adapter for a top-level Go AST node.
6
+ # rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength -- Go declaration forms share one structural identity boundary
7
+ class NodeWrapper
8
+ DECLARATION_TYPES = %w[
9
+ const_declaration
10
+ function_declaration
11
+ import_declaration
12
+ method_declaration
13
+ package_clause
14
+ type_declaration
15
+ var_declaration
16
+ ].freeze
17
+ GROUP_SPEC_TYPES = %w[const_spec import_spec type_spec var_spec].freeze
18
+
19
+ attr_reader :node, :source, :leading_comments, :trailing_comments
20
+
21
+ def initialize(node, source:, leading_comments: [])
22
+ @node = node
23
+ @source = source
24
+ @leading_comments = leading_comments.freeze
25
+ @trailing_comments = []
26
+ end
27
+
28
+ def signature
29
+ case node.type
30
+ when 'package_clause'
31
+ [:package, required_descendant_text(node, 'package_identifier')]
32
+ when 'import_declaration'
33
+ import_signature
34
+ when 'function_declaration'
35
+ [:function, required_direct_child_text(node, 'identifier')]
36
+ when 'method_declaration'
37
+ [:method, receiver_type_name, required_direct_child_text(node, 'field_identifier')]
38
+ when 'type_declaration'
39
+ declaration_signature(:type, 'type_spec', 'type_identifier')
40
+ when 'const_declaration'
41
+ declaration_signature(:const, 'const_spec', 'identifier')
42
+ when 'var_declaration'
43
+ declaration_signature(:var, 'var_spec', 'identifier')
44
+ else
45
+ raise ArgumentError, "Unsupported top-level Go node #{node.type.inspect}"
46
+ end.freeze
47
+ end
48
+
49
+ def grouped?
50
+ case node.type
51
+ when 'import_declaration'
52
+ !find_descendant(node, ['import_spec_list']).nil?
53
+ when 'type_declaration', 'const_declaration'
54
+ node.children.any? { |child| child.type == '(' }
55
+ when 'var_declaration'
56
+ !find_descendant(node, ['var_spec_list']).nil?
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ def start_byte
63
+ leading_comments.first&.start_byte || node.start_byte
64
+ end
65
+
66
+ def attach_trailing_comment!(comment)
67
+ trailing_comments << comment
68
+ end
69
+
70
+ def end_byte = trailing_comments.last&.end_byte || node.end_byte
71
+ def start_line = line_for_byte(start_byte)
72
+ def end_line = line_for_byte(end_byte.zero? ? 0 : end_byte - 1)
73
+ def source_text = source.byteslice(start_byte...end_byte).to_s
74
+
75
+ def semantic_tree
76
+ semantic_node(node)
77
+ end
78
+
79
+ private
80
+
81
+ def import_signature
82
+ specs = descendants(node, 'import_spec')
83
+ values = specs.map do |spec|
84
+ literal = required_descendant(spec, 'interpreted_string_literal', 'raw_string_literal')
85
+ alias_node = spec.children.find do |child|
86
+ %w[package_identifier dot blank_identifier].include?(child.type)
87
+ end
88
+ [alias_node ? text(alias_node) : nil, import_path(literal)]
89
+ end
90
+ return [:import_group, values.sort_by { |value| value.map(&:to_s) }.freeze] if grouped?
91
+
92
+ [:import, values.fetch(0)]
93
+ end
94
+
95
+ def import_path(literal)
96
+ content = literal.children.find do |child|
97
+ %w[interpreted_string_literal_content raw_string_literal_content].include?(child.type)
98
+ end
99
+ return text(content) if content
100
+
101
+ literal_text = text(literal)
102
+ literal_text.byteslice(1...-1).to_s
103
+ end
104
+
105
+ def receiver_type_name
106
+ receiver = node.children.find { |child| child.type == 'parameter_list' }
107
+ parameter = required_descendant(receiver, 'parameter_declaration')
108
+ required_descendant_text(parameter, 'type_identifier')
109
+ end
110
+
111
+ def declaration_signature(kind, spec_type, identifier_type)
112
+ specs = descendants(node, spec_type)
113
+ member_names = specs.map do |spec|
114
+ spec.children.select { |child| child.type == identifier_type }.map { |child| text(child) }
115
+ end
116
+ raise ArgumentError, "#{node.type} has no declared name" if member_names.flatten.empty?
117
+ return [:"#{kind}_group", member_names.map(&:freeze).freeze] if grouped?
118
+
119
+ names = member_names.flatten
120
+ [kind, names.length == 1 ? names.first : names.freeze]
121
+ end
122
+
123
+ def required_direct_child_text(parent, type)
124
+ child = parent.children.find { |candidate| candidate.type == type }
125
+ raise ArgumentError, "#{parent.type} has no #{type}" unless child
126
+
127
+ text(child)
128
+ end
129
+
130
+ def required_descendant_text(parent, *types)
131
+ text(required_descendant(parent, *types))
132
+ end
133
+
134
+ def required_descendant(parent, *types)
135
+ found = find_descendant(parent, types)
136
+ raise ArgumentError, "#{parent.type} has no #{types.join(' or ')}" unless found
137
+
138
+ found
139
+ end
140
+
141
+ def find_descendant(parent, types)
142
+ return parent if types.include?(parent.type)
143
+
144
+ parent.children.each do |child|
145
+ found = find_descendant(child, types)
146
+ return found if found
147
+ end
148
+ nil
149
+ end
150
+
151
+ def descendants(parent, type, found = [])
152
+ found << parent if parent.type == type
153
+ parent.children.each { |child| descendants(child, type, found) }
154
+ found
155
+ end
156
+
157
+ def semantic_node(value)
158
+ children = value.children
159
+ return [value.type, text(value)] if children.empty?
160
+
161
+ [value.type, children.select(&:named?).map { |child| semantic_node(child) }]
162
+ end
163
+
164
+ def text(value)
165
+ source.byteslice(value.start_byte...value.end_byte).to_s
166
+ end
167
+
168
+ def line_for_byte(byte)
169
+ source.byteslice(0...byte).to_s.count("\n") + 1
170
+ end
171
+ end
172
+ # rubocop:enable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength
173
+ end
174
+ end