herb 0.9.2-arm-linux-gnu → 0.9.4-arm-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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/config.yml +125 -0
  4. data/ext/herb/error_helpers.c +172 -2
  5. data/ext/herb/extconf.rb +6 -0
  6. data/ext/herb/extension.c +16 -2
  7. data/ext/herb/extension_helpers.c +6 -5
  8. data/ext/herb/extension_helpers.h +4 -4
  9. data/ext/herb/nodes.c +89 -3
  10. data/lib/herb/3.0/herb.so +0 -0
  11. data/lib/herb/3.1/herb.so +0 -0
  12. data/lib/herb/3.2/herb.so +0 -0
  13. data/lib/herb/3.3/herb.so +0 -0
  14. data/lib/herb/3.4/herb.so +0 -0
  15. data/lib/herb/4.0/herb.so +0 -0
  16. data/lib/herb/ast/erb_content_node.rb +32 -0
  17. data/lib/herb/ast/nodes.rb +244 -3
  18. data/lib/herb/cli.rb +12 -2
  19. data/lib/herb/engine/compiler.rb +166 -75
  20. data/lib/herb/engine/validators/security_validator.rb +40 -0
  21. data/lib/herb/engine.rb +3 -0
  22. data/lib/herb/errors.rb +268 -0
  23. data/lib/herb/parser_options.rb +7 -2
  24. data/lib/herb/project.rb +58 -17
  25. data/lib/herb/version.rb +1 -1
  26. data/lib/herb/visitor.rb +82 -0
  27. data/lib/herb.rb +1 -0
  28. data/sig/herb/ast/erb_content_node.rbs +13 -0
  29. data/sig/herb/ast/nodes.rbs +98 -2
  30. data/sig/herb/engine/compiler.rbs +31 -2
  31. data/sig/herb/engine/validators/security_validator.rbs +4 -0
  32. data/sig/herb/engine.rbs +3 -0
  33. data/sig/herb/errors.rbs +122 -0
  34. data/sig/herb/parser_options.rbs +6 -2
  35. data/sig/herb/visitor.rbs +12 -0
  36. data/sig/serialized_ast_errors.rbs +29 -0
  37. data/sig/serialized_ast_nodes.rbs +19 -0
  38. data/src/analyze/action_view/attribute_extraction_helpers.c +420 -91
  39. data/src/analyze/action_view/image_tag.c +87 -0
  40. data/src/analyze/action_view/javascript_include_tag.c +22 -12
  41. data/src/analyze/action_view/registry.c +6 -3
  42. data/src/analyze/action_view/tag.c +19 -2
  43. data/src/analyze/action_view/tag_helper_node_builders.c +105 -36
  44. data/src/analyze/action_view/tag_helpers.c +792 -44
  45. data/src/analyze/analyze.c +167 -13
  46. data/src/analyze/{helpers.c → analyze_helpers.c} +1 -1
  47. data/src/analyze/analyzed_ruby.c +1 -1
  48. data/src/analyze/builders.c +11 -8
  49. data/src/analyze/conditional_elements.c +6 -7
  50. data/src/analyze/conditional_open_tags.c +6 -7
  51. data/src/analyze/control_type.c +4 -2
  52. data/src/analyze/invalid_structures.c +5 -5
  53. data/src/analyze/missing_end.c +2 -2
  54. data/src/analyze/parse_errors.c +47 -6
  55. data/src/analyze/prism_annotate.c +7 -7
  56. data/src/analyze/render_nodes.c +6 -26
  57. data/src/analyze/strict_locals.c +651 -0
  58. data/src/analyze/transform.c +7 -0
  59. data/src/{ast_node.c → ast/ast_node.c} +8 -8
  60. data/src/{ast_nodes.c → ast/ast_nodes.c} +82 -11
  61. data/src/{ast_pretty_print.c → ast/ast_pretty_print.c} +113 -9
  62. data/src/{pretty_print.c → ast/pretty_print.c} +9 -9
  63. data/src/errors.c +398 -8
  64. data/src/extract.c +5 -5
  65. data/src/herb.c +15 -5
  66. data/src/include/analyze/action_view/attribute_extraction_helpers.h +3 -1
  67. data/src/include/analyze/action_view/tag_helper_handler.h +3 -3
  68. data/src/include/analyze/action_view/tag_helper_node_builders.h +34 -5
  69. data/src/include/analyze/action_view/tag_helpers.h +4 -3
  70. data/src/include/analyze/analyze.h +12 -5
  71. data/src/include/analyze/analyzed_ruby.h +2 -2
  72. data/src/include/analyze/builders.h +4 -4
  73. data/src/include/analyze/conditional_elements.h +2 -2
  74. data/src/include/analyze/conditional_open_tags.h +2 -2
  75. data/src/include/analyze/control_type.h +1 -1
  76. data/src/include/analyze/helpers.h +2 -2
  77. data/src/include/analyze/invalid_structures.h +1 -1
  78. data/src/include/analyze/prism_annotate.h +2 -2
  79. data/src/include/analyze/render_nodes.h +1 -1
  80. data/src/include/analyze/strict_locals.h +11 -0
  81. data/src/include/{ast_node.h → ast/ast_node.h} +4 -4
  82. data/src/include/{ast_nodes.h → ast/ast_nodes.h} +38 -14
  83. data/src/include/{ast_pretty_print.h → ast/ast_pretty_print.h} +3 -3
  84. data/src/include/{pretty_print.h → ast/pretty_print.h} +4 -4
  85. data/src/include/errors.h +65 -7
  86. data/src/include/extract.h +2 -2
  87. data/src/include/herb.h +5 -5
  88. data/src/include/{lex_helpers.h → lexer/lex_helpers.h} +5 -5
  89. data/src/include/{lexer.h → lexer/lexer.h} +1 -1
  90. data/src/include/{lexer_peek_helpers.h → lexer/lexer_peek_helpers.h} +2 -2
  91. data/src/include/{lexer_struct.h → lexer/lexer_struct.h} +2 -2
  92. data/src/include/{token.h → lexer/token.h} +3 -3
  93. data/src/include/{token_matchers.h → lexer/token_matchers.h} +1 -1
  94. data/src/include/{token_struct.h → lexer/token_struct.h} +3 -3
  95. data/src/include/{util → lib}/hb_foreach.h +1 -1
  96. data/src/include/{util → lib}/hb_string.h +5 -1
  97. data/src/include/{location.h → location/location.h} +1 -1
  98. data/src/include/parser/dot_notation.h +12 -0
  99. data/src/include/{parser.h → parser/parser.h} +11 -4
  100. data/src/include/{parser_helpers.h → parser/parser_helpers.h} +6 -6
  101. data/src/include/{prism_context.h → prism/prism_context.h} +2 -2
  102. data/src/include/{prism_helpers.h → prism/prism_helpers.h} +6 -6
  103. data/src/include/{html_util.h → util/html_util.h} +1 -1
  104. data/src/include/util/ruby_util.h +9 -0
  105. data/src/include/{utf8.h → util/utf8.h} +1 -1
  106. data/src/include/{util.h → util/util.h} +1 -1
  107. data/src/include/version.h +1 -1
  108. data/src/include/visitor.h +3 -3
  109. data/src/{lexer_peek_helpers.c → lexer/lexer_peek_helpers.c} +3 -3
  110. data/src/{token.c → lexer/token.c} +8 -8
  111. data/src/{token_matchers.c → lexer/token_matchers.c} +2 -2
  112. data/src/lexer.c +6 -6
  113. data/src/{util → lib}/hb_allocator.c +2 -2
  114. data/src/{util → lib}/hb_arena.c +1 -1
  115. data/src/{util → lib}/hb_arena_debug.c +2 -2
  116. data/src/{util → lib}/hb_array.c +2 -2
  117. data/src/{util → lib}/hb_buffer.c +2 -2
  118. data/src/{util → lib}/hb_narray.c +1 -1
  119. data/src/{util → lib}/hb_string.c +2 -2
  120. data/src/{location.c → location/location.c} +2 -2
  121. data/src/{position.c → location/position.c} +2 -2
  122. data/src/{range.c → location/range.c} +1 -1
  123. data/src/main.c +11 -11
  124. data/src/parser/dot_notation.c +100 -0
  125. data/src/{parser_match_tags.c → parser/match_tags.c} +34 -5
  126. data/src/{parser_helpers.c → parser/parser_helpers.c} +10 -10
  127. data/src/parser.c +68 -32
  128. data/src/{prism_helpers.c → prism/prism_helpers.c} +7 -7
  129. data/src/{ruby_parser.c → prism/ruby_parser.c} +1 -1
  130. data/src/{html_util.c → util/html_util.c} +4 -4
  131. data/src/{io.c → util/io.c} +3 -3
  132. data/src/util/ruby_util.c +42 -0
  133. data/src/{utf8.c → util/utf8.c} +2 -2
  134. data/src/{util.c → util/util.c} +4 -4
  135. data/src/visitor.c +35 -3
  136. data/templates/ext/herb/error_helpers.c.erb +2 -2
  137. data/templates/ext/herb/nodes.c.erb +1 -1
  138. data/templates/java/error_helpers.c.erb +1 -1
  139. data/templates/java/error_helpers.h.erb +2 -2
  140. data/templates/java/nodes.c.erb +4 -4
  141. data/templates/java/nodes.h.erb +1 -1
  142. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +4 -4
  143. data/templates/javascript/packages/node/extension/nodes.cpp.erb +4 -4
  144. data/templates/lib/herb/visitor.rb.erb +14 -0
  145. data/templates/src/analyze/missing_end.c.erb +2 -2
  146. data/templates/src/{ast_nodes.c.erb → ast/ast_nodes.c.erb} +9 -9
  147. data/templates/src/{ast_pretty_print.c.erb → ast/ast_pretty_print.c.erb} +8 -8
  148. data/templates/src/errors.c.erb +8 -8
  149. data/templates/src/include/{ast_nodes.h.erb → ast/ast_nodes.h.erb} +11 -12
  150. data/templates/src/include/{ast_pretty_print.h.erb → ast/ast_pretty_print.h.erb} +2 -2
  151. data/templates/src/include/errors.h.erb +7 -7
  152. data/templates/src/{parser_match_tags.c.erb → parser/match_tags.c.erb} +4 -4
  153. data/templates/src/visitor.c.erb +3 -3
  154. data/templates/wasm/error_helpers.cpp.erb +4 -4
  155. data/templates/wasm/nodes.cpp.erb +5 -5
  156. metadata +76 -68
  157. data/src/include/element_source.h +0 -10
  158. /data/src/include/{util → lib}/hb_allocator.h +0 -0
  159. /data/src/include/{util → lib}/hb_arena.h +0 -0
  160. /data/src/include/{util → lib}/hb_arena_debug.h +0 -0
  161. /data/src/include/{util → lib}/hb_array.h +0 -0
  162. /data/src/include/{util → lib}/hb_buffer.h +0 -0
  163. /data/src/include/{util → lib}/hb_narray.h +0 -0
  164. /data/src/include/{util → lib}/string.h +0 -0
  165. /data/src/include/{position.h → location/position.h} +0 -0
  166. /data/src/include/{range.h → location/range.h} +0 -0
  167. /data/src/include/{herb_prism_node.h → prism/herb_prism_node.h} +0 -0
  168. /data/src/include/{prism_serialized.h → prism/prism_serialized.h} +0 -0
  169. /data/src/include/{ruby_parser.h → prism/ruby_parser.h} +0 -0
  170. /data/src/include/{io.h → util/io.h} +0 -0
  171. /data/templates/src/include/{util → lib}/hb_foreach.h.erb +0 -0
