Introduce new inline snippets tag

Inline snippets will reduce code duplication and
improve the developer experience, eliminating the
need for one-off snippet files
This commit is contained in:
Josh Faigan
2025-10-30 12:00:44 +01:00
committed by Guilherme Carreiro
parent c357f91e0c
commit ed9c4e31c4
9 changed files with 470 additions and 3 deletions
+1
View File
@@ -5,6 +5,7 @@
block_tag_unexpected_args: "Syntax Error in '%{tag}' - Valid syntax: {% %{tag} %}{% end%{tag} %}"
assign: "Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"
capture: "Syntax Error in 'capture' - Valid syntax: capture [var]"
snippet: "Syntax Error in 'snippet' - Valid syntax: snippet [quoted string]"
case: "Syntax Error in 'case' - Valid syntax: case [condition]"
case_invalid_when: "Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %}"
case_invalid_else: "Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) "
+2
View File
@@ -20,6 +20,7 @@ require_relative "tags/raw"
require_relative "tags/render"
require_relative "tags/cycle"
require_relative "tags/doc"
require_relative "tags/snippet"
module Liquid
module Tags
@@ -44,6 +45,7 @@ module Liquid
'echo' => Echo,
'tablerow' => TableRow,
'doc' => Doc,
'snippet' => Snippet,
}.freeze
end
end
+18
View File
@@ -51,6 +51,24 @@ module Liquid
template_name = @template_name_expr
raise ::ArgumentError unless template_name.is_a?(String)
# Inline snippets take precedence over external snippets
if (inline_snippet = context.registers[:inline_snippet][template_name])
inner_context = context.new_isolated_subcontext
snippet_body = inline_snippet[:body]
snippet_args = inline_snippet[:args]
# Validate and set the arguments in the inner context
@attributes.each do |key, value|
unless snippet_args.include?(key)
raise Liquid::ArgumentError, "Invalid argument `#{key}` for snippet `#{template_name}`"
end
inner_context[key] = context.evaluate(value)
end
return output << snippet_body.render(inner_context)
end
partial = PartialCache.load(
template_name,
context: context,
+51
View File
@@ -0,0 +1,51 @@
# frozen_string_literal: true
module Liquid
# @liquid_public_docs
# @liquid_type tag
# @liquid_category theme
# @liquid_name snippet
# @liquid_summary
# Creates a new inline snippet using a string value as the identifier.
# @liquid_description
# You can create inline snippets to make your Liquid code more modular.
# @liquid_syntax
# {% snippet "input" %}
# value
# {% endsnippet %}
class Snippet < Block
SYNTAX = /(#{QuotedString})(?:\s*\|\s*([\w\s,]+)\s*\|)?/o
def initialize(tag_name, markup, options)
super
if markup =~ SYNTAX
@to = Regexp.last_match(1)
args = Regexp.last_match(2)
@args = args ? args.split(/\s*,\s*/) : []
else
raise SyntaxError, options[:locale].t("errors.syntax.snippet")
end
end
def render(context)
context.registers[:inline_snippet] ||= {}
context.registers[:inline_snippet][snippet_id] = {
body: snippet_body,
args: @args,
}
''
end
private
def snippet_id
@to[1, @to.size - 2]
end
def snippet_body
body = @body
body
end
end
end