diff --git a/Gemfile.lock b/Gemfile.lock index 1299828d3..9f8e00dce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,9 +5,9 @@ PATH activesupport (>= 6.0) ast benchmark - better_html bundler constant_resolver (>= 0.3) + herb parallel (< 2) parser prism (>= 1.4.0) @@ -50,13 +50,6 @@ GEM ast (2.4.3) base64 (0.3.0) benchmark (0.5.0) - better_html (2.1.1) - actionview (>= 6.0) - activesupport (>= 6.0) - ast (~> 2.0) - erubi (~> 1.4) - parser (>= 2.4) - smart_properties bigdecimal (4.1.2) builder (3.3.0) byebug (11.1.3) @@ -70,6 +63,10 @@ GEM erb (4.0.4.1) cgi (>= 0.3.3) erubi (1.13.1) + herb (0.10.1-aarch64-linux-gnu) + herb (0.10.1-arm64-darwin) + herb (0.10.1-x86_64-darwin) + herb (0.10.1-x86_64-linux-gnu) i18n (1.14.8) concurrent-ruby (~> 1.0) io-console (0.8.0) @@ -185,7 +182,6 @@ GEM rubydex (0.2.0-x86_64-darwin) rubydex (0.2.0-x86_64-linux) securerandom (0.4.1) - smart_properties (1.17.0) sorbet (0.6.13184) sorbet-static (= 0.6.13184) sorbet-runtime (0.6.13184) diff --git a/lib/packwerk/parsers/erb.rb b/lib/packwerk/parsers/erb.rb index 52f50404f..6a8555a1c 100644 --- a/lib/packwerk/parsers/erb.rb +++ b/lib/packwerk/parsers/erb.rb @@ -1,9 +1,7 @@ # typed: strict # frozen_string_literal: true -require "ast/node" -require "better_html" -require "better_html/parser" +require "herb" require "parser/source/buffer" module Packwerk @@ -11,9 +9,8 @@ module Parsers class Erb include ParserInterface - #: (?parser_class: untyped, ?ruby_parser: Ruby) -> void - def initialize(parser_class: BetterHtml::Parser, ruby_parser: Ruby.new) - @parser_class = parser_class #: singleton(BetterHtml::Parser) + #: (?ruby_parser: Ruby) -> void + def initialize(ruby_parser: Ruby.new) @ruby_parser = ruby_parser end @@ -25,53 +22,16 @@ def call(io:, file_path: "") parse_buffer(buffer, file_path: file_path) end + # `Herb.extract_ruby` returns the Ruby parts of the ERB source with whitespace padding + # so character positions match the original file — that gives Packwerk's downstream + # reference offenses accurate line/column info in ERB templates. #: (Parser::Source::Buffer buffer, file_path: String) -> AST::Node? def parse_buffer(buffer, file_path:) - parser = @parser_class.new(buffer, template_language: :html) - to_ruby_ast(parser.ast, file_path) + ruby_source = Herb.extract_ruby(buffer.source) + @ruby_parser.call(io: StringIO.new(ruby_source), file_path: file_path) rescue EncodingError => e result = ParseResult.new(file: file_path, message: e.message) raise Parsers::ParseError, result - rescue Parser::SyntaxError => e - result = ParseResult.new(file: file_path, message: "Syntax error: #{e}") - raise Parsers::ParseError, result - end - - private - - #: ((::AST::Node & Object) erb_ast, String file_path) -> ::AST::Node? - def to_ruby_ast(erb_ast, file_path) - # Note that we're not using the source location (line/column) at the moment, but if we did - # care about that, we'd need to tweak this to insert empty lines and spaces so that things - # line up with the ERB file - nodes = code_nodes(erb_ast) #: as !nil - code_pieces = nodes.map do |node| - node #: as ::AST::Node - .children.first - end - - @ruby_parser.call( - io: StringIO.new(code_pieces.join("\n")), - file_path: file_path, - ) - end - - #: ((::AST::Node | String)? node) ?{ (::AST::Node arg0) -> void } -> (Enumerator[::AST::Node] | Array[String])? - def code_nodes(node, &block) - return enum_for(:code_nodes, node) unless block - return unless node.is_a?(::AST::Node) - - yield node if node.type == :code - - # Skip descending into an ERB comment node, which may contain code nodes - if node.type == :erb - first_child = node.children.first - return if first_child&.type == :indicator && first_child&.children&.first == "#" - end - - node.children.each do |child| - code_nodes(child, &block) - end end end end diff --git a/packwerk.gemspec b/packwerk.gemspec index 2104d8ea0..a95ad9266 100644 --- a/packwerk.gemspec +++ b/packwerk.gemspec @@ -51,5 +51,5 @@ Gem::Specification.new do |spec| spec.add_dependency("prism", ">= 1.4.0") # For ERB parsing - spec.add_dependency("better_html") + spec.add_dependency("herb") end diff --git a/sorbet/rbi/gems/better_html@2.1.1.rbi b/sorbet/rbi/gems/better_html@2.1.1.rbi deleted file mode 100644 index 984d10b84..000000000 --- a/sorbet/rbi/gems/better_html@2.1.1.rbi +++ /dev/null @@ -1,529 +0,0 @@ -# typed: true - -# DO NOT EDIT MANUALLY -# This is an autogenerated file for types exported from the `better_html` gem. -# Please instead update this file by running `bin/tapioca gem better_html`. - -# source://better_html//lib/better_html.rb#7 -module BetterHtml - class << self - # source://better_html//lib/better_html.rb#11 - def config; end - - # Sets the attribute config - # - # @param value the value to set the attribute config to. - # - # source://better_html//lib/better_html.rb#9 - def config=(_arg0); end - - # @yield [config] - # - # source://better_html//lib/better_html.rb#15 - def configure; end - end -end - -# source://better_html//lib/better_html/ast/iterator.rb#7 -module BetterHtml::AST; end - -# source://better_html//lib/better_html/ast/iterator.rb#8 -class BetterHtml::AST::Iterator - # @return [Iterator] a new instance of Iterator - # - # source://better_html//lib/better_html/ast/iterator.rb#18 - def initialize(types, &block); end - - # source://better_html//lib/better_html/ast/iterator.rb#23 - def traverse(node); end - - # source://better_html//lib/better_html/ast/iterator.rb#30 - def traverse_all(nodes); end - - class << self - # source://better_html//lib/better_html/ast/iterator.rb#10 - def descendants(root_node, type); end - end -end - -# source://better_html//lib/better_html/ast/node.rb#8 -class BetterHtml::AST::Node < ::AST::Node - # source://better_html//lib/better_html/ast/node.rb#11 - def descendants(*types); end - - # Returns the value of attribute loc. - # - # source://better_html//lib/better_html/ast/node.rb#9 - def loc; end - - # source://better_html//lib/better_html/ast/node.rb#15 - def location; end -end - -# source://better_html//lib/better_html/config.rb#6 -class BetterHtml::Config - include ::SmartProperties - extend ::SmartProperties::ClassMethods - - # @return [Boolean] - # - # source://better_html//lib/better_html/config.rb#20 - def javascript_attribute_name?(name); end - - # @return [Boolean] - # - # source://better_html//lib/better_html/config.rb#28 - def javascript_safe_method?(name); end - - # @return [Boolean] - # - # source://better_html//lib/better_html/config.rb#24 - def lodash_safe_javascript_expression?(code); end -end - -# source://better_html//lib/better_html/errors.rb#8 -class BetterHtml::DontInterpolateHere < ::BetterHtml::InterpolatorError; end - -# source://better_html//lib/better_html/errors.rb#12 -class BetterHtml::Errors < ::Array - def add(_arg0); end -end - -# source://better_html//lib/better_html/helpers.rb#4 -module BetterHtml::Helpers - # source://better_html//lib/better_html/helpers.rb#5 - def html_attributes(args); end -end - -# source://better_html//lib/better_html/html_attributes.rb#4 -class BetterHtml::HtmlAttributes - # @return [HtmlAttributes] a new instance of HtmlAttributes - # - # source://better_html//lib/better_html/html_attributes.rb#5 - def initialize(data); end - - # source://better_html//lib/better_html/html_attributes.rb#9 - def to_s; end -end - -# source://better_html//lib/better_html/errors.rb#10 -class BetterHtml::HtmlError < ::RuntimeError; end - -# source://better_html//lib/better_html/errors.rb#7 -class BetterHtml::InterpolatorError < ::RuntimeError; end - -# source://better_html//lib/better_html/parser.rb#13 -class BetterHtml::Parser - # @raise [ArgumentError] - # @return [Parser] a new instance of Parser - # - # source://better_html//lib/better_html/parser.rb#26 - def initialize(buffer, template_language: T.unsafe(nil)); end - - # source://better_html//lib/better_html/parser.rb#48 - def ast; end - - # source://better_html//lib/better_html/parser.rb#61 - def inspect; end - - # source://better_html//lib/better_html/parser.rb#43 - def nodes_with_type(*type); end - - # source://better_html//lib/better_html/parser.rb#52 - def parser_errors; end - - # Returns the value of attribute template_language. - # - # source://better_html//lib/better_html/parser.rb#14 - def template_language; end - - private - - # source://better_html//lib/better_html/parser.rb#180 - def build_attribute_name_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#170 - def build_attribute_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#185 - def build_attribute_value_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#115 - def build_cdata_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#120 - def build_comment_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#69 - def build_document_node; end - - # source://better_html//lib/better_html/parser.rb#91 - def build_erb_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#249 - def build_interpolation_node(tokens); end - - # @raise [ArgumentError] - # - # source://better_html//lib/better_html/parser.rb#210 - def build_location(enumerable); end - - # source://better_html//lib/better_html/parser.rb#104 - def build_lodash_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#165 - def build_nameless_attribute_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#202 - def build_node(type, tokens, pre: T.unsafe(nil), post: T.unsafe(nil)); end - - # source://better_html//lib/better_html/parser.rb#145 - def build_tag_attributes_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#140 - def build_tag_name_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#125 - def build_tag_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#197 - def build_text_node(tokens); end - - # source://better_html//lib/better_html/parser.rb#217 - def empty_location; end - - # source://better_html//lib/better_html/parser.rb#221 - def shift_all(tokens, *types); end - - # source://better_html//lib/better_html/parser.rb#259 - def shift_all_with_interpolation(tokens, *types); end - - # source://better_html//lib/better_html/parser.rb#284 - def shift_between(tokens, start_type, end_type); end - - # source://better_html//lib/better_html/parser.rb#292 - def shift_between_with_interpolation(tokens, start_type, end_type); end - - # source://better_html//lib/better_html/parser.rb#233 - def shift_single(tokens, *types); end - - # source://better_html//lib/better_html/parser.rb#237 - def shift_until(tokens, *types); end - - # source://better_html//lib/better_html/parser.rb#272 - def shift_until_with_interpolation(tokens, *types); end - - # source://better_html//lib/better_html/parser.rb#300 - def wrap_token(object); end - - # source://better_html//lib/better_html/parser.rb#322 - def wrap_tokens(enumerable); end -end - -# source://better_html//lib/better_html/parser.rb#16 -class BetterHtml::Parser::Error < ::BetterHtml::HtmlError - # @return [Error] a new instance of Error - # - # source://better_html//lib/better_html/parser.rb#20 - def initialize(message, location:); end - - # Returns the value of attribute location. - # - # source://better_html//lib/better_html/parser.rb#17 - def loc; end - - # Returns the value of attribute location. - # - # source://better_html//lib/better_html/parser.rb#17 - def location; end -end - -# source://better_html//lib/better_html/parser.rb#67 -BetterHtml::Parser::INTERPOLATION_TYPES = T.let(T.unsafe(nil), Array) - -# source://better_html//lib/better_html/errors.rb#16 -class BetterHtml::ParserError < ::RuntimeError - # @return [ParserError] a new instance of ParserError - # - # source://better_html//lib/better_html/errors.rb#19 - def initialize(message, position, line, column); end - - # Returns the value of attribute column. - # - # source://better_html//lib/better_html/errors.rb#17 - def column; end - - # Returns the value of attribute line. - # - # source://better_html//lib/better_html/errors.rb#17 - def line; end - - # Returns the value of attribute position. - # - # source://better_html//lib/better_html/errors.rb#17 - def position; end -end - -# source://better_html//lib/better_html/tokenizer/token.rb#4 -module BetterHtml::Tokenizer; end - -# source://better_html//lib/better_html/tokenizer/base_erb.rb#10 -class BetterHtml::Tokenizer::BaseErb < ::Erubi::Engine - # @raise [ArgumentError] - # @return [BaseErb] a new instance of BaseErb - # - # source://better_html//lib/better_html/tokenizer/base_erb.rb#18 - def initialize(buffer); end - - # Returns the value of attribute current_position. - # - # source://better_html//lib/better_html/tokenizer/base_erb.rb#16 - def current_position; end - - # Returns the value of attribute tokens. - # - # source://better_html//lib/better_html/tokenizer/base_erb.rb#15 - def tokens; end - - private - - # source://better_html//lib/better_html/tokenizer/base_erb.rb#34 - def add_code(code); end - - # source://better_html//lib/better_html/tokenizer/base_erb.rb#53 - def add_erb_tokens(ltrim, indicator, code, rtrim); end - - # source://better_html//lib/better_html/tokenizer/base_erb.rb#47 - def add_expression(indicator, code); end - - # source://better_html//lib/better_html/tokenizer/base_erb.rb#80 - def add_token(type, begin_pos, end_pos); end - - # source://better_html//lib/better_html/tokenizer/base_erb.rb#30 - def append(text); end -end - -# source://better_html//lib/better_html/tokenizer/base_erb.rb#13 -BetterHtml::Tokenizer::BaseErb::EXPR_TRIM_MATCHER = T.let(T.unsafe(nil), Regexp) - -# source://better_html//lib/better_html/tokenizer/base_erb.rb#11 -BetterHtml::Tokenizer::BaseErb::REGEXP_WITHOUT_TRIM = T.let(T.unsafe(nil), Regexp) - -# source://better_html//lib/better_html/tokenizer/base_erb.rb#12 -BetterHtml::Tokenizer::BaseErb::STMT_TRIM_MATCHER = T.let(T.unsafe(nil), Regexp) - -# source://better_html//lib/better_html/tokenizer/html_erb.rb#7 -class BetterHtml::Tokenizer::HtmlErb < ::BetterHtml::Tokenizer::BaseErb - # @return [HtmlErb] a new instance of HtmlErb - # - # source://better_html//lib/better_html/tokenizer/html_erb.rb#10 - def initialize(buffer); end - - # source://better_html//lib/better_html/tokenizer/html_erb.rb#15 - def current_position; end - - # Returns the value of attribute parser. - # - # source://better_html//lib/better_html/tokenizer/html_erb.rb#8 - def parser; end - - private - - # source://better_html//lib/better_html/tokenizer/html_erb.rb#25 - def add_text(text); end - - # source://better_html//lib/better_html/tokenizer/html_erb.rb#21 - def append(text); end -end - -# source://better_html//lib/better_html/tokenizer/html_lodash.rb#9 -class BetterHtml::Tokenizer::HtmlLodash - # @return [HtmlLodash] a new instance of HtmlLodash - # - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#18 - def initialize(buffer); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_escape; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_escape=(val); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_evaluate; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_evaluate=(val); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_interpolate; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_interpolate=(val); end - - # Returns the value of attribute parser. - # - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#11 - def parser; end - - # Returns the value of attribute tokens. - # - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#10 - def tokens; end - - private - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#79 - def add_lodash_tokens(indicator, code); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#73 - def add_text(text); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#96 - def add_token(type, begin_pos: T.unsafe(nil), end_pos: T.unsafe(nil)); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#28 - def scan!; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#62 - def scan_pattern; end - - class << self - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_escape; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_escape=(val); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_evaluate; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_evaluate=(val); end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_interpolate; end - - # source://better_html//lib/better_html/tokenizer/html_lodash.rb#13 - def lodash_interpolate=(val); end - end -end - -# source://better_html//lib/better_html/tokenizer/javascript_erb.rb#7 -class BetterHtml::Tokenizer::JavascriptErb < ::BetterHtml::Tokenizer::BaseErb - private - - # source://better_html//lib/better_html/tokenizer/javascript_erb.rb#10 - def add_text(text); end -end - -# source://better_html//lib/better_html/tokenizer/location.rb#8 -class BetterHtml::Tokenizer::Location < ::Parser::Source::Range - # @raise [ArgumentError] - # @return [Location] a new instance of Location - # - # source://better_html//lib/better_html/tokenizer/location.rb#9 - def initialize(buffer, begin_pos, end_pos); end - - # source://better_html//lib/better_html/tokenizer/location.rb#50 - def adjust(begin_pos: T.unsafe(nil), end_pos: T.unsafe(nil)); end - - # source://better_html//lib/better_html/tokenizer/location.rb#62 - def begin; end - - # source://better_html//lib/better_html/tokenizer/location.rb#66 - def end; end - - # source://better_html//lib/better_html/tokenizer/location.rb#30 - def line_range; end - - # source://better_html//lib/better_html/tokenizer/location.rb#39 - def line_source_with_underline; end - - # source://better_html//lib/better_html/tokenizer/location.rb#58 - def offset(offset); end - - # source://better_html//lib/better_html/tokenizer/location.rb#26 - def range; end - - # source://better_html//lib/better_html/tokenizer/location.rb#54 - def resize(new_size); end - - # source://parser/3.3.3.0/lib/parser/source/range.rb#92 - def start_column; end - - # source://parser/3.3.3.0/lib/parser/source/range.rb#83 - def start_line; end - - # source://parser/3.3.3.0/lib/parser/source/range.rb#106 - def stop_column; end - - # source://parser/3.3.3.0/lib/parser/source/range.rb#99 - def stop_line; end - - # source://better_html//lib/better_html/tokenizer/location.rb#46 - def with(begin_pos: T.unsafe(nil), end_pos: T.unsafe(nil)); end -end - -# source://better_html//lib/better_html/tokenizer/token.rb#5 -class BetterHtml::Tokenizer::Token - # @return [Token] a new instance of Token - # - # source://better_html//lib/better_html/tokenizer/token.rb#8 - def initialize(type:, loc:); end - - # source://better_html//lib/better_html/tokenizer/token.rb#13 - def inspect; end - - # Returns the value of attribute loc. - # - # source://better_html//lib/better_html/tokenizer/token.rb#6 - def loc; end - - # Returns the value of attribute type. - # - # source://better_html//lib/better_html/tokenizer/token.rb#6 - def type; end -end - -# source://better_html//lib/better_html/tokenizer/token_array.rb#5 -class BetterHtml::Tokenizer::TokenArray - # @return [TokenArray] a new instance of TokenArray - # - # source://better_html//lib/better_html/tokenizer/token_array.rb#6 - def initialize(list); end - - # @return [Boolean] - # - # source://better_html//lib/better_html/tokenizer/token_array.rb#37 - def any?; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#41 - def current; end - - # @return [Boolean] - # - # source://better_html//lib/better_html/tokenizer/token_array.rb#33 - def empty?; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#45 - def last; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#20 - def pop; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#12 - def shift; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#49 - def size; end - - # source://better_html//lib/better_html/tokenizer/token_array.rb#28 - def trim(type); end -end - -# source://better_html//lib/better_html/errors.rb#9 -class BetterHtml::UnsafeHtmlError < ::BetterHtml::InterpolatorError; end - -# source://better_html//lib/better_html/version.rb#4 -BetterHtml::VERSION = T.let(T.unsafe(nil), String) diff --git a/sorbet/rbi/shims/herb.rbi b/sorbet/rbi/shims/herb.rbi new file mode 100644 index 000000000..585343aac --- /dev/null +++ b/sorbet/rbi/shims/herb.rbi @@ -0,0 +1,8 @@ +# typed: strict + +module Herb + class << self + #: (String source, ?semicolons: bool, ?comments: bool, ?preserve_positions: bool) -> String + def extract_ruby(source, semicolons: true, comments: false, preserve_positions: true); end + end +end diff --git a/sorbet/tapioca/require.rb b/sorbet/tapioca/require.rb index b9ad7f270..102c00c10 100644 --- a/sorbet/tapioca/require.rb +++ b/sorbet/tapioca/require.rb @@ -7,9 +7,8 @@ require "ast" require "ast/node" require "benchmark" -require "better_html" -require "better_html/parser" require "constant_resolver" +require "herb" require "minitest/autorun" require "mocha/minitest" require "parallel" diff --git a/test/unit/packwerk/parsers/erb_test.rb b/test/unit/packwerk/parsers/erb_test.rb index 1b29dfe64..097c6de93 100644 --- a/test/unit/packwerk/parsers/erb_test.rb +++ b/test/unit/packwerk/parsers/erb_test.rb @@ -1,16 +1,11 @@ # typed: true # frozen_string_literal: true -# TODO: make better_html not require Rails -require "rails/railtie" - require "test_helper" module Packwerk module Parsers class ErbTest < Minitest::Test - include TypedMock - test "#call returns node with valid file" do node = File.open(fixture_path("valid.erb"), "r") do |fixture| Erb.new.call(io: fixture) @@ -19,54 +14,40 @@ class ErbTest < Minitest::Test assert_kind_of(::AST::Node, node) end - test "#call returns node with valid javascript file" do + test "#call returns nil when the ERB contains no Ruby" do node = File.open(fixture_path("javascript_valid.erb"), "r") do |fixture| Erb.new.call(io: fixture) end - assert_kind_of(NilClass, node) + assert_nil(node) end - test "#call writes parse error to stdout" do - error_message = "stub error" - err = Parser::SyntaxError.new(stub(message: error_message)) - parser = stub - parser.stubs(:ast).raises(err) - - parser_class_stub = typed_mock(new: parser) - - parser = Erb.new(parser_class: parser_class_stub) + test "#call raises ParseError with the file path when the embedded Ruby has a syntax error" do file_path = fixture_path("invalid.erb") exc = assert_raises(Parsers::ParseError) do File.open(file_path, "r") do |fixture| - parser.call(io: fixture, file_path: file_path) + Erb.new.call(io: fixture, file_path: file_path) end end - assert_equal("Syntax error: stub error", exc.result.message) + assert_match(/Syntax error/, exc.result.message) assert_equal(file_path, exc.result.file) end - test "#call writes encoding error to stdout" do - error_message = "stub error" - err = EncodingError.new(error_message) - parser = stub - parser.stubs(:ast).raises(err) + test "#call wraps an EncodingError as a ParseError with the file path" do + Herb.stubs(:extract_ruby).raises(EncodingError, "stub error") - parser_class_stub = typed_mock(new: parser) - - parser = Erb.new(parser_class: parser_class_stub) - file_path = fixture_path("invalid.erb") + file_path = fixture_path("valid.erb") exc = assert_raises(Parsers::ParseError) do File.open(file_path, "r") do |fixture| - parser.call(io: fixture, file_path: file_path) + Erb.new.call(io: fixture, file_path: file_path) end end assert_equal("stub error", exc.result.message) - assert_equal(file_path.to_s, exc.result.file) + assert_equal(file_path, exc.result.file) end private diff --git a/test/unit/packwerk/parsers/factory_test.rb b/test/unit/packwerk/parsers/factory_test.rb index 962f193fa..c1d900468 100644 --- a/test/unit/packwerk/parsers/factory_test.rb +++ b/test/unit/packwerk/parsers/factory_test.rb @@ -1,9 +1,6 @@ # typed: true # frozen_string_literal: true -# TODO: make better_html not require Rails -require "rails/railtie" - require "test_helper" module Packwerk