data/lib/herb/errors.rb CHANGED
@@ -1258,5 +1258,273 @@ module Herb
1258
1258
  end
1259
1259
  end
1260
1260
 
1261
+ class StrictLocalsPositionalArgumentError < Error
1262
+ include Colors
1263
+
1264
+ #| name: String?,
1265
+ #| }
1266
+
1267
+ attr_reader :name #: String?
1268
+
1269
+ #: (String, Location?, String, String) -> void
1270
+ def initialize(type, location, message, name)
1271
+ super(type, location, message)
1272
+ @name = name
1273
+ end
1274
+
1275
+ #: () -> String
1276
+ def inspect
1277
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1278
+ end
1279
+
1280
+ #: () -> serialized_strict_locals_positional_argument_error
1281
+ def to_hash
1282
+ super.merge(
1283
+ name: name
1284
+ ) #: Herb::serialized_strict_locals_positional_argument_error
1285
+ end
1286
+
1287
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1288
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1289
+ output = +""
1290
+
1291
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1292
+ output += white("├── message: #{green(message.inspect)}\n")
1293
+ output += white("└── name: #{green(name.inspect)}\n")
1294
+ output += %(\n)
1295
+
1296
+ output.gsub(/^/, " " * indent)
1297
+ end
1298
+ end
1299
+
1300
+ class StrictLocalsBlockArgumentError < Error
1301
+ include Colors
1302
+
1303
+ #| name: String?,
1304
+ #| }
1305
+
1306
+ attr_reader :name #: String?
1307
+
1308
+ #: (String, Location?, String, String) -> void
1309
+ def initialize(type, location, message, name)
1310
+ super(type, location, message)
1311
+ @name = name
1312
+ end
1313
+
1314
+ #: () -> String
1315
+ def inspect
1316
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1317
+ end
1318
+
1319
+ #: () -> serialized_strict_locals_block_argument_error
1320
+ def to_hash
1321
+ super.merge(
1322
+ name: name
1323
+ ) #: Herb::serialized_strict_locals_block_argument_error
1324
+ end
1325
+
1326
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1327
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1328
+ output = +""
1329
+
1330
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1331
+ output += white("├── message: #{green(message.inspect)}\n")
1332
+ output += white("└── name: #{green(name.inspect)}\n")
1333
+ output += %(\n)
1334
+
1335
+ output.gsub(/^/, " " * indent)
1336
+ end
1337
+ end
1338
+
1339
+ class StrictLocalsSplatArgumentError < Error
1340
+ include Colors
1341
+
1342
+ #| name: String?,
1343
+ #| }
1344
+
1345
+ attr_reader :name #: String?
1346
+
1347
+ #: (String, Location?, String, String) -> void
1348
+ def initialize(type, location, message, name)
1349
+ super(type, location, message)
1350
+ @name = name
1351
+ end
1352
+
1353
+ #: () -> String
1354
+ def inspect
1355
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1356
+ end
1357
+
1358
+ #: () -> serialized_strict_locals_splat_argument_error
1359
+ def to_hash
1360
+ super.merge(
1361
+ name: name
1362
+ ) #: Herb::serialized_strict_locals_splat_argument_error
1363
+ end
1364
+
1365
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1366
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1367
+ output = +""
1368
+
1369
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1370
+ output += white("├── message: #{green(message.inspect)}\n")
1371
+ output += white("└── name: #{green(name.inspect)}\n")
1372
+ output += %(\n)
1373
+
1374
+ output.gsub(/^/, " " * indent)
1375
+ end
1376
+ end
1377
+
1378
+ class StrictLocalsMissingParenthesisError < Error
1379
+ include Colors
1380
+
1381
+ #| rest: String?,
1382
+ #| }
1383
+
1384
+ attr_reader :rest #: String?
1385
+
1386
+ #: (String, Location?, String, String) -> void
1387
+ def initialize(type, location, message, rest)
1388
+ super(type, location, message)
1389
+ @rest = rest
1390
+ end
1391
+
1392
+ #: () -> String
1393
+ def inspect
1394
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1395
+ end
1396
+
1397
+ #: () -> serialized_strict_locals_missing_parenthesis_error
1398
+ def to_hash
1399
+ super.merge(
1400
+ rest: rest
1401
+ ) #: Herb::serialized_strict_locals_missing_parenthesis_error
1402
+ end
1403
+
1404
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1405
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1406
+ output = +""
1407
+
1408
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1409
+ output += white("├── message: #{green(message.inspect)}\n")
1410
+ output += white("└── rest: #{green(rest.inspect)}\n")
1411
+ output += %(\n)
1412
+
1413
+ output.gsub(/^/, " " * indent)
1414
+ end
1415
+ end
1416
+
1417
+ class StrictLocalsDuplicateDeclarationError < Error
1418
+ include Colors
1419
+
1420
+ #: () -> String
1421
+ def inspect
1422
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1423
+ end
1424
+
1425
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1426
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1427
+ output = +""
1428
+
1429
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1430
+ output += white("└── message: #{green(message.inspect)}\n")
1431
+ output += %(\n)
1432
+
1433
+ output.gsub(/^/, " " * indent)
1434
+ end
1435
+ end
1436
+
1437
+ class VoidElementContentError < Error
1438
+ include Colors
1439
+
1440
+ #| tag_name: Herb::Token?,
1441
+ #| helper_name: String?,
1442
+ #| content_type: String?,
1443
+ #| }
1444
+
1445
+ attr_reader :tag_name #: Herb::Token?
1446
+ attr_reader :helper_name #: String?
1447
+ attr_reader :content_type #: String?
1448
+
1449
+ #: (String, Location?, String, Herb::Token, String, String) -> void
1450
+ def initialize(type, location, message, tag_name, helper_name, content_type)
1451
+ super(type, location, message)
1452
+ @tag_name = tag_name
1453
+ @helper_name = helper_name
1454
+ @content_type = content_type
1455
+ end
1456
+
1457
+ #: () -> String
1458
+ def inspect
1459
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1460
+ end
1461
+
1462
+ #: () -> serialized_void_element_content_error
1463
+ def to_hash
1464
+ super.merge(
1465
+ tag_name: tag_name,
1466
+ helper_name: helper_name,
1467
+ content_type: content_type
1468
+ ) #: Herb::serialized_void_element_content_error
1469
+ end
1470
+
1471
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1472
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1473
+ output = +""
1474
+
1475
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1476
+ output += white("├── message: #{green(message.inspect)}\n")
1477
+ output += white("├── tag_name: ")
1478
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
1479
+ output += "\n"
1480
+ output += white("├── helper_name: #{green(helper_name.inspect)}\n")
1481
+ output += white("└── content_type: #{green(content_type.inspect)}\n")
1482
+ output += %(\n)
1483
+
1484
+ output.gsub(/^/, " " * indent)
1485
+ end
1486
+ end
1487
+
1488
+ class DotNotationCasingError < Error
1489
+ include Colors
1490
+
1491
+ #| segment: Herb::Token?,
1492
+ #| }
1493
+
1494
+ attr_reader :segment #: Herb::Token?
1495
+
1496
+ #: (String, Location?, String, Herb::Token) -> void
1497
+ def initialize(type, location, message, segment)
1498
+ super(type, location, message)
1499
+ @segment = segment
1500
+ end
1501
+
1502
+ #: () -> String
1503
+ def inspect
1504
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1505
+ end
1506
+
1507
+ #: () -> serialized_dot_notation_casing_error
1508
+ def to_hash
1509
+ super.merge(
1510
+ segment: segment
1511
+ ) #: Herb::serialized_dot_notation_casing_error
1512
+ end
1513
+
1514
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1515
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
1516
+ output = +""
1517
+
1518
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
1519
+ output += white("├── message: #{green(message.inspect)}\n")
1520
+ output += white("└── segment: ")
1521
+ output += segment ? segment.tree_inspect : magenta("∅")
1522
+ output += "\n"
1523
+ output += %(\n)
1524
+
1525
+ output.gsub(/^/, " " * indent)
1526
+ end
1527
+ end
1528
+
1261
1529
  end
