herb 0.8.10-x86_64-linux-gnu → 0.9.0-x86_64-linux-gnu

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.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +11 -3
  3. data/README.md +64 -34
  4. data/Rakefile +48 -40
  5. data/config.yml +317 -34
  6. data/ext/herb/error_helpers.c +367 -140
  7. data/ext/herb/error_helpers.h +1 -0
  8. data/ext/herb/extconf.rb +67 -28
  9. data/ext/herb/extension.c +317 -51
  10. data/ext/herb/extension.h +1 -0
  11. data/ext/herb/extension_helpers.c +23 -14
  12. data/ext/herb/extension_helpers.h +2 -2
  13. data/ext/herb/nodes.c +537 -270
  14. data/ext/herb/nodes.h +1 -0
  15. data/herb.gemspec +3 -2
  16. data/lib/herb/3.0/herb.so +0 -0
  17. data/lib/herb/3.1/herb.so +0 -0
  18. data/lib/herb/3.2/herb.so +0 -0
  19. data/lib/herb/3.3/herb.so +0 -0
  20. data/lib/herb/3.4/herb.so +0 -0
  21. data/lib/herb/4.0/herb.so +0 -0
  22. data/lib/herb/ast/helpers.rb +3 -3
  23. data/lib/herb/ast/node.rb +15 -2
  24. data/lib/herb/ast/nodes.rb +1132 -157
  25. data/lib/herb/bootstrap.rb +87 -0
  26. data/lib/herb/cli.rb +341 -31
  27. data/lib/herb/configuration.rb +248 -0
  28. data/lib/herb/defaults.yml +32 -0
  29. data/lib/herb/engine/compiler.rb +78 -11
  30. data/lib/herb/engine/debug_visitor.rb +13 -3
  31. data/lib/herb/engine/error_formatter.rb +13 -9
  32. data/lib/herb/engine/parser_error_overlay.rb +10 -6
  33. data/lib/herb/engine/validator.rb +8 -3
  34. data/lib/herb/engine/validators/nesting_validator.rb +2 -2
  35. data/lib/herb/engine.rb +82 -35
  36. data/lib/herb/errors.rb +563 -88
  37. data/lib/herb/lex_result.rb +1 -0
  38. data/lib/herb/location.rb +7 -3
  39. data/lib/herb/parse_result.rb +12 -2
  40. data/lib/herb/parser_options.rb +57 -0
  41. data/lib/herb/position.rb +1 -0
  42. data/lib/herb/prism_inspect.rb +116 -0
  43. data/lib/herb/project.rb +923 -331
  44. data/lib/herb/range.rb +1 -0
  45. data/lib/herb/token.rb +7 -1
  46. data/lib/herb/version.rb +1 -1
  47. data/lib/herb/visitor.rb +37 -2
  48. data/lib/herb/warnings.rb +6 -1
  49. data/lib/herb.rb +35 -3
  50. data/sig/herb/ast/helpers.rbs +2 -2
  51. data/sig/herb/ast/node.rbs +12 -2
  52. data/sig/herb/ast/nodes.rbs +641 -128
  53. data/sig/herb/bootstrap.rbs +31 -0
  54. data/sig/herb/configuration.rbs +89 -0
  55. data/sig/herb/engine/compiler.rbs +9 -1
  56. data/sig/herb/engine/debug_visitor.rbs +2 -0
  57. data/sig/herb/engine/validator.rbs +5 -1
  58. data/sig/herb/engine.rbs +17 -3
  59. data/sig/herb/errors.rbs +258 -63
  60. data/sig/herb/location.rbs +4 -0
  61. data/sig/herb/parse_result.rbs +4 -2
  62. data/sig/herb/parser_options.rbs +42 -0
  63. data/sig/herb/position.rbs +1 -0
  64. data/sig/herb/prism_inspect.rbs +28 -0
  65. data/sig/herb/range.rbs +1 -0
  66. data/sig/herb/token.rbs +6 -0
  67. data/sig/herb/visitor.rbs +25 -4
  68. data/sig/herb/warnings.rbs +6 -1
  69. data/sig/herb.rbs +14 -0
  70. data/sig/herb_c_extension.rbs +5 -2
  71. data/sig/serialized_ast_errors.rbs +54 -6
  72. data/sig/serialized_ast_nodes.rbs +60 -6
  73. data/src/analyze/action_view/attribute_extraction_helpers.c +290 -0
  74. data/src/analyze/action_view/content_tag.c +70 -0
  75. data/src/analyze/action_view/link_to.c +143 -0
  76. data/src/analyze/action_view/registry.c +60 -0
  77. data/src/analyze/action_view/tag.c +64 -0
  78. data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
  79. data/src/analyze/action_view/tag_helpers.c +748 -0
  80. data/src/analyze/action_view/turbo_frame_tag.c +88 -0
  81. data/src/analyze/analyze.c +882 -0
  82. data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  83. data/src/analyze/builders.c +343 -0
  84. data/src/analyze/conditional_elements.c +594 -0
  85. data/src/analyze/conditional_open_tags.c +640 -0
  86. data/src/analyze/control_type.c +250 -0
  87. data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
  88. data/src/analyze/invalid_structures.c +193 -0
  89. data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  90. data/src/analyze/parse_errors.c +84 -0
  91. data/src/analyze/prism_annotate.c +397 -0
  92. data/src/{analyze_transform.c → analyze/transform.c} +17 -3
  93. data/src/ast_node.c +17 -7
  94. data/src/ast_nodes.c +662 -387
  95. data/src/ast_pretty_print.c +190 -6
  96. data/src/errors.c +1076 -520
  97. data/src/extract.c +145 -49
  98. data/src/herb.c +52 -34
  99. data/src/html_util.c +241 -12
  100. data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  101. data/src/include/analyze/action_view/tag_helper_handler.h +41 -0
  102. data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  103. data/src/include/analyze/action_view/tag_helpers.h +38 -0
  104. data/src/include/{analyze.h → analyze/analyze.h} +14 -4
  105. data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  106. data/src/include/analyze/builders.h +27 -0
  107. data/src/include/analyze/conditional_elements.h +9 -0
  108. data/src/include/analyze/conditional_open_tags.h +9 -0
  109. data/src/include/analyze/control_type.h +14 -0
  110. data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
  111. data/src/include/analyze/invalid_structures.h +11 -0
  112. data/src/include/analyze/prism_annotate.h +16 -0
  113. data/src/include/ast_node.h +11 -5
  114. data/src/include/ast_nodes.h +117 -38
  115. data/src/include/ast_pretty_print.h +5 -0
  116. data/src/include/element_source.h +3 -8
  117. data/src/include/errors.h +148 -55
  118. data/src/include/extract.h +21 -5
  119. data/src/include/herb.h +18 -6
  120. data/src/include/herb_prism_node.h +13 -0
  121. data/src/include/html_util.h +7 -2
  122. data/src/include/io.h +3 -1
  123. data/src/include/lex_helpers.h +29 -0
  124. data/src/include/lexer.h +1 -1
  125. data/src/include/lexer_peek_helpers.h +87 -13
  126. data/src/include/lexer_struct.h +2 -0
  127. data/src/include/location.h +2 -1
  128. data/src/include/parser.h +27 -2
  129. data/src/include/parser_helpers.h +19 -3
  130. data/src/include/pretty_print.h +10 -5
  131. data/src/include/prism_context.h +45 -0
  132. data/src/include/prism_helpers.h +10 -7
  133. data/src/include/prism_serialized.h +12 -0
  134. data/src/include/token.h +16 -4
  135. data/src/include/token_struct.h +10 -3
  136. data/src/include/utf8.h +2 -1
  137. data/src/include/util/hb_allocator.h +78 -0
  138. data/src/include/util/hb_arena.h +6 -1
  139. data/src/include/util/hb_arena_debug.h +12 -1
  140. data/src/include/util/hb_array.h +7 -3
  141. data/src/include/util/hb_buffer.h +6 -4
  142. data/src/include/util/hb_foreach.h +79 -0
  143. data/src/include/util/hb_narray.h +8 -4
  144. data/src/include/util/hb_string.h +56 -9
  145. data/src/include/util.h +6 -3
  146. data/src/include/version.h +1 -1
  147. data/src/io.c +3 -2
  148. data/src/lexer.c +42 -30
  149. data/src/lexer_peek_helpers.c +12 -74
  150. data/src/location.c +2 -2
  151. data/src/main.c +53 -28
  152. data/src/parser.c +783 -247
  153. data/src/parser_helpers.c +110 -23
  154. data/src/parser_match_tags.c +109 -48
  155. data/src/pretty_print.c +29 -24
  156. data/src/prism_helpers.c +30 -27
  157. data/src/ruby_parser.c +2 -0
  158. data/src/token.c +151 -66
  159. data/src/token_matchers.c +0 -1
  160. data/src/utf8.c +7 -6
  161. data/src/util/hb_allocator.c +341 -0
  162. data/src/util/hb_arena.c +81 -56
  163. data/src/util/hb_arena_debug.c +32 -17
  164. data/src/util/hb_array.c +30 -15
  165. data/src/util/hb_buffer.c +17 -21
  166. data/src/util/hb_narray.c +22 -7
  167. data/src/util/hb_string.c +49 -35
  168. data/src/util.c +21 -11
  169. data/src/visitor.c +47 -0
  170. data/templates/ext/herb/error_helpers.c.erb +24 -11
  171. data/templates/ext/herb/error_helpers.h.erb +1 -0
  172. data/templates/ext/herb/nodes.c.erb +50 -16
  173. data/templates/ext/herb/nodes.h.erb +1 -0
  174. data/templates/java/error_helpers.c.erb +1 -1
  175. data/templates/java/nodes.c.erb +30 -8
  176. data/templates/java/org/herb/ast/Errors.java.erb +24 -1
  177. data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
  178. data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
  179. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
  180. data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
  181. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
  182. data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
  183. data/templates/lib/herb/ast/nodes.rb.erb +88 -31
  184. data/templates/lib/herb/errors.rb.erb +15 -3
  185. data/templates/lib/herb/visitor.rb.erb +2 -2
  186. data/templates/rust/src/ast/nodes.rs.erb +97 -44
  187. data/templates/rust/src/errors.rs.erb +2 -1
  188. data/templates/rust/src/nodes.rs.erb +167 -15
  189. data/templates/rust/src/union_types.rs.erb +60 -0
  190. data/templates/rust/src/visitor.rs.erb +81 -0
  191. data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
  192. data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
  193. data/templates/src/ast_nodes.c.erb +34 -26
  194. data/templates/src/ast_pretty_print.c.erb +24 -5
  195. data/templates/src/errors.c.erb +60 -54
  196. data/templates/src/include/ast_nodes.h.erb +6 -2
  197. data/templates/src/include/ast_pretty_print.h.erb +5 -0
  198. data/templates/src/include/errors.h.erb +15 -11
  199. data/templates/src/include/util/hb_foreach.h.erb +20 -0
  200. data/templates/src/parser_match_tags.c.erb +10 -4
  201. data/templates/src/visitor.c.erb +2 -2
  202. data/templates/template.rb +204 -29
  203. data/templates/wasm/error_helpers.cpp.erb +9 -5
  204. data/templates/wasm/nodes.cpp.erb +41 -4
  205. metadata +57 -16
  206. data/src/analyze.c +0 -1608
  207. data/src/element_source.c +0 -12
  208. data/src/include/util/hb_system.h +0 -9
  209. data/src/util/hb_system.c +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2cb3fc5a1e4ce65edf3d8818c9f7beac3346b3f088ebb11d1b35b7ec838875a
4
- data.tar.gz: 95b4a29114c7b51b3f6b011d4ba9df0d102151c2134afa9aae2f5b6c642c815e
3
+ metadata.gz: 266d436d1f028ecf08ef1c80e0bd4d5b687b573a0afdef36e12b73ab34ef3f44
4
+ data.tar.gz: 3102f72fe7a8aa299b3d5b44ba0e8e3d4c2fd8da9d5232153fc3b1f36d61383c
5
5
  SHA512:
6
- metadata.gz: 251e108052ed75775bebcfa4a4ee5bfa51b65ef2f1ec348c897ea50dcd8e8139883eaf181eab119bbd79e76c98cbcd175c99f1e6a8840ad092d4650324bad305
7
- data.tar.gz: 72992065a836969dd55a56f9c8e47a51d2041f59e9c3f644bb54e6ce24b11a17b472f427442dec2bad7d2b1aec3ddceba58fdfeca58cd2a369509eb6cdf6ba0e
6
+ metadata.gz: 87285b864845e03f8ec8d932cd5e823e503fcf3f9df55f8f0b3f5753f9e0dc43e906b6dc81e49b5a995a10adcb592a7416e56255a09ca86b24a649141aaa311c
7
+ data.tar.gz: ac838a00774930c1716b34e4761884e38df6edf1a35d6e1ddf6b98ddcd35486227676a49a271499ca4fac8dcfcaa287d1be2bcfb218b9c99599110aed0fe178a
data/Makefile CHANGED
@@ -1,8 +1,8 @@
1
1
  exec = herb
