tree_haver 5.0.0 → 5.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 +77 -2
- data/README.md +161 -166
- data/lib/tree_haver/backend_api.rb +12 -12
- data/lib/tree_haver/backend_registry.rb +230 -7
- data/lib/tree_haver/grammar_finder.rb +7 -6
- data/lib/tree_haver/parser.rb +5 -3
- data/lib/tree_haver/rspec/dependency_tags.rb +148 -87
- data/lib/tree_haver/rspec/testable_node.rb +217 -0
- data/lib/tree_haver/rspec.rb +11 -1
- data/lib/tree_haver/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +5 -4
- metadata.gz.sig +0 -0
data/README.md
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
[rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
|
|
32
32
|
[policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
|
|
33
33
|
|
|
34
|
-
[![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]]
|
|
34
|
+
[![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-rb Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-rb-i]][🖼️kettle-rb]
|
|
35
35
|
|
|
36
36
|
[🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
|
|
37
37
|
[🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
# 🌴 TreeHaver
|
|
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
|
|
|
@@ -50,7 +50,7 @@
|
|
|
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
|
|
|
53
|
-
[![OpenCollective Backers][🖇osc-backers-i]]
|
|
53
|
+
[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![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 on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
|
|
54
54
|
|
|
55
55
|
## 🌻 Synopsis
|
|
56
56
|
|
|
@@ -88,28 +88,28 @@ tree = parser.parse(source_code)
|
|
|
88
88
|
|
|
89
89
|
### Key Features
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
91
|
+
- **Universal Ruby Support**: Works on MRI Ruby, JRuby, and TruffleRuby
|
|
92
|
+
- **10 Parsing Backends** - Choose the right backend for your needs:
|
|
93
|
+
- **Tree-sitter Backends** (high-performance, incremental parsing):
|
|
94
|
+
- **MRI Backend**: Leverages [`ruby_tree_sitter`][ruby_tree_sitter] gem (C extension, fastest on MRI)
|
|
95
|
+
- **Rust Backend**: Uses [`tree_stump`][tree_stump] gem (Rust with precompiled binaries)
|
|
96
|
+
- **Note**: `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
97
|
+
- **FFI Backend**: Pure Ruby FFI bindings to `libtree-sitter` (JRuby only; TruffleRuby's FFI doesn't support tree-sitter's struct-by-value returns)
|
|
98
|
+
- **Java Backend**: Native Java integration for JRuby with [`java-tree-sitter`](https://github.com/tree-sitter/java-tree-sitter) / [`jtreesitter`][jtreesitter] grammar JARs
|
|
99
|
+
- **Language-Specific Backends** (native parser integration):
|
|
100
|
+
- **Prism Backend**: Ruby's official parser ([Prism][prism], stdlib in Ruby 3.4+)
|
|
101
|
+
- **Psych Backend**: Ruby's YAML parser ([Psych][psych], stdlib)
|
|
102
|
+
- **Commonmarker Backend**: Fast Markdown parser ([Commonmarker][commonmarker], comrak Rust)
|
|
103
|
+
- **Markly Backend**: GitHub Flavored Markdown ([Markly][markly], cmark-gfm C)
|
|
104
|
+
- **Pure Ruby Fallback**:
|
|
105
|
+
- **Citrus Backend**: Pure Ruby PEG parsing via [`citrus`][citrus] (no native dependencies)
|
|
106
|
+
- **Parslet Backend**: Pure Ruby PEG parsing via [`parslet`][parslet] (no native dependencies)
|
|
107
|
+
- **Automatic Backend Selection**: Intelligently selects the best backend for your Ruby implementation
|
|
108
|
+
- **Language Agnostic**: Parse any language - Ruby, Markdown, YAML, JSON, Bash, TOML, JavaScript, etc.
|
|
109
|
+
- **Grammar Discovery**: Built-in `GrammarFinder` utility for platform-aware grammar library discovery
|
|
110
|
+
- **Unified Position API**: Consistent `start_line`, `end_line`, `source_position` across all backends
|
|
111
|
+
- **Thread-Safe**: Built-in language registry with thread-safe caching
|
|
112
|
+
- **Minimal API Surface**: Simple, focused API that covers the most common use cases
|
|
113
113
|
|
|
114
114
|
### Backend Requirements
|
|
115
115
|
|
|
@@ -142,9 +142,9 @@ gem "ruby_tree_sitter", "~> 2.0"
|
|
|
142
142
|
|
|
143
143
|
The Rust backend uses [tree\_stump][tree_stump], which is a Rust native extension built with [magnus](https://github.com/matsadler/magnus) and [rb-sys](https://github.com/oxidize-rb/rb-sys). These libraries are only compatible with MRI Ruby's C API.
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
- **JRuby**: Cannot load native `.so` extensions (runs on JVM)
|
|
146
|
+
- **TruffleRuby**: magnus/rb-sys are incompatible with TruffleRuby's C API emulation
|
|
147
|
+
NOTE: `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
148
148
|
|
|
149
149
|
```ruby
|
|
150
150
|
# Add to your Gemfile for Rust backend (MRI only)
|
|
@@ -157,7 +157,7 @@ gem "tree_stump", github: "joker1007/tree_stump", branch: "main"
|
|
|
157
157
|
|
|
158
158
|
Requires the `ffi` gem and a system installation of `libtree-sitter`.
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
- **TruffleRuby**: TruffleRuby's FFI implementation doesn't support `STRUCT_BY_VALUE` return types, which tree-sitter's C API uses for functions like `ts_tree_root_node` and `ts_node_child`.
|
|
161
161
|
|
|
162
162
|
```ruby
|
|
163
163
|
# Add to your Gemfile for FFI backend (MRI and JRuby)
|
|
@@ -210,8 +210,8 @@ gem "parslet", "~> 2.0"
|
|
|
210
210
|
|
|
211
211
|
**Also requires**:
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
- Tree-sitter runtime library (`libtree-sitter.so`) version 0.26+ (must match jtreesitter version)
|
|
214
|
+
- Grammar `.so` files built against tree-sitter 0.26+ (or rebuilt with `tree-sitter generate`)
|
|
215
215
|
|
|
216
216
|
### Version Requirements for Tree-Sitter Backends
|
|
217
217
|
|
|
@@ -237,11 +237,11 @@ dnf install tree-sitter tree-sitter-devel
|
|
|
237
237
|
|
|
238
238
|
**The Java backend requires jtreesitter \>= 0.26.0.** This version introduced breaking API changes:
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
240
|
+
- `Parser.parse()` returns `Optional<Tree>` instead of `Tree`
|
|
241
|
+
- `Tree.getRootNode()` returns `Node` directly (not `Optional<Node>`)
|
|
242
|
+
- `Node.getChild()`, `getParent()`, `getNextSibling()`, `getPrevSibling()` return `Optional<Node>`
|
|
243
|
+
- `Language.load(name)` was removed; use `SymbolLookup` API instead
|
|
244
|
+
Older versions of jtreesitter are **NOT supported**.
|
|
245
245
|
|
|
246
246
|
```bash
|
|
247
247
|
# Download jtreesitter 0.26.0 from Maven Central
|
|
@@ -293,30 +293,27 @@ cc -shared -fPIC -o libtree-sitter-toml.so src/parser.c src/scanner.c -I src
|
|
|
293
293
|
|
|
294
294
|
TruffleRuby has **no working tree-sitter backend**:
|
|
295
295
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
296
|
+
- **FFI**: TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` return types (used by `ts_tree_root_node`, `ts_node_child`, etc.)
|
|
297
|
+
- **MRI/Rust**: C and Rust extensions require MRI's C API internals (`RBasic.flags`, `rb_gc_writebarrier`, etc.) that TruffleRuby doesn't expose
|
|
298
|
+
TruffleRuby users should use: **Prism** (Ruby), **Psych** (YAML), **Citrus/Parslet** (e.g., TOML via toml-rb/toml), or potentially **Commonmarker/Markly** (Markdown).
|
|
299
299
|
|
|
300
300
|
#### JRuby Limitations
|
|
301
301
|
|
|
302
302
|
JRuby runs on the JVM and **cannot load native `.so` extensions via Ruby's C API**:
|
|
303
303
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
[ruby\_tree\_sitter][ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
|
|
309
|
-
[tree\_stump][tree_stump]: https://github.com/joker1007/tree\_stump
|
|
310
|
-
\[jtreesitter\]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
|
|
304
|
+
- **MRI/Rust**: C and Rust extensions simply cannot be loaded
|
|
305
|
+
- **FFI**: Works\! JRuby has excellent FFI support
|
|
306
|
+
- **Java**: Works\! The Java backend uses jtreesitter (requires \>= 0.26.0)
|
|
307
|
+
JRuby users should use: **Java backend** (best performance, full API) or **FFI backend** for tree-sitter, plus **Prism**, **Psych**, **Citrus/Parslet** for other formats.
|
|
311
308
|
|
|
312
309
|
### Why TreeHaver?
|
|
313
310
|
|
|
314
311
|
tree-sitter is a powerful parser generator that creates incremental parsers for many programming languages. However, integrating it into Ruby applications can be challenging:
|
|
315
312
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
313
|
+
- MRI-based C extensions don't work on JRuby
|
|
314
|
+
- FFI-based solutions may not be optimal for MRI
|
|
315
|
+
- Managing different backends for different Ruby implementations is cumbersome
|
|
316
|
+
TreeHaver solves these problems by providing a unified API that automatically selects the appropriate backend for your Ruby implementation, allowing you to write code once and run it anywhere.
|
|
320
317
|
|
|
321
318
|
### The `*-merge` Gem Family
|
|
322
319
|
|
|
@@ -324,7 +321,7 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
|
|
|
324
321
|
|
|
325
322
|
| Gem | Version | CI | | Language<br>/ Format | Parser Backend(s) | Description |
|
|
326
323
|
|------------------------------------------|----------------------------------------------------------------|--------------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|-------------|
|
|
327
|
-
| [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] | [![Version][tree_haver-ci-i]][tree_haver-ci] | Multi | MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet
|
|
324
|
+
| [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] | [![Version][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) |
|
|
328
325
|
| [ast-merge][ast-merge] | [![Version][ast-merge-gem-i]][ast-merge-gem] | [![Version][ast-merge-ci-i]][ast-merge-ci] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
|
|
329
326
|
| [bash-merge][bash-merge] | [![Version][bash-merge-gem-i]][bash-merge-gem] | [![Version][bash-merge-ci-i]][bash-merge-ci] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
|
|
330
327
|
| [commonmarker-merge][commonmarker-merge] | [![Version][commonmarker-merge-gem-i]][commonmarker-merge-gem] | [![Version][commonmarker-merge-ci-i]][commonmarker-merge-ci] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
|
|
@@ -342,18 +339,18 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
|
|
|
342
339
|
|
|
343
340
|
tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
|
|
344
341
|
|
|
345
|
-
| Platform 👉️<br> TreeHaver Backend 👇️
|
|
346
|
-
|
|
347
|
-
| **MRI** ([ruby_tree_sitter][ruby_tree_sitter])
|
|
348
|
-
| **Rust** ([tree_stump][tree_stump])
|
|
349
|
-
| **FFI**
|
|
350
|
-
| **Java** ([jtreesitter][jtreesitter])
|
|
351
|
-
| **Prism**
|
|
352
|
-
| **Psych**
|
|
353
|
-
| **Citrus**
|
|
354
|
-
| **Parslet**
|
|
355
|
-
| **Commonmarker**
|
|
356
|
-
| **Markly**
|
|
342
|
+
| Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
|
|
343
|
+
|-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
|
|
344
|
+
| **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
|
|
345
|
+
| **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
|
|
346
|
+
| **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
|
|
347
|
+
| **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
|
|
348
|
+
| **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
|
|
349
|
+
| **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
|
|
350
|
+
| **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
|
|
351
|
+
| **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
|
|
352
|
+
| **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
|
|
353
|
+
| **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
|
|
357
354
|
|
|
358
355
|
**Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
|
|
359
356
|
|
|
@@ -447,6 +444,7 @@ tree_haver supports multiple parsing backends, but not all backends work on all
|
|
|
447
444
|
[kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
|
|
448
445
|
[prism]: https://github.com/ruby/prism
|
|
449
446
|
[psych]: https://github.com/ruby/psych
|
|
447
|
+
[ffi]: https://github.com/ffi/ffi
|
|
450
448
|
[ts-json]: https://github.com/tree-sitter/tree-sitter-json
|
|
451
449
|
[ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
|
|
452
450
|
[ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
|
|
@@ -461,30 +459,27 @@ tree_haver supports multiple parsing backends, but not all backends work on all
|
|
|
461
459
|
[ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
|
|
462
460
|
[tree_stump]: https://github.com/joker1007/tree_stump
|
|
463
461
|
[jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
|
|
462
|
+
[citrus]: https://github.com/mjackson/citrus
|
|
463
|
+
[parslet]: https://github.com/kschiess/parslet
|
|
464
464
|
|
|
465
465
|
### Comparison with Other Ruby AST / Parser Bindings
|
|
466
466
|
|
|
467
|
-
| Feature | [tree\_haver][📜src-gh] (this gem)
|
|
468
|
-
|
|
469
|
-
| **MRI Ruby** | ✅ Yes
|
|
470
|
-
| **JRuby** | ✅ Yes (FFI, Java, Citrus, or Parslet backend)
|
|
471
|
-
| **TruffleRuby** | ✅ Yes (FFI, Citrus, or Parslet)
|
|
472
|
-
| **Backend** | Multi (MRI C, Rust, FFI, Java, Citrus, Parslet) | C extension only
|
|
473
|
-
| **Incremental Parsing** | ✅ Via MRI C/Rust/Java backend
|
|
474
|
-
| **Query API** | ⚡ Via MRI/Rust/Java backend
|
|
475
|
-
| **Grammar Discovery** | ✅ Built-in `GrammarFinder`
|
|
476
|
-
| **Security Validations** | ✅ `PathValidator`
|
|
477
|
-
| **Language Registration** | ✅ Thread-safe registry
|
|
478
|
-
| **Native Performance** | ⚡ Backend-dependent
|
|
479
|
-
| **Precompiled Binaries** | ⚡ Via Rust backend
|
|
480
|
-
| **Zero Native Deps** | ⚡ Via Citrus/Parslet backend
|
|
481
|
-
| **Minimum Ruby** | 3.2+
|
|
467
|
+
| Feature | [tree\_haver][📜src-gh] (this gem) | [ruby\_tree\_sitter][ruby_tree_sitter] | [tree\_stump][tree_stump] | [citrus][citrus] | [parslet][parslet] |
|
|
468
|
+
|---------------------------|-------------------------------------------------|----------------------------------------|---------------------------|------------------|--------------------|
|
|
469
|
+
| **MRI Ruby** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
470
|
+
| **JRuby** | ✅ Yes (FFI, Java, Citrus, or Parslet backend) | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
|
|
471
|
+
| **TruffleRuby** | ✅ Yes (FFI, Citrus, or Parslet) | ❌ No | ❓ Unknown | ✅ Yes | ✅ Yes |
|
|
472
|
+
| **Backend** | Multi (MRI C, Rust, FFI, Java, Citrus, Parslet) | C extension only | Rust extension | Pure Ruby | Pure Ruby |
|
|
473
|
+
| **Incremental Parsing** | ✅ Via MRI C/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
|
|
474
|
+
| **Query API** | ⚡ Via MRI/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
|
|
475
|
+
| **Grammar Discovery** | ✅ Built-in `GrammarFinder` | ❌ Manual | ❌ Manual | ❌ Manual | ❌ Manual |
|
|
476
|
+
| **Security Validations** | ✅ `PathValidator` | ❌ No | ❌ No | ❌ No | ❌ No |
|
|
477
|
+
| **Language Registration** | ✅ Thread-safe registry | ❌ No | ❌ No | ❌ No | ❌ No |
|
|
478
|
+
| **Native Performance** | ⚡ Backend-dependent | ✅ Native C | ✅ Native Rust | ❌ Pure Ruby | ❌ Pure Ruby |
|
|
479
|
+
| **Precompiled Binaries** | ⚡ Via Rust backend | ✅ Yes | ✅ Yes | ✅ Pure Ruby | ✅ Pure Ruby |
|
|
480
|
+
| **Zero Native Deps** | ⚡ Via Citrus/Parslet backend | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
|
|
481
|
+
| **Minimum Ruby** | 3.2+ | 3.0+ | 3.1+ | 0+ | 0+ |
|
|
482
482
|
|
|
483
|
-
[ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
|
|
484
|
-
[tree_stump]: https://github.com/joker1007/tree_stump
|
|
485
|
-
[citrus]: https://github.com/mjackson/citrus
|
|
486
|
-
[parslet]: https://github.com/kschiess/parslet
|
|
487
|
-
[tree_haver]: https://github.com/kettle-rb/tree_haver
|
|
488
483
|
**Note:** Java backend works with grammar `.so` files built against tree-sitter 0.24+. The grammars must be rebuilt with `tree-sitter generate` if they were compiled against older tree-sitter versions. FFI is recommended for JRuby as it's easier to set up.
|
|
489
484
|
|
|
490
485
|
**Note:** TreeHaver can use `ruby_tree_sitter` (MRI) or `tree_stump` (MRI) as backends, or `java-tree-sitter` / `jtreesitter` \>= 0.26.0 ([docs](https://tree-sitter.github.io/java-tree-sitter/), [maven][jtreesitter], [source](https://github.com/tree-sitter/java-tree-sitter), JRuby), or FFI on any backend, giving you TreeHaver's unified API, grammar discovery, and security features, plus full access to incremental parsing when using those backends.
|
|
@@ -525,18 +520,18 @@ tree_haver supports multiple parsing backends, but not all backends work on all
|
|
|
525
520
|
|
|
526
521
|
## 💡 Info you can shake a stick at
|
|
527
522
|
|
|
528
|
-
| Tokens to Remember | [![Gem name][⛳️name-img]]
|
|
523
|
+
| Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
|
|
529
524
|
|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
530
|
-
| Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]]
|
|
531
|
-
| Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]]
|
|
532
|
-
| Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]]
|
|
533
|
-
| Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]]
|
|
534
|
-
| Source | [![Source on GitLab.com][📜src-gl-img]]
|
|
535
|
-
| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]]
|
|
536
|
-
| Compliance | [![License: MIT][📄license-img]]
|
|
537
|
-
| Style | [![Enforced Code Style Linter][💎rlts-img]]
|
|
538
|
-
| Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]]
|
|
539
|
-
| `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]]
|
|
525
|
+
| Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
|
|
526
|
+
| 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] |
|
|
527
|
+
| 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] |
|
|
528
|
+
| 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] |
|
|
529
|
+
| 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] |
|
|
530
|
+
| 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] |
|
|
531
|
+
| 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] |
|
|
532
|
+
| 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] |
|
|
533
|
+
| 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] |
|
|
534
|
+
| `...` 💖 | [![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] |
|
|
540
535
|
|
|
541
536
|
### Compatibility
|
|
542
537
|
|
|
@@ -556,13 +551,13 @@ Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRu
|
|
|
556
551
|
| 🧪 [kettle-rb/tree\_haver on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
|
|
557
552
|
| 🧊 [kettle-rb/tree\_haver on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
|
|
558
553
|
| 🐙 [kettle-rb/tree\_haver on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
|
|
559
|
-
| 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]]
|
|
554
|
+
| 🎮️ [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] |
|
|
560
555
|
|
|
561
556
|
</details>
|
|
562
557
|
|
|
563
558
|
[gh-discussions]: https://github.com/kettle-rb/tree_haver/discussions
|
|
564
559
|
|
|
565
|
-
### Enterprise Support []
|
|
560
|
+
### Enterprise Support [][🏙️entsup-tidelift]
|
|
566
561
|
|
|
567
562
|
Available as part of the Tidelift Subscription.
|
|
568
563
|
|
|
@@ -571,20 +566,20 @@ Available as part of the Tidelift Subscription.
|
|
|
571
566
|
|
|
572
567
|
The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
|
|
573
568
|
|
|
574
|
-
[![Get help from me on Tidelift][🏙️entsup-tidelift-img]]
|
|
569
|
+
[![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
|
|
575
570
|
|
|
576
|
-
|
|
571
|
+
- 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
|
|
577
572
|
|
|
578
|
-
|
|
573
|
+
- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
|
|
579
574
|
|
|
580
|
-
|
|
581
|
-
|
|
575
|
+
- 💡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
|
|
576
|
+
Alternatively:
|
|
582
577
|
|
|
583
|
-
|
|
578
|
+
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
|
|
584
579
|
|
|
585
|
-
|
|
580
|
+
- [![Get help from me on Upwork][👨🏼🏫expsup-upwork-img]][👨🏼🏫expsup-upwork]
|
|
586
581
|
|
|
587
|
-
|
|
582
|
+
- [![Get help from me on Codementor][👨🏼🏫expsup-codementor-img]][👨🏼🏫expsup-codementor]
|
|
588
583
|
|
|
589
584
|
</details>
|
|
590
585
|
|
|
@@ -668,9 +663,9 @@ TreeHaver supports 10 parsing backends, each with different trade-offs. The `aut
|
|
|
668
663
|
|
|
669
664
|
**Known Issues:**
|
|
670
665
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
666
|
+
- \*MRI + Bash: ABI incompatibility (use FFI instead)
|
|
667
|
+
- \*Rust + Bash: Version mismatch (use FFI instead)
|
|
668
|
+
**Backend Requirements:**
|
|
674
669
|
|
|
675
670
|
```ruby
|
|
676
671
|
# Tree-sitter backends
|
|
@@ -746,10 +741,10 @@ end
|
|
|
746
741
|
|
|
747
742
|
This is particularly useful for:
|
|
748
743
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
744
|
+
- **Testing**: Test the same code with different backends
|
|
745
|
+
- **Performance comparison**: Benchmark different backends
|
|
746
|
+
- **Fallback scenarios**: Try one backend, fall back to another
|
|
747
|
+
- **Thread isolation**: Each thread can use a different backend safely
|
|
753
748
|
|
|
754
749
|
```ruby
|
|
755
750
|
# Example: Testing with multiple backends
|
|
@@ -782,13 +777,13 @@ TreeHaver provides defense-in-depth validations, but you should understand the r
|
|
|
782
777
|
|
|
783
778
|
TreeHaver's `PathValidator` module protects against:
|
|
784
779
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
780
|
+
- **Path traversal**: Paths containing `/../` or `/./` are rejected
|
|
781
|
+
- **Null byte injection**: Paths containing null bytes are rejected
|
|
782
|
+
- **Non-absolute paths**: Relative paths are rejected to prevent CWD-based attacks
|
|
783
|
+
- **Invalid extensions**: Only `.so`, `.dylib`, and `.dll` files are accepted
|
|
784
|
+
- **Malicious filenames**: Filenames must match a safe pattern (alphanumeric, hyphens, underscores)
|
|
785
|
+
- **Invalid language names**: Language names must be lowercase alphanumeric with underscores
|
|
786
|
+
- **Invalid symbol names**: Symbol names must be valid C identifiers
|
|
792
787
|
|
|
793
788
|
#### Secure Usage
|
|
794
789
|
|
|
@@ -816,12 +811,12 @@ The `find_library_path_safe` method only returns paths in trusted directories.
|
|
|
816
811
|
|
|
817
812
|
**Default trusted directories:**
|
|
818
813
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
814
|
+
- `/usr/lib`, `/usr/lib64`
|
|
815
|
+
- `/usr/lib/x86_64-linux-gnu`, `/usr/lib/aarch64-linux-gnu`
|
|
816
|
+
- `/usr/local/lib`
|
|
817
|
+
- `/opt/homebrew/lib`, `/opt/local/lib`
|
|
818
|
+
**Adding custom trusted directories:**
|
|
819
|
+
For non-standard installations (Homebrew on Linux, luarocks, mise, asdf, etc.), register additional trusted directories:
|
|
825
820
|
|
|
826
821
|
```ruby
|
|
827
822
|
# Programmatically at application startup
|
|
@@ -951,29 +946,29 @@ TreeHaver recognizes several environment variables for configuration:
|
|
|
951
946
|
|
|
952
947
|
#### Security Configuration
|
|
953
948
|
|
|
954
|
-
|
|
949
|
+
- **`TREE_HAVER_TRUSTED_DIRS`**: Comma-separated list of additional trusted directories for grammar libraries
|
|
955
950
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
951
|
+
```bash
|
|
952
|
+
# For Homebrew on Linux and luarocks
|
|
953
|
+
export TREE_HAVER_TRUSTED_DIRS="/home/linuxbrew/.linuxbrew/Cellar,~/.local/share/mise/installs/lua"
|
|
954
|
+
```
|
|
960
955
|
|
|
961
|
-
|
|
956
|
+
Tilde (`~`) is expanded to the user's home directory. Directories listed here are considered safe for `find_library_path_safe`.
|
|
962
957
|
|
|
963
958
|
#### Core Runtime Library
|
|
964
959
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
960
|
+
- **`TREE_SITTER_RUNTIME_LIB`**: Absolute path to the core `libtree-sitter` shared library
|
|
961
|
+
```bash
|
|
962
|
+
export TREE_SITTER_RUNTIME_LIB=/usr/local/lib/libtree-sitter.so
|
|
963
|
+
```
|
|
969
964
|
|
|
970
965
|
If not set, TreeHaver tries these names in order:
|
|
971
966
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
967
|
+
- `tree-sitter`
|
|
968
|
+
- `libtree-sitter.so.0`
|
|
969
|
+
- `libtree-sitter.so`
|
|
970
|
+
- `libtree-sitter.dylib`
|
|
971
|
+
- `libtree-sitter.dll`
|
|
977
972
|
|
|
978
973
|
#### Language Symbol Resolution
|
|
979
974
|
|
|
@@ -1245,10 +1240,10 @@ end
|
|
|
1245
1240
|
**Why inherit from Exception?**
|
|
1246
1241
|
Following ruby\_tree\_sitter's reasoning:
|
|
1247
1242
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1243
|
+
- **Thread safety**: Prevents accidental catching in thread cleanup code
|
|
1244
|
+
- **Signal handling**: Ensures parsing errors don't interfere with SIGTERM/SIGINT
|
|
1245
|
+
- **Intentional handling**: Forces developers to explicitly handle parsing errors
|
|
1246
|
+
See `lib/tree_haver/compat.rb` for compatibility layer documentation.
|
|
1252
1247
|
|
|
1253
1248
|
## 🔧 Basic Usage
|
|
1254
1249
|
|
|
@@ -1686,11 +1681,11 @@ end
|
|
|
1686
1681
|
|
|
1687
1682
|
**⚠️ Citrus Backend Limitations:**
|
|
1688
1683
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1684
|
+
- Uses Citrus grammars (not tree-sitter grammars)
|
|
1685
|
+
- No incremental parsing support
|
|
1686
|
+
- No query API
|
|
1687
|
+
- Pure Ruby performance (slower than native backends)
|
|
1688
|
+
- Best for: prototyping, environments without native extension support, teaching
|
|
1694
1689
|
|
|
1695
1690
|
##### Option 4: Parslet Backend (pure Ruby, portable)
|
|
1696
1691
|
|
|
@@ -1712,11 +1707,11 @@ end
|
|
|
1712
1707
|
|
|
1713
1708
|
**⚠️ Parslet Backend Limitations:**
|
|
1714
1709
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1710
|
+
- Uses Parslet grammars (not tree-sitter grammars)
|
|
1711
|
+
- No incremental parsing support
|
|
1712
|
+
- No query API
|
|
1713
|
+
- Pure Ruby performance (slower than native backends)
|
|
1714
|
+
- Best for: prototyping, environments without native extension support, teaching
|
|
1720
1715
|
|
|
1721
1716
|
#### TruffleRuby
|
|
1722
1717
|
|
|
@@ -2033,7 +2028,7 @@ I’m developing a new library, [floss\_funding][🖇floss-funding-gem], designe
|
|
|
2033
2028
|
|
|
2034
2029
|
**[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
|
|
2035
2030
|
|
|
2036
|
-
[![OpenCollective Backers][🖇osc-backers-i]]
|
|
2031
|
+
[![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![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 on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
|
|
2037
2032
|
|
|
2038
2033
|
## 🔐 Security
|
|
2039
2034
|
|
|
@@ -2045,7 +2040,7 @@ If you need some ideas of where to help, you could work on adding more code cove
|
|
|
2045
2040
|
or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
|
|
2046
2041
|
or use the gem and think about how it could be better.
|
|
2047
2042
|
|
|
2048
|
-
We [![Keep A Changelog][📗keep-changelog-img]]
|
|
2043
|
+
We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
|
|
2049
2044
|
|
|
2050
2045
|
See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
|
|
2051
2046
|
|
|
@@ -2055,20 +2050,20 @@ See [CONTRIBUTING.md][🤝contributing].
|
|
|
2055
2050
|
|
|
2056
2051
|
### Code Coverage
|
|
2057
2052
|
|
|
2058
|
-
[![Coverage Graph][🏀codecov-g]]
|
|
2053
|
+
[![Coverage Graph][🏀codecov-g]][🏀codecov]
|
|
2059
2054
|
|
|
2060
|
-
[![Coveralls Test Coverage][🏀coveralls-img]]
|
|
2055
|
+
[![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
|
|
2061
2056
|
|
|
2062
|
-
[![QLTY Test Coverage][🏀qlty-covi]]
|
|
2057
|
+
[![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
|
|
2063
2058
|
|
|
2064
2059
|
### 🪇 Code of Conduct
|
|
2065
2060
|
|
|
2066
2061
|
Everyone interacting with this project's codebases, issue trackers,
|
|
2067
|
-
chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]]
|
|
2062
|
+
chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
|
|
2068
2063
|
|
|
2069
2064
|
## 🌈 Contributors
|
|
2070
2065
|
|
|
2071
|
-
[![Contributors][🖐contributors-img]]
|
|
2066
|
+
[![Contributors][🖐contributors-img]][🖐contributors]
|
|
2072
2067
|
|
|
2073
2068
|
Made with [contributors-img][🖐contrib-rocks].
|
|
2074
2069
|
|
|
@@ -2089,7 +2084,7 @@ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/tree_haver/-/graphs/
|
|
|
2089
2084
|
|
|
2090
2085
|
## 📌 Versioning
|
|
2091
2086
|
|
|
2092
|
-
This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]]
|
|
2087
|
+
This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
|
|
2093
2088
|
Violations of this scheme should be reported as bugs.
|
|
2094
2089
|
Specifically, if a minor or patch version is released that breaks backward compatibility,
|
|
2095
2090
|
a new version should be immediately released that restores compatibility.
|
|
@@ -2118,7 +2113,7 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
|
|
|
2118
2113
|
To get a better understanding of how SemVer is intended to work over a project's lifetime,
|
|
2119
2114
|
read this article from the creator of SemVer:
|
|
2120
2115
|
|
|
2121
|
-
|
|
2116
|
+
- ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
|
|
2122
2117
|
|
|
2123
2118
|
</details>
|
|
2124
2119
|
|
|
@@ -2127,7 +2122,7 @@ See [CHANGELOG.md][📌changelog] for a list of releases.
|
|
|
2127
2122
|
## 📄 License
|
|
2128
2123
|
|
|
2129
2124
|
The gem is available as open source under the terms of
|
|
2130
|
-
the [MIT License][📄license] [![License: MIT][📄license-img]]
|
|
2125
|
+
the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
|
|
2131
2126
|
See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
|
|
2132
2127
|
|
|
2133
2128
|
### © Copyright
|
|
@@ -2155,11 +2150,11 @@ Please consider sponsoring me or the project.
|
|
|
2155
2150
|
|
|
2156
2151
|
To join the community or get help 👇️ Join the Discord.
|
|
2157
2152
|
|
|
2158
|
-
[![Live Chat on Discord][✉️discord-invite-img-ftb]]
|
|
2153
|
+
[![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
|
|
2159
2154
|
|
|
2160
2155
|
To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
|
|
2161
2156
|
|
|
2162
|
-
[![Sponsor kettle-rb/tree\_haver on Open Source Collective][🖇osc-all-bottom-img]]
|
|
2157
|
+
[![Sponsor kettle-rb/tree\_haver 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]
|
|
2163
2158
|
|
|
2164
2159
|
### Please give the project a star ⭐ ♥.
|
|
2165
2160
|
|
|
@@ -2323,7 +2318,7 @@ Thanks for RTFM. ☺️
|
|
|
2323
2318
|
[📌gitmoji]: https://gitmoji.dev
|
|
2324
2319
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
2325
2320
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
2326
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
2321
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.542-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
2327
2322
|
[🔐security]: SECURITY.md
|
|
2328
2323
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
2329
2324
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|