1262
1530
  end
@@ -7,6 +7,7 @@ module Herb
7
7
  attr_reader :analyze #: bool
8
8
  attr_reader :action_view_helpers #: bool
9
9
  attr_reader :render_nodes #: bool
10
+ attr_reader :strict_locals #: bool
10
11
  attr_reader :prism_program #: bool
11
12
  attr_reader :prism_nodes #: bool
12
13
  attr_reader :prism_nodes_deep #: bool
@@ -16,17 +17,19 @@ module Herb
16
17
  DEFAULT_ANALYZE = true #: bool
17
18
  DEFAULT_ACTION_VIEW_HELPERS = false #: bool
18
19
  DEFAULT_RENDER_NODES = false #: bool
20
+ DEFAULT_STRICT_LOCALS = false #: bool
19
21
  DEFAULT_PRISM_PROGRAM = false #: bool
20
22
  DEFAULT_PRISM_NODES = false #: bool
21
23
  DEFAULT_PRISM_NODES_DEEP = false #: bool
22
24
 
23
- #: (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool) -> void
24
- def initialize(strict: DEFAULT_STRICT, track_whitespace: DEFAULT_TRACK_WHITESPACE, analyze: DEFAULT_ANALYZE, action_view_helpers: DEFAULT_ACTION_VIEW_HELPERS, render_nodes: DEFAULT_RENDER_NODES, prism_nodes: DEFAULT_PRISM_NODES, prism_nodes_deep: DEFAULT_PRISM_NODES_DEEP, prism_program: DEFAULT_PRISM_PROGRAM)
25
+ #: (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?render_nodes: bool, ?strict_locals: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool) -> void
26
+ def initialize(strict: DEFAULT_STRICT, track_whitespace: DEFAULT_TRACK_WHITESPACE, analyze: DEFAULT_ANALYZE, action_view_helpers: DEFAULT_ACTION_VIEW_HELPERS, render_nodes: DEFAULT_RENDER_NODES, strict_locals: DEFAULT_STRICT_LOCALS, prism_nodes: DEFAULT_PRISM_NODES, prism_nodes_deep: DEFAULT_PRISM_NODES_DEEP, prism_program: DEFAULT_PRISM_PROGRAM)
25
27
  @strict = strict
26
28
  @track_whitespace = track_whitespace
27
29
  @analyze = analyze
28
30
  @action_view_helpers = action_view_helpers
29
31
  @render_nodes = render_nodes
32
+ @strict_locals = strict_locals
30
33
  @prism_nodes = prism_nodes
31
34
  @prism_nodes_deep = prism_nodes_deep
32
35
  @prism_program = prism_program
@@ -40,6 +43,7 @@ module Herb
40
43
  analyze: @analyze,
41
44
  action_view_helpers: @action_view_helpers,
42
45
  render_nodes: @render_nodes,
46
+ strict_locals: @strict_locals,
43
47
  prism_nodes: @prism_nodes,
44
48
  prism_nodes_deep: @prism_nodes_deep,
45
49
  prism_program: @prism_program,
@@ -54,6 +58,7 @@ module Herb
54
58
  "analyze=#{@analyze}\n " \
55
59
  "action_view_helpers=#{@action_view_helpers}\n " \
56
60
  "render_nodes=#{@render_nodes}\n " \
61
+ "strict_locals=#{@strict_locals}\n " \
57
62
  "prism_nodes=#{@prism_nodes}\n " \
58
63
  "prism_nodes_deep=#{@prism_nodes_deep}\n " \
59
64
  "prism_program=#{@prism_program}>"