2
2
  test_exec = run_herb_tests
3
3
 
4
- sources = $(wildcard src/*.c) $(wildcard src/**/*.c)
5
- headers = $(wildcard src/*.h) $(wildcard src/**/*.h)
4
+ sources = $(shell find src -name '*.c')
5
+ headers = $(shell find src -name '*.h')
6
6
  objects = $(sources:.c=.o)
7
7
 
8
8
  extension_sources = $(wildcard ext/**/*.c)
@@ -20,6 +20,9 @@ test_sources = $(wildcard test/**/*.c)
20
20
  test_objects = $(test_sources:.c=.o)
21
21
  non_main_objects = $(filter-out src/main.o, $(objects))
22
22
 
23
+ bench_allocs_exec = bench_allocs
24
+ bench_allocs_source = bench/bench_allocs.c
25
+
23
26
  soext ?= $(shell ruby -e 'puts RbConfig::CONFIG["DLEXT"]')
24
27
  lib_name = $(build_dir)/lib$(exec).$(soext)
25
28
  static_lib_name = $(build_dir)/lib$(exec).a
@@ -102,9 +105,14 @@ test/%.o: test/%.c templates prism
102
105
  test: $(test_objects) $(non_main_objects)
103
106
  $(cc) $(test_objects) $(non_main_objects) $(test_cflags) $(test_ldflags) -o $(test_exec)
