From 1f0a0ad55c3b19f8e00bf7431781c5272577053a Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Thu, 16 Dec 2021 10:15:12 -0500 Subject: [PATCH 1/4] Add `#` inline comment tag. This commit adds a new tag named `#` that behaves like a comment. Therefore it behaves as you'd expect any tag would work. The difference with the comment tag is that the comment is in the tag markup and that there is no block delimiter. What it looks like in practice: ```liquid {%- # this is an inline comment -%} {% # this too is an inline comment %} {% liquid # required args: assign product = product # optional args: assign should_show_border = should_show_border | default: true assign should_show_cursor = should_show_cursor | default: true %} {% liquid # This is a very long comment that spans multiple lines. # It looks very similar to what it would look like if you wrote # ruby code instead of liquid. But it doesn't have all the clunk # of having an open tag and a close tag with so many characters. %} ``` Co-authored-by: Dylan Thacker-Smith --- Gemfile | 2 +- lib/liquid.rb | 1 + lib/liquid/block_body.rb | 4 +- lib/liquid/locales/en.yml | 11 ++-- lib/liquid/tags/inline_comment.rb | 30 +++++++++ test/integration/tags/inline_comment_test.rb | 68 ++++++++++++++++++++ 6 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 lib/liquid/tags/inline_comment.rb create mode 100644 test/integration/tags/inline_comment_test.rb diff --git a/Gemfile b/Gemfile index daff580cf..e4c1adab7 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,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-fresh' end end diff --git a/lib/liquid.rb b/lib/liquid.rb index f6aabb0d0..a0a058810 100644 --- a/lib/liquid.rb +++ b/lib/liquid.rb @@ -29,6 +29,7 @@ module Liquid WhitespaceControl = '-' TagStart = /\{\%/ TagEnd = /\%\}/ + TagName = /#|\w+/ VariableSignature = /\(?[\w\-\.\[\]]\)?/ VariableSegment = /[\w\-]/ VariableStart = /\{\{/ diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index d8c7e453f..a0d35a790 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*(#{TagName})\s*(.*?)\z/o + FullToken = /\A#{TagStart}#{WhitespaceControl}?(\s*)(#{TagName})(\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..7e232de42 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -13,15 +13,16 @@ for_invalid_attribute: "Invalid attribute in for loop. Valid attributes are limit and offset" if: "Syntax Error in tag 'if' - Valid syntax: if [expression]" include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]" - unknown_tag: "Unknown tag '%{tag}'" + inline_comment_invalid: "Syntax error in tag '#' - Each line of comments must be prefixed by the '#' character" invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" + render: "Syntax error in tag 'render' - Template name must be a quoted string" + table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" + tag_never_closed: "'%{block_name}' tag was never closed" + tag_termination: "Tag '%{token}' was not properly terminated with regexp: %{tag_end}" unexpected_else: "%{block_name} tag does not expect 'else' tag" unexpected_outer_tag: "Unexpected outer '%{tag}' tag" - tag_termination: "Tag '%{token}' was not properly terminated with regexp: %{tag_end}" + unknown_tag: "Unknown tag '%{tag}'" variable_termination: "Variable '%{token}' was not properly terminated with regexp: %{tag_end}" - 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" 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..493cfddc7 --- /dev/null +++ b/lib/liquid/tags/inline_comment.rb @@ -0,0 +1,30 @@ +# 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 and prevent the introduction + # of inline comments from being backward incompatible change. + # + # As such, we're forcing users to put a # symbol on every line otherwise this + # tag will throw an error. + if markup.match?(/\n\s*[^#\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..66fbc48db --- /dev/null +++ b/test/integration/tags/inline_comment_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class InlineCommentTest < Minitest::Test + include Liquid + + def test_inline_comment_returns_nothing + assert_template_result('', '{%- # this is an inline comment -%}') + assert_template_result('', '{%-# this is an inline comment -%}') + assert_template_result('', '{% # this is an inline comment %}') + assert_template_result('', '{%# this is an inline comment %}') + end + + def test_inline_comment_does_not_require_a_space_after_the_pound_sign + assert_template_result('', '{%#this is an inline comment%}') + end + + def test_liquid_inline_comment_returns_nothing + assert_template_result('Hey there, how are you doing today?', <<~LIQUID) + {%- liquid + # This is how you'd write a block comment in a liquid tag. + # It looks a lot like what you'd have in ruby. + + # You can use it as inline documentation in your + # liquid blocks to explain why you're doing something. + echo "Hey there, " + + # It won't affect the output. + echo "how are you doing today?" + -%} + LIQUID + end + + def test_inline_comment_can_be_written_on_multiple_lines + assert_template_result('', <<~LIQUID) + {%- + # That kind of block comment is also allowed. + # It would only be a stylistic difference. + # Much like JavaScript's /* */ comments and their + # leading * on new lines. + -%} + LIQUID + end + + def test_inline_comment_multiple_pound_signs + assert_template_result('', <<~LIQUID) + {%- liquid + ###################################### + # We support comments like this too. # + ###################################### + -%} + LIQUID + end + + def test_inline_comments_require_the_pound_sign_on_every_new_line + assert_match_syntax_error("Each line of comments must be prefixed by the '#' character", <<~LIQUID) + {%- + # some comment + echo 'hello world' + -%} + LIQUID + end + + def test_inline_comment_does_not_support_nested_tags + assert_template_result(' -%}', "{%- # {% echo 'hello world' %} -%}") + end +end From 21f3337dec67ba17cdee6509c9597bc820048c7e Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Thu, 28 Apr 2022 09:32:30 -0400 Subject: [PATCH 2/4] Test a blank line in a comment tag --- test/integration/tags/inline_comment_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/tags/inline_comment_test.rb b/test/integration/tags/inline_comment_test.rb index 66fbc48db..a4fb23ee1 100644 --- a/test/integration/tags/inline_comment_test.rb +++ b/test/integration/tags/inline_comment_test.rb @@ -37,6 +37,7 @@ def test_inline_comment_can_be_written_on_multiple_lines {%- # That kind of block comment is also allowed. # It would only be a stylistic difference. + # Much like JavaScript's /* */ comments and their # leading * on new lines. -%} From 23a8438fa60257ebddbada81565622afa6905cd6 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Thu, 28 Apr 2022 09:39:16 -0400 Subject: [PATCH 3/4] Use liquid-c master branch again, it now has inline comment support --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index e4c1adab7..daff580cf 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,6 @@ group :test do gem 'rubocop-performance', require: false platform :mri, :truffleruby do - gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'inline-comment-fresh' + gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master' end end From 54414dfd833dbedc3f5c1a188b81d0accfc920aa Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Thu, 28 Apr 2022 09:43:08 -0400 Subject: [PATCH 4/4] Add changelog entry, making the next release a feature release --- History.md | 5 ++++- lib/liquid/version.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 940f2b5a6..7d619219f 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,9 @@ # Liquid Change Log -## 5.3.1 (unreleased) +## 5.4.0 (unreleased) + +### Features +* Allow `#` to be used as an inline comment tag (#1498) [CP Clermont] ### Fixes * `PartialCache` now shares snippet cache with subcontexts by default (#1553) [Chris AtLee] diff --git a/lib/liquid/version.rb b/lib/liquid/version.rb index 3fc87a5af..9b0de1431 100644 --- a/lib/liquid/version.rb +++ b/lib/liquid/version.rb @@ -2,5 +2,5 @@ # frozen_string_literal: true module Liquid - VERSION = "5.3.0" + VERSION = "5.4.0.alpha" end