data/lib/herb/project.rb CHANGED
@@ -71,9 +71,9 @@ module Herb
71
71
  attr_reader :successful, :failed, :timeout, :template_error, :unexpected_error,
72
72
  :strict_parse_error, :analyze_parse_error,
73
73
  :validation_error, :compilation_failed, :strict_compilation_failed,
74
- :invalid_ruby,
74
+ :invalid_ruby, :skipped,
75
75
  :error_outputs, :file_contents, :parse_errors, :compilation_errors,
76
- :file_diagnostics
76
+ :file_diagnostics, :skip_reasons
77
77
 
78
78
  def initialize
79
79
  @successful = []
@@ -87,11 +87,13 @@ module Herb
87
87
  @compilation_failed = []
88
88
  @strict_compilation_failed = []
89
89
  @invalid_ruby = []
90
+ @skipped = []
90
91
  @error_outputs = {}
91
92
  @file_contents = {}
92
93
  @parse_errors = {}
93
94
  @compilation_errors = {}
94
95
  @file_diagnostics = {}
96
+ @skip_reasons = {}
95
97
  end
96
98
 
97
99
  def problem_files
@@ -432,8 +434,7 @@ module Herb
432
434
  nil
433
435
  end
434
436
 
435
- { file_path: file_path, status: :timeout, file_content: file_content,
436
- log: "⏱️ Parsing #{file_path} timed out after 1 second" }
437
+ { file_path: file_path, status: :timeout, file_content: file_content, log: "⏱️ Parsing #{file_path} timed out after 1 second" }
437
438
  rescue StandardError => e