104
107
 
108
+ .PHONY: bench_allocs
109
+ bench_allocs: $(non_main_objects)
110
+ $(cc) $(bench_allocs_source) $(non_main_objects) $(flags) $(prism_ldflags) -o $(bench_allocs_exec)
111
+ ./$(bench_allocs_exec)
112
+
105
113
  .PHONY: clean
106
114
  clean:
107
- rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(ruby_extension)
115
+ rm -f $(exec) $(test_exec) $(bench_allocs_exec) $(lib_name) $(shared_lib_name) $(ruby_extension)
108
116
  rm -rf $(objects) $(test_objects) $(extension_objects) lib/herb/*.bundle tmp
109
117
  rm -rf $(prism_path)
110
118
  rake prism:clean
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  <div align="center">
2
- <img alt="Herb HTML+ERB parser" style="height: 256px" height="256px" src="https://github.com/user-attachments/assets/d0714ee1-ca33-4aa4-aaa9-d632ba79d54a">
2
+ <img alt="Herb HTML+ERB Toolchain" style="height: 256px" height="256px" src="https://github.com/user-attachments/assets/d0714ee1-ca33-4aa4-aaa9-d632ba79d54a">
3
3
  </div>
4
4
 
5
5
  <h2 align="center">Herb</h2>
6
6
 
7
- <h4 align="center">HTML+ERB (HTML + Embedded Ruby)</h4>
7
+ <h4 align="center">The modern HTML+ERB Toolchain</h4>
8
8
 
9
- <div align="center">Powerful and seamless HTML-aware ERB parsing and tooling.</div><br/>
9
+ <div align="center">An ecosystem of powerful and seamless developer tools for HTML+ERB (HTML + Embedded Ruby) templates.</div><br/>
10
10
 
11
11
  <p align="center">
12
12
  <a href="https://rubygems.org/gems/herb"><img alt="Gem Version" src="https://img.shields.io/gem/v/herb"></a>
@@ -25,36 +25,53 @@
25
25
 
26
26
  ## What is Herb?
27
27
 
28
- **Herb** is an ecosystem of developer tooling built specifically around **HTML+ERB** (`.html.erb`) files. It is designed to simplify and enhance the experience of working with HTML+ERB templates through precise, accurate tooling.
28
+ **Herb** is a powerful and seamless HTML-aware ERB toolchain and an ecosystem of developer tools built specifically for **HTML+ERB** (`.html.erb`) files. It is designed to simplify and enhance the experience of working with HTML+ERB templates through precise, accurate tooling.
29
29
 
30
- At the core of Herb is the **Herb Parser**, a fast, portable, and HTML-aware ERB parser written in C. The parser generates a detailed, accurate syntax tree that serves as the foundation for reliable code analysis, transformations, and developer tooling.
30
+ **Parser**
31
31
 
32
- The Herb ecosystem includes **developer tools** (CLI, language server, formatter, linter), **language bindings** (for Ruby, Node.js, and the Browser using WebAssembly), and **utility libraries** (language service, highlighter, minifier, printer). All these components leverage the Herb Parser's syntax tree to provide consistent, accurate, and helpful tooling experiences.
32
+ At the core of the Herb ecosystem is the **Herb Parser**, a fast, portable, and HTML-aware ERB parser written in C. The parser generates a detailed, accurate syntax tree that serves as the foundation for reliable code analysis, transformations, and developer tooling.
33
33
 
34
- ## What Herb Can Do for You
34
+ **Toolchain**
35
35
 
36
- Herb provides a complete ecosystem of HTML+ERB tooling, designed to simplify and enhance your daily workflow. Built on the **Herb Parser**, it offers multiple tools that integrate seamlessly into editors, developer environments, and CI pipelines:
36
+ The Herb toolchain includes **developer tools** (CLI, language server, formatter, linter, browser dev tools), **language bindings** (for Ruby, Node.js, Java, Rust, and the Browser using WebAssembly), and **utility libraries** (language service, highlighter, minifier, printer).
37
37
 
38
- - **Herb Language Server** ([available now](https://herb-tools.dev/projects/language-server)):
39
- Rich integration for editors like VS Code, Zed, Neovim, and more. It provides diagnostics and real-time feedback to keep your templates error-free.
38
+ All these components leverage the Herb Parser's syntax tree to provide consistent, accurate, and helpful tooling experiences.
40
39
 
41
- - **Herb Formatter** ([experimental preview](https://herb-tools.dev/projects/formatter)):
42
- Automatic, consistent formatting for HTML+ERB files, reducing manual styling and enforcing a standard across projects. Currently in experimental preview - use with caution on version-controlled files.
40
+ **Engine**
43
41
 
44
- - **Herb Linter** ([available now](https://herb-tools.dev/projects/linter)):
45
- Static analysis for your HTML+ERB templates to enforce best practices and quickly identify common mistakes with plenty of rules.
42
+ `Herb::Engine` is a new, HTML-aware ERB rendering engine built on the Herb Parser. It is designed to be API-compatible with [`Erubi::Engine`](https://github.com/jeremyevans/erubi) while adding structural awareness of HTML+ERB content, enabling features like HTML validation, security checks, and precise error reporting.
46
43
 
47
- You can use Herb programmatically in **Ruby**, as well as in **JavaScript** via Node.js, WebAssembly, or directly in browsers.
44
+ The Engine powers **ReActionView** and lays the foundation for a modern view layer for Rails and other Ruby web frameworks.
45
+
46
+ | **[ReActionView](https://reactionview.dev)** <br> 🌱 A new ActionView-compatible ERB engine with modern DX, re-imagined with `Herb::Engine`. |
47
+ | --- |
48
+ | [GitHub](https://github.com/marcoroth/reactionview) · [Website](https://reactionview.dev) · [Documentation](https://reactionview.dev/overview) |
49
+
50
+ ## Ecosystem
51
+
52
+ The Herb ecosystem offers multiple tools that integrate seamlessly into editors, developer environments, and CI pipelines:
53
+
54
+ | Tool | Description |
55
+ | --- | --- |
56
+ | [Herb Parser](https://herb-tools.dev/projects/parser) | Fast, portable, HTML-aware ERB parser written in C. |
57
+ | [Herb Linter](https://herb-tools.dev/projects/linter) | Static analysis to enforce best practices and identify common mistakes. |
58
+ | [Herb Formatter](https://herb-tools.dev/projects/formatter) | Automatic, consistent formatting for HTML+ERB files. *(experimental)* |
59
+ | [Herb Language Server](https://herb-tools.dev/projects/language-server) | Rich editor integration for VS Code, Zed, Neovim, and more. |
60
+ | [Herb Engine](https://herb-tools.dev/projects/engine) | HTML-aware ERB rendering engine, API-compatible with Erubi. |
61
+ | [Herb Dev Tools](https://herb-tools.dev/projects/dev-tools) | In-browser dev tools for inspecting and debugging templates, shipped with ReActionView. |
62
+ | [ReActionView](https://reactionview.dev) | ActionView-compatible ERB engine with modern DX for Rails. |
63
+
64
+ You can use the Herb Parser programmatically in **Ruby**, **Java**, **Rust**, as well as in **JavaScript** via Node.js, WebAssembly, or directly in browsers.
48
65
 
49
66
  For a complete overview of all available tools, libraries, and integrations, visit the [**Projects page**](https://herb-tools.dev/projects) on our documentation site.
50
67
 
51
68
  ## Motivation
52
69
 
53
- HTML+ERB templates never really had good, accurate, and reliable tooling. While developer tooling for Ruby code improved significantly in the last few years (especially with the introduction of the new Prism parser), HTML+ERB files remained underserved, lacking fundamental support like syntax checking, auto-formatting, linting, and structural understanding.
70
+ HTML+ERB templates never really had good, accurate, and reliable tooling. While developer tooling for Ruby code improved significantly in the last few years (especially with the introduction of the new [Prism parser](https://github.com/ruby/prism)), HTML+ERB files remained underserved, lacking fundamental support like syntax checking, auto-formatting, linting, and structural understanding.
54
71
 
55
72
  At the same time, with the rise of tools like [Hotwire](https://hotwired.dev), [Stimulus](https://stimulus.hotwired.dev), [Turbo](https://turbo.hotwired.dev), [HTMX](https://htmx.org), [Unpoly](https://unpoly.com), and [Alpine.js](https://alpinejs.dev), advanced HTML templating became increasingly relevant (again). Developers expect modern, reliable, and precise tooling, especially given the robust ecosystem available to JavaScript frameworks and libraries.
56
73
 
57
- Herb was built to close this tooling gap, providing proper tooling for HTML+ERB that matches what modern developers expect in the age of language servers, LLMs, and AI-driven workflows.
74
+ Herb was built to close this tooling gap with an HTML-aware approach, understanding both HTML structure and ERB as first-class citizens, to provide the kind of tooling modern developers expect in the age of language servers, LLMs, and AI-driven workflows.
58
75
 
59
76
  ## Command-Line Usage
60
77
 
@@ -64,6 +81,20 @@ Install the Herb gem via RubyGems:
64
81
  gem install herb
65
82
  ```
66
83
 
84
+ ### Installing from a Git branch
85
+
86
+ To test a branch before it's released (e.g. from a fork), add both `prism` and `herb` to your Gemfile:
87
+
88
+ ```ruby
89
+ gem "prism", github: "ruby/prism", tag: "v1.9.0"
90
+ gem "herb", github: "fork/herb", branch: "my-branch"
91
+ ```
92
+
93
+ The `prism` gem is required because Herb's native C extension compiles against
94
+ Prism's C source, which is vendored automatically during installation.
95
+
96
+ For detailed information, like how you can use Herb programmatically in Ruby and JavaScript, visit the [documentation site](https://herb-tools.dev/bindings/ruby/reference).
97
+
67
98
  Basic usage to analyze all HTML+ERB files in your project:
68
99
 
69
100
  ```sh
@@ -86,30 +117,29 @@ Files with parse errors:
86
117
  Results saved to 2025-06-29_12-16-23_erb_parsing_result_rubyevents.log
87
118
  ```
88
119
 
89
- Herb also comes with other useful commands:
120
+ Lint your HTML+ERB templates:
90
121
 
122
+ ```sh
123
+ npx @herb-tools/linter
91
124
  ```
92
- Herb 🌿 Powerful and seamless HTML-aware ERB parsing and tooling.
93
-
94
- Usage:
95
- bundle exec herb [command] [options]
96
-
97
- Commands:
98
- bundle exec herb lex [file] Lex a file.
99
- bundle exec herb parse [file] Parse a file.
100
- bundle exec herb analyze [path] Analyze a project by passing a directory to the root of the project
101
- bundle exec herb ruby [file] Extract Ruby from a file.
102
- bundle exec herb html [file] Extract HTML from a file.
103
- bundle exec herb playground [file] Open the content of the source file in the playground
104
- bundle exec herb version Prints the versions of the Herb gem and the libherb library.
125
+
126
+ Format your HTML+ERB templates:
127
+
128
+ ```sh
129
+ npx @herb-tools/formatter
105
130
  ```
106
131
 
107
- For detailed information, like how you can use Herb programmatically in Ruby and JavaScript, visit the [documentation site](https://herb-tools.dev/bindings/ruby/reference).
108
132
 
109
133
 
110
- ## Background and Talk
134
+ ## Background and Talks
135
+
136
+ The **Herb Parser** was first introduced at [**RubyKaigi 2025**](https://rubykaigi.org/2025/presentations/marcoroth.html) in April 2025 with the talk [*Empowering Developers with HTML-Aware ERB Tooling*](https://www.rubyevents.org/talks/empowering-developers-with-html-aware-erb-tooling-rubykaigi-2025).
137
+
138
+ At [**RailsConf 2025**](https://www.rubyevents.org/events/railsconf-2025) in July 2025, the Herb ecosystem was expanded with the talk [*The Modern View Layer Rails Deserves: A Vision for 2025 and Beyond*](https://www.rubyevents.org/talks/the-modern-view-layer-rails-deserves-a-vision-for-2025-and-beyond), introducing the linter, formatter, language server, and the vision for ReActionView.
139
+
140
+ At [**Rails World 2025**](https://www.rubyevents.org/events/rails-world-2025) in September 2025, `Herb::Engine`, ReActionView, and the visual dev tools were launched with the talk [*Introducing ReActionView: An ActionView-Compatible ERB Engine*](https://www.rubyevents.org/talks/introducing-reactionview-an-actionview-compatible-erb-engine).
111
141
 
112
- **Herb** was first introduced at [**RubyKaigi 2025**](https://rubykaigi.org/2025/presentations/marcoroth.html) in April 2025 with the talk [*Empowering Developers with HTML-Aware ERB Tooling*](https://www.rubyevents.org/talks/empowering-developers-with-html-aware-erb-tooling-rubykaigi-2025).
142
+ At [**San Francisco Ruby Conference 2025**](https://www.rubyevents.org/events/sfruby-2025) in November 2025, the keynote [*Herb to ReActionView: A New Foundation for the View Layer*](https://www.rubyevents.org/talks/keynote-herb-to-reactionview-a-new-foundation-for-the-view-layer) gave an overview of how Herb came to be, what Herb can do for you today, and how it could enable the next generation of the Rails view layer with ReActionView.
113
143
 
114
144
  ## Contributing
115
145
 
data/Rakefile CHANGED
@@ -5,6 +5,34 @@ require "bundler/gem_tasks"
5
5
  require "rake/testtask"
6
6
 
7
7
  Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.test_files = FileList["test/**/*_test.rb"].exclude("test/engine/**/*_test.rb", "test/integration/**/*_test.rb")
