herb 0.6.1-x86-linux-musl → 0.7.0-x86-linux-musl

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/ext/herb/nodes.c +6 -4
  4. data/lib/herb/3.0/herb.so +0 -0
  5. data/lib/herb/3.1/herb.so +0 -0
  6. data/lib/herb/3.2/herb.so +0 -0
  7. data/lib/herb/3.3/herb.so +0 -0
  8. data/lib/herb/3.4/herb.so +0 -0
  9. data/lib/herb/ast/helpers.rb +26 -0
  10. data/lib/herb/ast/nodes.rb +7 -3
  11. data/lib/herb/cli.rb +158 -1
  12. data/lib/herb/engine/compiler.rb +399 -0
  13. data/lib/herb/engine/debug_visitor.rb +321 -0
  14. data/lib/herb/engine/error_formatter.rb +420 -0
  15. data/lib/herb/engine/parser_error_overlay.rb +767 -0
  16. data/lib/herb/engine/validation_error_overlay.rb +182 -0
  17. data/lib/herb/engine/validation_errors.rb +65 -0
  18. data/lib/herb/engine/validator.rb +75 -0
  19. data/lib/herb/engine/validators/accessibility_validator.rb +31 -0
  20. data/lib/herb/engine/validators/nesting_validator.rb +95 -0
  21. data/lib/herb/engine/validators/security_validator.rb +71 -0
  22. data/lib/herb/engine.rb +366 -0
  23. data/lib/herb/project.rb +3 -3
  24. data/lib/herb/version.rb +1 -1
  25. data/lib/herb/visitor.rb +2 -0
  26. data/lib/herb.rb +2 -0
  27. data/sig/herb/ast/helpers.rbs +16 -0
  28. data/sig/herb/ast/nodes.rbs +4 -2
  29. data/sig/herb/engine/compiler.rbs +109 -0
  30. data/sig/herb/engine/debug.rbs +38 -0
  31. data/sig/herb/engine/debug_visitor.rbs +70 -0
  32. data/sig/herb/engine/error_formatter.rbs +47 -0
  33. data/sig/herb/engine/parser_error_overlay.rbs +41 -0
  34. data/sig/herb/engine/validation_error_overlay.rbs +35 -0
  35. data/sig/herb/engine/validation_errors.rbs +45 -0
  36. data/sig/herb/engine/validator.rbs +37 -0
  37. data/sig/herb/engine/validators/accessibility_validator.rbs +19 -0
  38. data/sig/herb/engine/validators/nesting_validator.rbs +25 -0
  39. data/sig/herb/engine/validators/security_validator.rbs +23 -0
  40. data/sig/herb/engine.rbs +72 -0
  41. data/sig/herb/visitor.rbs +2 -0
  42. data/sig/herb_c_extension.rbs +7 -0
  43. data/sig/serialized_ast_nodes.rbs +1 -0
  44. data/src/ast_nodes.c +2 -1
  45. data/src/ast_pretty_print.c +2 -1
  46. data/src/element_source.c +11 -0
  47. data/src/include/ast_nodes.h +3 -1
  48. data/src/include/element_source.h +13 -0
  49. data/src/include/version.h +1 -1
  50. data/src/parser.c +3 -0
  51. data/src/parser_helpers.c +1 -0
  52. metadata +30 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4aa64c91c7cbc7283994ea4483bcd4919b6c34a1dd6168abe5e7067c73c035ff
4
- data.tar.gz: b11c8bce197668327e5b01de03748d5c2877582a18e382beb542548a0356785c
3
+ metadata.gz: 4c817e048425267d57d7e86f1e8ee6c08a283458435a1d1bd13cf8ec42d1722b
4
+ data.tar.gz: 1461dcca1670e4315755aa5364c31c7cbefc8ee5f8b7f8746e7a88f5e96040b8
5
5
  SHA512:
6
- metadata.gz: f001e033f06ccf76e84c4a359abdd1caad166ee3ea3d9ffeba59ee3933c9bb0f799e4a41b965ff625ce2bfff189584439c87ca3d0b0068b21921143692ab8441
7
- data.tar.gz: 3545109c8b87bc84ab9cffb541d3e6033420b564b8ffe70a51a6fcd1cd94a57094eff4a2dbcd09d0d41d89b677b8ac5b73b8e3c7cf3f8860c7949fef22cdfe3f
6
+ metadata.gz: 1d8e07da38c1c0400a3bf8e7cd06cd70e0b737268d30c778efef7bb603027c281e8cf0d761c202a895888a0003353ca89aa5d4eb163d08cad0bec9a83e13d11b
7
+ data.tar.gz: bf2f61abf772b93cb77e7405dfdc5e0e2bf1870c642941ff6c9484b9c8a52a440dc8993e89ed614f84397f3880b1f0fbed73c11404d926d72f3ef1af91fcf9d0
data/README.md CHANGED
@@ -127,6 +127,7 @@ While Herb brings a fresh approach to HTML+ERB tooling, it builds upon and learn
127
127
  - [**htmlbeautifier**](https://github.com/threedaymonk/htmlbeautifier)
128
128
  - [**vscode-erb-beautify**](https://github.com/aliariff/vscode-erb-beautify)
129
129
  - [**vscode-erb-linter**](https://github.com/manuelpuyol/vscode-erb-linter)
130
+ - [**syntax_tree-erb**](https://github.com/davidwessman/syntax_tree-erb)
130
131
 
131
132
  Herb differentiates itself by being HTML-aware from the ground up, providing a unified parsing approach that understands both HTML and ERB as first-class citizens, rather than treating one as embedded within the other.
132
133
 
data/ext/herb/nodes.c CHANGED
@@ -151,8 +151,9 @@ static VALUE rb_html_element_node_from_c_struct(AST_HTML_ELEMENT_NODE_T* html_el
151
151
  VALUE html_element_node_body = rb_nodes_array_from_c_array(html_element_node->body);
152
152
  VALUE html_element_node_close_tag = rb_node_from_c_struct((AST_NODE_T*) html_element_node->close_tag);
153
153
  VALUE html_element_node_is_void = (html_element_node->is_void) ? Qtrue : Qfalse;
154
+ VALUE html_element_node_source = rb_str_new_cstr(element_source_to_string(html_element_node->source));
154
155
 
155
- VALUE args[8] = {
156
+ VALUE args[9] = {
156
157
  type,
157
158
  location,
158
159
  errors,
@@ -160,10 +161,11 @@ static VALUE rb_html_element_node_from_c_struct(AST_HTML_ELEMENT_NODE_T* html_el
160
161
  html_element_node_tag_name,
161
162
  html_element_node_body,
162
163
  html_element_node_close_tag,
163
- html_element_node_is_void
164
+ html_element_node_is_void,
165
+ html_element_node_source
164
166
  };
165
167
 
166
- return rb_class_new_instance(8, args, HTMLElementNode);
168
+ return rb_class_new_instance(9, args, HTMLElementNode);
167
169
  };
168
170
 
169
171
  static VALUE rb_html_attribute_value_node_from_c_struct(AST_HTML_ATTRIBUTE_VALUE_NODE_T* html_attribute_value_node) {
@@ -443,7 +445,7 @@ static VALUE rb_erb_content_node_from_c_struct(AST_ERB_CONTENT_NODE_T* erb_conte
443
445
  VALUE erb_content_node_tag_opening = rb_token_from_c_struct(erb_content_node->tag_opening);
444
446
  VALUE erb_content_node_content = rb_token_from_c_struct(erb_content_node->content);
445
447
  VALUE erb_content_node_tag_closing = rb_token_from_c_struct(erb_content_node->tag_closing);
446
- /* #<Herb::Template::AnalyzedRubyField:0x00007f62e38bbaa8 @name="analyzed_ruby", @options={kind: nil}> */
448
+ /* #<Herb::Template::AnalyzedRubyField:0x00007f1e10166f68 @name="analyzed_ruby", @options={kind: nil}> */
447
449
  VALUE erb_content_node_analyzed_ruby = Qnil;
448
450
  VALUE erb_content_node_parsed = (erb_content_node->parsed) ? Qtrue : Qfalse;
449
451
  VALUE erb_content_node_valid = (erb_content_node->valid) ? Qtrue : Qfalse;
data/lib/herb/3.0/herb.so CHANGED
Binary file
data/lib/herb/3.1/herb.so CHANGED
Binary file
data/lib/herb/3.2/herb.so CHANGED
Binary file
data/lib/herb/3.3/herb.so CHANGED
Binary file
data/lib/herb/3.4/herb.so CHANGED
Binary file
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module Herb
5
+ module AST
6
+ module Helpers
7
+ #: (Herb::AST::Node) -> bool
8
+ def erb_outputs?(node)
9
+ return false unless node.is_a?(Herb::AST::ERBContentNode)
10
+
11
+ opening = node.tag_opening&.value
12
+ opening&.include?("=") && !opening&.start_with?("<%#")
13
+ end
14
+
15
+ #: (String) -> bool
16
+ def erb_comment?(opening)
17
+ opening.start_with?("<%#")
18
+ end
19
+
20
+ #: (String) -> bool
21
+ def erb_output?(opening)
22
+ opening.include?("=")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -269,15 +269,17 @@ module Herb
269
269
  attr_reader :body #: Array[Herb::AST::Node]
270
270
  attr_reader :close_tag #: Herb::AST::HTMLCloseTagNode
271
271
  attr_reader :is_void #: bool
272
+ attr_reader :source #: String
272
273
 
273
- #: (String, Location, Array[Herb::Errors::Error], Herb::AST::HTMLOpenTagNode, Herb::Token, Array[Herb::AST::Node], Herb::AST::HTMLCloseTagNode, bool) -> void
274
- def initialize(type, location, errors, open_tag, tag_name, body, close_tag, is_void)
274
+ #: (String, Location, Array[Herb::Errors::Error], Herb::AST::HTMLOpenTagNode, Herb::Token, Array[Herb::AST::Node], Herb::AST::HTMLCloseTagNode, bool, String) -> void
275
+ def initialize(type, location, errors, open_tag, tag_name, body, close_tag, is_void, source)
275
276
  super(type, location, errors)
276
277
  @open_tag = open_tag
277
278
  @tag_name = tag_name
278
279
  @body = body
279
280
  @close_tag = close_tag
280
281
  @is_void = is_void
282
+ @source = source
281
283
  end
282
284
 
283
285
  #: () -> serialized_html_element_node
@@ -288,6 +290,7 @@ module Herb
288
290
  body: body,
289
291
  close_tag: close_tag,
290
292
  is_void: is_void,
293
+ source: source,
291
294
  }) #: Herb::serialized_html_element_node
292
295
  end
293
296
 
@@ -342,9 +345,10 @@ module Herb
342
345
  else
343
346
  output += "∅\n"
344
347
  end
345
- output += "└── is_void: "
348
+ output += "├── is_void: "
346
349
  output += [true, false].include?(is_void) ? is_void.to_s : "∅"
347
350
  output += "\n"
351
+ output += %(└── source: #{source.inspect}\n)
348
352
  output += "\n"
349
353
 
350
354
  output.gsub(/^/, " " * indent)
data/lib/herb/cli.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  require "optparse"
7
7
 
8
8
  class Herb::CLI
9
- attr_accessor :json, :silent, :no_interactive, :no_log_file, :no_timing, :local
9
+ attr_accessor :json, :silent, :no_interactive, :no_log_file, :no_timing, :local, :escape, :no_escape, :freeze, :debug
10
10
 
11
11
  def initialize(args)
12
12
  @args = args
@@ -86,6 +86,8 @@ class Herb::CLI
86
86
  Commands:
87
87
  bundle exec herb lex [file] Lex a file.
88
88
  bundle exec herb parse [file] Parse a file.
89
+ bundle exec herb compile [file] Compile ERB template to Ruby code.
90
+ bundle exec herb render [file] Compile and render ERB template to final output.
89
91
  bundle exec herb analyze [path] Analyze a project by passing a directory to the root of the project
90
92
  bundle exec herb ruby [file] Extract Ruby from a file.
91
93
  bundle exec herb html [file] Extract HTML from a file.
@@ -110,10 +112,15 @@ class Herb::CLI
110
112
  project.no_interactive = no_interactive
111
113
  project.no_log_file = no_log_file
112
114
  project.no_timing = no_timing
115
+ project.silent = silent
113
116
  has_issues = project.parse!
114
117
  exit(has_issues ? 1 : 0)
115
118
  when "parse"
116
119
  Herb.parse(file_content)
120
+ when "compile"
121
+ compile_template
122
+ when "render"
123
+ render_template
117
124
  when "lex"
118
125
  Herb.lex(file_content)
119
126
  when "ruby"
@@ -191,6 +198,22 @@ class Herb::CLI
191
198
  parser.on("--local", "Use localhost for playground command instead of herb-tools.dev") do
192
199
  self.local = true
193
200
  end
201
+
202
+ parser.on("--escape", "Enable HTML escaping by default (for compile command)") do
203
+ self.escape = true
204
+ end
205
+
206
+ parser.on("--no-escape", "Disable HTML escaping by default (for compile command)") do
207
+ self.no_escape = true
208
+ end
209
+
210
+ parser.on("--freeze", "Add frozen string literal pragma (for compile command)") do
211
+ self.freeze = true
212
+ end
213
+
214
+ parser.on("--debug", "Enable debug mode with ERB expression wrapping (for compile command)") do
215
+ self.debug = true
216
+ end
194
217
  end
195
218
  end
196
219
 
@@ -200,6 +223,140 @@ class Herb::CLI
200
223
 
201
224
  private
202
225
 
226
+ def compile_template
227
+ require_relative "engine"
228
+
229
+ begin
230
+ options = {}
231
+ options[:filename] = @file if @file
232
+ options[:escape] = no_escape ? false : true
233
+ options[:freeze] = true if freeze
234
+
235
+ if debug
236
+ options[:debug] = true
237
+ options[:debug_filename] = @file if @file
238
+ end
239
+
240
+ engine = Herb::Engine.new(file_content, options)
241
+
242
+ if json
243
+ result = {
244
+ success: true,
245
+ source: engine.src,
246
+ filename: engine.filename,
247
+ bufvar: engine.bufvar,
248
+ }
249
+
250
+ puts result.to_json
251
+ elsif silent
252
+ puts "Success"
253
+ else
254
+ puts engine.src
255
+ end
256
+
257
+ exit(0)
258
+ rescue Herb::Engine::CompilationError => e
259
+ if json
260
+ result = {
261
+ success: false,
262
+ error: e.message,
263
+ filename: @file,
264
+ }
265
+ puts result.to_json
266
+ elsif silent
267
+ puts "Failed"
268
+ else
269
+ puts e.message
270
+ end
271
+
272
+ exit(1)
273
+ rescue StandardError => e
274
+ if json
275
+ result = {
276
+ success: false,
277
+ error: "Unexpected error: #{e.class}: #{e.message}",
278
+ filename: @file,
279
+ }
280
+ puts result.to_json
281
+ elsif silent
282
+ puts "Failed"
283
+ else
284
+ puts "Unexpected error: #{e.class}: #{e.message}"
285
+ puts e.backtrace.first(5).join("\n") unless silent
286
+ end
287
+
288
+ exit(1)
289
+ end
290
+ end
291
+
292
+ def render_template
293
+ require_relative "engine"
294
+
295
+ begin
296
+ options = {}
297
+ options[:filename] = @file if @file
298
+ options[:escape] = no_escape ? false : true
299
+ options[:freeze] = true if freeze
300
+
301
+ if debug
302
+ options[:debug] = true
303
+ options[:debug_filename] = @file if @file
304
+ end
305
+
306
+ engine = Herb::Engine.new(file_content, options)
307
+ compiled_code = engine.src
308
+
309
+ rendered_output = eval(compiled_code)
310
+
311
+ if json
312
+ result = {
313
+ success: true,
314
+ output: rendered_output,
315
+ filename: engine.filename,
316
+ }
317
+
318
+ puts result.to_json
319
+ elsif silent
320
+ puts "Success"
321
+ else
322
+ puts rendered_output
323
+ end
324
+
325
+ exit(0)
326
+ rescue Herb::Engine::CompilationError => e
327
+ if json
328
+ result = {
329
+ success: false,
330
+ error: e.message,
331
+ filename: @file,
332
+ }
333
+ puts result.to_json
334
+ elsif silent
335
+ puts "Failed"
336
+ else
337
+ puts e.message
338
+ end
339
+
340
+ exit(1)
341
+ rescue StandardError => e
342
+ if json
343
+ result = {
344
+ success: false,
345
+ error: "Unexpected error: #{e.class}: #{e.message}",
346
+ filename: @file,
347
+ }
348
+ puts result.to_json
349
+ elsif silent
350
+ puts "Failed"
351
+ else
352
+ puts "Unexpected error: #{e.class}: #{e.message}"
353
+ puts e.backtrace.first(5).join("\n") unless silent
354
+ end
355
+
356
+ exit(1)
357
+ end
358
+ end
359
+
203
360
  def print_version
204
361
  puts Herb.version
205
362
  exit(0)