438
439
  file_content ||= begin
439
440
  File.read(file_path)
@@ -441,8 +442,7 @@ module Herb
441
442
  nil
442
443
  end
443
444
 
444
- { file_path: file_path, status: :failed, file_content: file_content,
445
- log: "⚠️ Error processing #{file_path}: #{e.message}" }
445
+ { file_path: file_path, status: :failed, file_content: file_content, log: "⚠️ Error processing #{file_path}: #{e.message}" }
446
446
  ensure
447
447
  [stdout_file, stderr_file].each do |tempfile|
448
448
  next unless tempfile
@@ -488,6 +488,9 @@ module Herb
488
488
  Herb::Engine.new(file_content, filename: file_path, escape: true, validate_ruby: validate_ruby)
489
489
 
490
490
  { status: :successful, log: "✅ Compiled #{file_path} successfully" }
491
+ rescue Herb::Engine::GeneratorTemplateError => e
492
+ { status: :skipped, skip_reason: e.message,
493
+ log: "⊘ Skipping #{file_path}: #{e.message}" }
491
494
  rescue Herb::Engine::InvalidRubyError => e
492
495
  { status: :invalid_ruby, file_content: file_content,
493
496
  compilation_error: { error: e.message, backtrace: e.backtrace&.first(10) || [] },
@@ -545,6 +548,7 @@ module Herb
545
548
  tracker.parse_errors[file_path] = result[:parse_error] if result[:parse_error]
546
549
  tracker.compilation_errors[file_path] = result[:compilation_error] if result[:compilation_error]
547
550
  tracker.file_diagnostics[file_path] = result[:diagnostics] if result[:diagnostics]&.any?
551
+ tracker.skip_reasons[file_path] = result[:skip_reason] if result[:skip_reason]
548
552
  end
549
553
 
550
554
  def print_summary(results, log, duration)
@@ -563,13 +567,18 @@ module Herb
563
567
  puts " #{label("Checked")} #{cyan("#{total} #{pluralize(total, "file")}")}"
564
568
 
565
569
  if total > 1
566
- files_line = if issues.positive?
567
- "#{bold(green("#{passed} clean"))} | #{bold(red("#{issues} with issues"))}"
568
- else
569
- bold(green("#{total} clean"))
570
- end
570
+ files_parts = []
571
571
 
572
- puts " #{label("Files")} #{files_line}"
572
+ if issues.positive?
573
+ files_parts << bold(green("#{passed} clean"))
574
+ files_parts << bold(red("#{issues} with issues"))
575
+ else
576
+ files_parts << bold(green("#{total - results.skipped.count} clean"))
577
+ end
578
+
579
+ files_parts << dimmed("#{results.skipped.count} skipped") if results.skipped.any?
580
+
581
+ puts " #{label("Files")} #{files_parts.join(" | ")}"
573
582
  end
574
583
 
575
584
  parser_parts = []
@@ -581,8 +590,9 @@ module Herb
581
590
  parser_parts << stat(results.analyze_parse_error.count, "analyze", :yellow) if results.analyze_parse_error.any?
582
591
  puts " #{label("Parser")} #{parser_parts.join(" | ")}"
583
592
 
584
- skipped = total - passed - results.validation_error.count - results.compilation_failed.count -
585
- results.strict_compilation_failed.count - results.invalid_ruby.count
593
+ not_compiled = total - passed - results.skipped.count - results.validation_error.count -
594
+ results.compilation_failed.count - results.strict_compilation_failed.count -
595
+ results.invalid_ruby.count
586
596
 
587
597
  engine_parts = []
588
598
  engine_parts << stat(passed, "compiled", :green)
@@ -590,13 +600,17 @@ module Herb
590
600
  engine_parts << stat(results.compilation_failed.count, "compilation", :red) if results.compilation_failed.any?
591
601
  engine_parts << stat(results.strict_compilation_failed.count, "strict", :yellow) if results.strict_compilation_failed.any?
592
602
  engine_parts << stat(results.invalid_ruby.count, "produced invalid Ruby", :red) if results.invalid_ruby.any?
593
- engine_parts << dimmed("#{skipped} skipped") if skipped.positive?
603
+ engine_parts << dimmed("#{not_compiled} not compiled") if not_compiled.positive?
594
604
  puts " #{label("Engine")} #{engine_parts.join(" | ")}"
595
605
 
596
606
  if results.timeout.any?
597
607
  puts " #{label("Timeout")} #{stat(results.timeout.count, "timed out", :yellow)}"
598
608
  end
599
609
 
610
+ if results.skipped.any?
611
+ puts " #{label("Skipped")} #{dimmed("#{results.skipped.count} #{pluralize(results.skipped.count, "file")}")}"
612
+ end
613
+
600
614
  if duration
601
615
  puts " #{label("Duration")} #{cyan(format_duration(duration))}"
602
616
  end
@@ -630,6 +644,7 @@ module Herb
630
644
  log.puts ""
631
645
  log.puts "--- Other ---"
632
646
  log.puts "⏱️ Timed out: #{results.timeout.count} (#{percentage(results.timeout.count, total)}%)"
647
+ log.puts "⊘ Skipped: #{results.skipped.count} (#{percentage(results.skipped.count, total)}%)"
633
648
 
634
649
  return unless duration
635
650
 
@@ -639,10 +654,27 @@ module Herb
639
654
  def print_file_lists(results, log)
640
655
  log_file_lists(results, log)
641
656
 
642
- return unless results.problem_files.any?
643
-
644
657
  printed_section = false
645
658
 
659
+ if results.skipped.any?
660
+ printed_section = true
661
+
662
+ puts "\n"
663
+ puts " #{bold("Skipped files:")}"
664
+ puts " #{dimmed("These files were parsed successfully but skipped for compilation by the engine.")}"
665
+
666
+ results.skipped.each do |file|
667
+ relative = relative_path(file)
668
+ reason = results.skip_reasons[file]
669
+
670
+ puts ""
671
+ puts " #{cyan(relative)}:"
672
+ puts " #{dimmed("⊘")} #{dimmed(reason)}"
673
+ end
674
+ end
675
+
676
+ return unless results.problem_files.any?
677
+
646
678
  ISSUE_TYPES.each do |type|
647
679
  file_list = results.send(type[:key])
648
680
  next unless file_list.any?
@@ -682,6 +714,15 @@ module Herb
682
714
  end
683
715
 
684
716
  def log_file_lists(results, log)
717
+ if results.skipped.any?
718
+ log.puts "\n#{heading("Files: Skipped")}"
719
+
720
+ results.skipped.each do |file|
721
+ reason = results.skip_reasons[file]
722
+ log.puts "#{file} - #{reason}"
723
+ end
724
+ end
725
+
685
726
  ISSUE_TYPES.each do |type|
686
727
  file_list = results.send(type[:key])
687
728
  next unless file_list.any?
data/lib/herb/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # typed: true
3
3
 
4
4
  module Herb
5
- VERSION = "0.9.2"
5
+ VERSION = "0.9.4"
6
6
  end