11
+ end
12
+
13
+ task :test_tip do
14
+ puts "TIP: This only runs core tests. Other test tasks available:"
15
+ puts " rake test:all"
16
+ puts " rake test:engine"
17
+ puts " rake test:integration"
18
+ puts
19
+ end
20
+
21
+ Rake::Task[:test].enhance([:test_tip])
22
+
23
+ Rake::TestTask.new("test:engine") do |t|
24
+ t.libs << "test"
25
+ t.libs << "lib"
26
+ t.test_files = FileList["test/engine/**/*_test.rb"]
27
+ end
28
+
29
+ Rake::TestTask.new("test:integration") do |t|
30
+ t.libs << "test"
31
+ t.libs << "lib"
32
+ t.test_files = FileList["test/integration/**/*_test.rb"]
33
+ end
34
+
35
+ Rake::TestTask.new("test:all") do |t|
8
36
  t.libs << "test"
9
37
  t.libs << "lib"
10
38
  t.test_files = FileList["test/**/*_test.rb"]
@@ -22,17 +50,17 @@ end
22
50
  begin
23
51
  require "rake/extensiontask"
24
52
 
25
- PLATFORMS = %w[
26
- aarch64-linux-gnu
27
- aarch64-linux-musl
28
- arm-linux-gnu
29
- arm-linux-musl
30
- arm64-darwin
31
- x86_64-darwin
32
- x86_64-linux-gnu
33
- x86_64-linux-musl
34
- x86-linux-gnu
35
- x86-linux-musl
53
+ PLATFORMS = [
54
+ "aarch64-linux-gnu",
55
+ "aarch64-linux-musl",
56
+ "arm-linux-gnu",
57
+ "arm-linux-musl",
58
+ "arm64-darwin",
59
+ "x86_64-darwin",
60
+ "x86_64-linux-gnu",
61
+ "x86_64-linux-musl",
62
+ "x86-linux-gnu",
63
+ "x86-linux-musl"
36
64
  ].freeze
37
65
 
38
66
  exttask = Rake::ExtensionTask.new do |ext|
@@ -121,55 +149,35 @@ end
121
149
 
122
150
  desc "Render out template files"
123
151
  task :templates do
124
- require_relative "templates/template"
152
+ require_relative "lib/herb/bootstrap"
125
153
 
126
- Dir.glob("#{__dir__}/templates/**/*.erb").each do |template|
127
- Herb::Template.render(template)
128
- end
154
+ Herb::Bootstrap.generate_templates
129
155
  end
130
156
 
131
- prism_vendor_path = "vendor/prism"
132
-
133
157
  namespace :prism do
134
158
  desc "Setup and vendor Prism"
135
159
  task :vendor do
160
+ require_relative "lib/herb/bootstrap"
161
+
136
162
  Rake::Task["prism:clean"].execute
137
163
 
138
164
  prism_bundle_path = `bundle show prism`.chomp
139
165
 
140
- puts prism_bundle_path
141
-
142
166
  if prism_bundle_path.empty?
143
167
  puts "Make sure to run `bundle install` in the herb project directory first"
144
168
  exit 1
145
169
  end
146
170
 
147
- FileUtils.mkdir_p(prism_vendor_path)
148
-
149
- files = [
150
- "config.yml",
151
- "Rakefile",
152
- "src/",
153
- "include/",
154
- "templates/"
155
- ]
156
-
157
- files.each do |file|
158
- vendored_file_path = prism_vendor_path + "/#{file}"
159
- puts "Vendoring '#{file}' Prism file to #{vendored_file_path}"
160
- FileUtils.cp_r(prism_bundle_path + "/#{file}", prism_vendor_path)
161
- end
162
-
163
- prism_ast_header = "#{prism_vendor_path}/include/prism/ast.h"
171
+ puts prism_bundle_path
164
172
 
165
- unless File.exist?(prism_ast_header)
166
- puts "Generating Prism template files..."
167
- system("ruby #{prism_vendor_path}/templates/template.rb", exception: true)
168
- end
173
+ Herb::Bootstrap.vendor_prism(prism_gem_path: prism_bundle_path)
169
174
  end
170
175
 
171
176
  desc "Clean vendored Prism in vendor/prism/"
172
177
  task :clean do
178
+ require_relative "lib/herb/bootstrap"
179
+
180
+ prism_vendor_path = Herb::Bootstrap::PRISM_VENDOR_DIR
173
181
  puts "Cleaning up vendored Prism at #{prism_vendor_path}..."
174
182
  begin
175
183
  FileUtils.rm_r(prism_vendor_path)