diff --git a/Gemfile b/Gemfile index ed0678f80..25ad5b868 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,6 @@ group :test do gem 'rubocop-performance', require: false platform :mri, :truffleruby do - gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master' + gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'inline-comment' end end diff --git a/History.md b/History.md index 4280a7298..968e27408 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,10 @@ # Liquid Change Log +## Unreleased + +### Features +* Allow `#` to be used as an inline comment tag (#1401) [Dylan Thacker-Smith] + ## 5.0.0 / 2021-01-06 ### Features diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index 76ab0a857..a9c002c93 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -4,8 +4,8 @@ module Liquid class BlockBody - LiquidTagToken = /\A\s*(\w+)\s*(.*?)\z/o - FullToken = /\A#{TagStart}#{WhitespaceControl}?(\s*)(\w+)(\s*)(.*?)#{WhitespaceControl}?#{TagEnd}\z/om + LiquidTagToken = /\A\s*(\w+|#)\s*(.*?)\z/o + FullToken = /\A#{TagStart}#{WhitespaceControl}?(\s*)(\w+|#)(\s*)(.*?)#{WhitespaceControl}?#{TagEnd}\z/om ContentOfVariable = /\A#{VariableStart}#{WhitespaceControl}?(.*?)#{WhitespaceControl}?#{VariableEnd}\z/om WhitespaceOrNothing = /\A\s*\z/ TAGSTART = "{%" diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml index eb35d8689..090451832 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -22,6 +22,7 @@ tag_never_closed: "'%{block_name}' tag was never closed" table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" render: "Syntax error in tag 'render' - Template name must be a quoted string" + inline_comment_invalid: "Syntax error in tag '#' - Each line of comments must be prefixed by the '#' character" argument: include: "Argument error in tag 'include' - Illegal template name" disabled: diff --git a/lib/liquid/tags/inline_comment.rb b/lib/liquid/tags/inline_comment.rb new file mode 100644 index 000000000..d2d493542 --- /dev/null +++ b/lib/liquid/tags/inline_comment.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Liquid + class InlineComment < Tag + def initialize(tag_name, markup, options) + super + # Semantically, a comment should only ignore everything after it on the line. + # Currently, this implementation doesn't support mixing a comment with another tag + # but we need to reserve future support for this. + if markup.match?(/\n\s*[^#]/) + raise SyntaxError, options[:locale].t("errors.syntax.inline_comment_invalid") + end + end + + def render_to_output_buffer(_context, output) + output + end + + def blank? + true + end + end + + Template.register_tag('#', InlineComment) +end diff --git a/test/integration/tags/inline_comment_test.rb b/test/integration/tags/inline_comment_test.rb new file mode 100644 index 000000000..a880b5451 --- /dev/null +++ b/test/integration/tags/inline_comment_test.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'test_helper' + +class InlineCommentTest < Minitest::Test + include Liquid + + def test_tag_in_different_styles + assert_template_result('', '{% # This text gets ignored %}') + assert_template_result('', '{%# This text gets ignored #%}') + assert_template_result('', '{%# This text gets ignored %}') + assert_template_result('', '{%#- This text gets ignored -#%}') + end + + def test_test_syntax_error + assert_template_result('fail', '{% #This doesnt work %}') + + assert false + rescue + # ok good + end + + def test_tag_ws_stripping + assert_template_result('', ' {%#- This text gets ignored -#%} ') + end + + def test_comment_inline_tag + assert_template_result('ok', '{% echo "ok" # output something from a tag %}') + end + + def test_comment_line_before_tag + assert_template_result('ok', '{% # this sort of comment also + echo "ok" %}') + end + + def test_comment_inline_variable + assert_template_result('ok', '{{ "ok" # output something from a variable }}') + assert_template_result('ok', '{{ "OK" | downcase # output something from a variable }}') + end + + def test_inside_liquid_tag + source = <<~LIQUID + {%- liquid + echo "before(" + # This text gets ignored + echo ")after" + -%} + LIQUID + assert_template_result('before()after', source) + end + + def test_multiline + assert_template_result('', '{% # this sort of comment also + # will just work, because it parses + # as a single call to the "#" tag %}') + + end + +end