Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ describe("ParserNoErrorsRule", () => {
})

test("should report Ruby parse errors in ERB tags", () => {
expectError("expect_expression_after_operator: unexpected ';'; expected an expression after the operator (`RUBY_PARSE_ERROR`)")
expectError("expect_expression_after_operator: unexpected end-of-input; expected an expression after the operator (`RUBY_PARSE_ERROR`)")
expectError("unexpected_token_close_context: unexpected end-of-input, assuming it is closing the parent top level context (`RUBY_PARSE_ERROR`)")
assertOffenses(`<%= 1 + %>`)
})

Expand Down
41 changes: 37 additions & 4 deletions src/extract.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
void herb_extract_ruby_to_buffer_with_semicolons(const char* source, hb_buffer_T* output) {
hb_array_T* tokens = herb_lex(source);
bool skip_erb_content = false;
bool is_comment_tag = false;

for (size_t i = 0; i < hb_array_size(tokens); i++) {
const token_T* token = hb_array_get(tokens, i);
Expand All @@ -21,8 +22,15 @@ void herb_extract_ruby_to_buffer_with_semicolons(const char* source, hb_buffer_T
}

case TOKEN_ERB_START: {
if (strcmp(token->value, "<%#") == 0 || strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
if (strcmp(token->value, "<%#") == 0) {
skip_erb_content = true;
is_comment_tag = true;
} else if (strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
skip_erb_content = true;
is_comment_tag = false;
} else {
skip_erb_content = false;
is_comment_tag = false;
}

hb_buffer_append_whitespace(output, range_length(token->range));
Expand All @@ -40,11 +48,36 @@ void herb_extract_ruby_to_buffer_with_semicolons(const char* source, hb_buffer_T
}

case TOKEN_ERB_END: {
bool was_comment = is_comment_tag;
skip_erb_content = false;
is_comment_tag = false;

if (was_comment) {
hb_buffer_append_whitespace(output, range_length(token->range));
break;
}

bool needs_semicolon = false;
uint32_t current_line = token->location.end.line;

hb_buffer_append_char(output, ' ');
hb_buffer_append_char(output, ';');
hb_buffer_append_whitespace(output, range_length(token->range) - 2);
for (size_t j = i + 1; j < hb_array_size(tokens); j++) {
const token_T* next_token = hb_array_get(tokens, j);

if (next_token->type == TOKEN_NEWLINE) { break; }

if (next_token->type == TOKEN_ERB_START && next_token->location.start.line == current_line) {
needs_semicolon = true;
break;
}
}

if (needs_semicolon) {
hb_buffer_append_char(output, ' ');
hb_buffer_append_char(output, ';');
hb_buffer_append_whitespace(output, range_length(token->range) - 2);
} else {
hb_buffer_append_whitespace(output, range_length(token->range));
}
break;
}

Expand Down
2 changes: 2 additions & 0 deletions test/c/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ TCase *io_tests(void);
TCase *lex_tests(void);
TCase *token_tests(void);
TCase *util_tests(void);
TCase *extract_tests(void);

Suite *herb_suite(void) {
Suite *suite = suite_create("Herb Suite");
Expand All @@ -25,6 +26,7 @@ Suite *herb_suite(void) {
suite_add_tcase(suite, lex_tests());
suite_add_tcase(suite, token_tests());
suite_add_tcase(suite, util_tests());
suite_add_tcase(suite, extract_tests());

return suite;
}
Expand Down
106 changes: 106 additions & 0 deletions test/c/test_extract.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "include/test.h"

#include "../../src/include/herb.h"
#include "../../src/include/extract.h"
#include "../../src/include/util/hb_buffer.h"

TEST(extract_ruby_single_erb_no_semicolon)
char* source = "<% if %>\n<% end %>";
char* result = herb_extract_ruby_with_semicolons(source);

char expected[] = " if \n end ";
ck_assert_str_eq(result, expected);

free(result);
END

TEST(extract_ruby_multiple_erb_same_line_with_semicolon)
char* source = "<% x = 1 %> <% y = 2 %>";
char* result = herb_extract_ruby_with_semicolons(source);

ck_assert_str_eq(result, " x = 1 ; y = 2 ");

free(result);
END

TEST(extract_ruby_three_erb_same_line_with_semicolons)
char* source = "<% a = 1 %> <% b = 2 %> <% c = 3 %>";
char* result = herb_extract_ruby_with_semicolons(source);

ck_assert_str_eq(result, " a = 1 ; b = 2 ; c = 3 ");

free(result);
END

TEST(extract_ruby_different_lines_no_semicolons)
char* source = "<% x = 1 %>\n<% y = 2 %>";
char* result = herb_extract_ruby_with_semicolons(source);

char expected[] = " x = 1 \n y = 2 ";
ck_assert_str_eq(result, expected);

free(result);
END

TEST(extract_ruby_mixed_lines)
char* source = "<% a = 1 %> <% b = 2 %>\n<% c = 3 %>";
char* result = herb_extract_ruby_with_semicolons(source);

char expected[] = " a = 1 ; b = 2 \n c = 3 ";
ck_assert_str_eq(result, expected);

free(result);
END

TEST(extract_ruby_output_tags_same_line)
char* source = "<%= x %> <%= y %>";
char* result = herb_extract_ruby_with_semicolons(source);

ck_assert_str_eq(result, " x ; y ");

free(result);
END

TEST(extract_ruby_empty_erb_same_line)
char* source = "<% %> <% %>";
char* result = herb_extract_ruby_with_semicolons(source);

ck_assert_str_eq(result, " ; ");

free(result);
END

TEST(extract_ruby_comments_skipped)
char* source = "<%# comment %> <% code %>";
char* result = herb_extract_ruby_with_semicolons(source);

ck_assert_str_eq(result, " code ");

free(result);
END

TEST(extract_ruby_issue_135_if_without_condition)
char* source = "<% if %>\n<% end %>";
char* result = herb_extract_ruby_with_semicolons(source);

char expected[] = " if \n end ";
ck_assert_str_eq(result, expected);

free(result);
END

TCase *extract_tests(void) {
TCase *extract = tcase_create("Extract");

tcase_add_test(extract, extract_ruby_single_erb_no_semicolon);
tcase_add_test(extract, extract_ruby_multiple_erb_same_line_with_semicolon);
tcase_add_test(extract, extract_ruby_three_erb_same_line_with_semicolons);
tcase_add_test(extract, extract_ruby_different_lines_no_semicolons);
tcase_add_test(extract, extract_ruby_mixed_lines);
tcase_add_test(extract, extract_ruby_output_tags_same_line);
tcase_add_test(extract, extract_ruby_empty_erb_same_line);
tcase_add_test(extract, extract_ruby_comments_skipped);
tcase_add_test(extract, extract_ruby_issue_135_if_without_condition);

return extract;
}
9 changes: 8 additions & 1 deletion test/parser/erb_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,15 @@ class ERBTest < Minitest::Spec
assert_parsed_snapshot(%(<% content %> %>))
end

test "TODO" do
test "incomplete erb tag" do
assert_parsed_snapshot(%(<%= 1 + %>))
end

test "if without condition" do
assert_parsed_snapshot(<<~HTML)
<% if %>
<% end %>
HTML
end
end
end

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading