liquid 5.6.0 → 5.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,6 @@
3
3
  require 'cgi'
4
4
  require 'base64'
5
5
  require 'bigdecimal'
6
-
7
6
  module Liquid
8
7
  module StandardFilters
9
8
  MAX_I32 = (1 << 31) - 1
@@ -64,7 +63,7 @@ module Liquid
64
63
  # @liquid_syntax string | downcase
65
64
  # @liquid_return [string]
66
65
  def downcase(input)
67
- input.to_s.downcase
66
+ Utils.to_s(input).downcase
68
67
  end
69
68
 
70
69
  # @liquid_public_docs
@@ -75,7 +74,7 @@ module Liquid
75
74
  # @liquid_syntax string | upcase
76
75
  # @liquid_return [string]
77
76
  def upcase(input)
78
- input.to_s.upcase
77
+ Utils.to_s(input).upcase
79
78
  end
80
79
 
81
80
  # @liquid_public_docs
@@ -86,7 +85,7 @@ module Liquid
86
85
  # @liquid_syntax string | capitalize
87
86
  # @liquid_return [string]
88
87
  def capitalize(input)
89
- input.to_s.capitalize
88
+ Utils.to_s(input).capitalize
90
89
  end
91
90
 
92
91
  # @liquid_public_docs
@@ -97,7 +96,7 @@ module Liquid
97
96
  # @liquid_syntax string | escape
98
97
  # @liquid_return [string]
99
98
  def escape(input)
100
- CGI.escapeHTML(input.to_s) unless input.nil?
99
+ CGI.escapeHTML(Utils.to_s(input)) unless input.nil?
101
100
  end
102
101
  alias_method :h, :escape
103
102
 
@@ -109,7 +108,7 @@ module Liquid
109
108
  # @liquid_syntax string | escape_once
110
109
  # @liquid_return [string]
111
110
  def escape_once(input)
112
- input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
111
+ Utils.to_s(input).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
113
112
  end
114
113
 
115
114
  # @liquid_public_docs
@@ -124,7 +123,7 @@ module Liquid
124
123
  # @liquid_syntax string | url_encode
125
124
  # @liquid_return [string]
126
125
  def url_encode(input)
127
- CGI.escape(input.to_s) unless input.nil?
126
+ CGI.escape(Utils.to_s(input)) unless input.nil?
128
127
  end
129
128
 
130
129
  # @liquid_public_docs
@@ -138,7 +137,7 @@ module Liquid
138
137
  def url_decode(input)
139
138
  return if input.nil?
140
139
 
141
- result = CGI.unescape(input.to_s)
140
+ result = CGI.unescape(Utils.to_s(input))
142
141
  raise Liquid::ArgumentError, "invalid byte sequence in #{result.encoding}" unless result.valid_encoding?
143
142
 
144
143
  result
@@ -152,7 +151,7 @@ module Liquid
152
151
  # @liquid_syntax string | base64_encode
153
152
  # @liquid_return [string]
154
153
  def base64_encode(input)
155
- Base64.strict_encode64(input.to_s)
154
+ Base64.strict_encode64(Utils.to_s(input))
156
155
  end
157
156
 
158
157
  # @liquid_public_docs
@@ -163,7 +162,7 @@ module Liquid
163
162
  # @liquid_syntax string | base64_decode
164
163
  # @liquid_return [string]
165
164
  def base64_decode(input)
166
- input = input.to_s
165
+ input = Utils.to_s(input)
167
166
  StandardFilters.try_coerce_encoding(Base64.strict_decode64(input), encoding: input.encoding)
168
167
  rescue ::ArgumentError
169
168
  raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
@@ -177,7 +176,7 @@ module Liquid
177
176
  # @liquid_syntax string | base64_url_safe_encode
178
177
  # @liquid_return [string]
179
178
  def base64_url_safe_encode(input)
180
- Base64.urlsafe_encode64(input.to_s)
179
+ Base64.urlsafe_encode64(Utils.to_s(input))
181
180
  end
182
181
 
183
182
  # @liquid_public_docs
@@ -188,7 +187,7 @@ module Liquid
188
187
  # @liquid_syntax string | base64_url_safe_decode
189
188
  # @liquid_return [string]
190
189
  def base64_url_safe_decode(input)
191
- input = input.to_s
190
+ input = Utils.to_s(input)
192
191
  StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding)
193
192
  rescue ::ArgumentError
194
193
  raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
@@ -212,7 +211,7 @@ module Liquid
212
211
  if input.is_a?(Array)
213
212
  input.slice(offset, length) || []
214
213
  else
215
- input.to_s.slice(offset, length) || ''
214
+ Utils.to_s(input).slice(offset, length) || ''
216
215
  end
217
216
  rescue RangeError
218
217
  if I64_RANGE.cover?(length) && I64_RANGE.cover?(offset)
@@ -236,10 +235,10 @@ module Liquid
236
235
  # @liquid_return [string]
237
236
  def truncate(input, length = 50, truncate_string = "...")
238
237
  return if input.nil?
239
- input_str = input.to_s
238
+ input_str = Utils.to_s(input)
240
239
  length = Utils.to_integer(length)
241
240
 
242
- truncate_string_str = truncate_string.to_s
241
+ truncate_string_str = Utils.to_s(truncate_string)
243
242
 
244
243
  l = length - truncate_string_str.length
245
244
  l = 0 if l < 0
@@ -263,7 +262,7 @@ module Liquid
263
262
  # @liquid_return [string]
264
263
  def truncatewords(input, words = 15, truncate_string = "...")
265
264
  return if input.nil?
266
- input = input.to_s
265
+ input = Utils.to_s(input)
267
266
  words = Utils.to_integer(words)
268
267
  words = 1 if words <= 0
269
268
 
@@ -277,7 +276,8 @@ module Liquid
277
276
  return input if wordlist.length <= words
278
277
 
279
278
  wordlist.pop
280
- wordlist.join(" ").concat(truncate_string.to_s)
279
+ truncate_string = Utils.to_s(truncate_string)
280
+ wordlist.join(" ").concat(truncate_string)
281
281
  end
282
282
 
283
283
  # @liquid_public_docs
@@ -288,7 +288,9 @@ module Liquid
288
288
  # @liquid_syntax string | split: string
289
289
  # @liquid_return [array[string]]
290
290
  def split(input, pattern)
291
- input.to_s.split(pattern.to_s)
291
+ pattern = Utils.to_s(pattern)
292
+ input = Utils.to_s(input)
293
+ input.split(pattern)
292
294
  end
293
295
 
294
296
  # @liquid_public_docs
@@ -299,7 +301,8 @@ module Liquid
299
301
  # @liquid_syntax string | strip
300
302
  # @liquid_return [string]
301
303
  def strip(input)
302
- input.to_s.strip
304
+ input = Utils.to_s(input)
305
+ input.strip
303
306
  end
304
307
 
305
308
  # @liquid_public_docs
@@ -310,7 +313,8 @@ module Liquid
310
313
  # @liquid_syntax string | lstrip
311
314
  # @liquid_return [string]
312
315
  def lstrip(input)
313
- input.to_s.lstrip
316
+ input = Utils.to_s(input)
317
+ input.lstrip
314
318
  end
315
319
 
316
320
  # @liquid_public_docs
@@ -321,7 +325,8 @@ module Liquid
321
325
  # @liquid_syntax string | rstrip
322
326
  # @liquid_return [string]
323
327
  def rstrip(input)
324
- input.to_s.rstrip
328
+ input = Utils.to_s(input)
329
+ input.rstrip
325
330
  end
326
331
 
327
332
  # @liquid_public_docs
@@ -332,8 +337,9 @@ module Liquid
332
337
  # @liquid_syntax string | strip_html
333
338
  # @liquid_return [string]
334
339
  def strip_html(input)
340
+ input = Utils.to_s(input)
335
341
  empty = ''
336
- result = input.to_s.gsub(STRIP_HTML_BLOCKS, empty)
342
+ result = input.gsub(STRIP_HTML_BLOCKS, empty)
337
343
  result.gsub!(STRIP_HTML_TAGS, empty)
338
344
  result
339
345
  end
@@ -346,7 +352,8 @@ module Liquid
346
352
  # @liquid_syntax string | strip_newlines
347
353
  # @liquid_return [string]
348
354
  def strip_newlines(input)
349
- input.to_s.gsub(/\r?\n/, '')
355
+ input = Utils.to_s(input)
356
+ input.gsub(/\r?\n/, '')
350
357
  end
351
358
 
352
359
  # @liquid_public_docs
@@ -357,6 +364,7 @@ module Liquid
357
364
  # @liquid_syntax array | join
358
365
  # @liquid_return [string]
359
366
  def join(input, glue = ' ')
367
+ glue = Utils.to_s(glue)
360
368
  InputIterator.new(input, context).join(glue)
361
369
  end
362
370
 
@@ -424,29 +432,59 @@ module Liquid
424
432
  # @liquid_syntax array | where: string, string
425
433
  # @liquid_return [array[untyped]]
426
434
  def where(input, property, target_value = nil)
427
- ary = InputIterator.new(input, context)
435
+ filter_array(input, property, target_value) { |ary, &block| ary.select(&block) }
436
+ end
428
437
 
429
- if ary.empty?
430
- []
431
- elsif target_value.nil?
432
- ary.select do |item|
433
- item[property]
434
- rescue TypeError
435
- raise_property_error(property)
436
- rescue NoMethodError
437
- return nil unless item.respond_to?(:[])
438
- raise
439
- end
440
- else
441
- ary.select do |item|
442
- item[property] == target_value
443
- rescue TypeError
444
- raise_property_error(property)
445
- rescue NoMethodError
446
- return nil unless item.respond_to?(:[])
447
- raise
448
- end
449
- end
438
+ # @liquid_public_docs
439
+ # @liquid_type filter
440
+ # @liquid_category array
441
+ # @liquid_summary
442
+ # Filters an array to exclude items with a specific property value.
443
+ # @liquid_description
444
+ # This requires you to provide both the property name and the associated value.
445
+ # @liquid_syntax array | reject: string, string
446
+ # @liquid_return [array[untyped]]
447
+ def reject(input, property, target_value = nil)
448
+ filter_array(input, property, target_value) { |ary, &block| ary.reject(&block) }
449
+ end
450
+
451
+ # @liquid_public_docs
452
+ # @liquid_type filter
453
+ # @liquid_category array
454
+ # @liquid_summary
455
+ # Tests if any item in an array has a specific property value.
456
+ # @liquid_description
457
+ # This requires you to provide both the property name and the associated value.
458
+ # @liquid_syntax array | has: string, string
459
+ # @liquid_return [boolean]
460
+ def has(input, property, target_value = nil)
461
+ filter_array(input, property, target_value, false) { |ary, &block| ary.any?(&block) }
462
+ end
463
+
464
+ # @liquid_public_docs
465
+ # @liquid_type filter
466
+ # @liquid_category array
467
+ # @liquid_summary
468
+ # Returns the first item in an array with a specific property value.
469
+ # @liquid_description
470
+ # This requires you to provide both the property name and the associated value.
471
+ # @liquid_syntax array | find: string, string
472
+ # @liquid_return [untyped]
473
+ def find(input, property, target_value = nil)
474
+ filter_array(input, property, target_value, nil) { |ary, &block| ary.find(&block) }
475
+ end
476
+
477
+ # @liquid_public_docs
478
+ # @liquid_type filter
479
+ # @liquid_category array
480
+ # @liquid_summary
481
+ # Returns the index of the first item in an array with a specific property value.
482
+ # @liquid_description
483
+ # This requires you to provide both the property name and the associated value.
484
+ # @liquid_syntax array | find_index: string, string
485
+ # @liquid_return [number]
486
+ def find_index(input, property, target_value = nil)
487
+ filter_array(input, property, target_value, nil) { |ary, &block| ary.find_index(&block) }
450
488
  end
451
489
 
452
490
  # @liquid_public_docs
@@ -543,7 +581,10 @@ module Liquid
543
581
  # @liquid_syntax string | replace: string, string
544
582
  # @liquid_return [string]
545
583
  def replace(input, string, replacement = '')
546
- input.to_s.gsub(string.to_s, replacement.to_s)
584
+ string = Utils.to_s(string)
585
+ replacement = Utils.to_s(replacement)
586
+ input = Utils.to_s(input)
587
+ input.gsub(string, replacement)
547
588
  end
548
589
 
549
590
  # @liquid_public_docs
@@ -554,7 +595,10 @@ module Liquid
554
595
  # @liquid_syntax string | replace_first: string, string
555
596
  # @liquid_return [string]
556
597
  def replace_first(input, string, replacement = '')
557
- input.to_s.sub(string.to_s, replacement.to_s)
598
+ string = Utils.to_s(string)
599
+ replacement = Utils.to_s(replacement)
600
+ input = Utils.to_s(input)
601
+ input.sub(string, replacement)
558
602
  end
559
603
 
560
604
  # @liquid_public_docs
@@ -565,9 +609,9 @@ module Liquid
565
609
  # @liquid_syntax string | replace_last: string, string
566
610
  # @liquid_return [string]
567
611
  def replace_last(input, string, replacement)
568
- input = input.to_s
569
- string = string.to_s
570
- replacement = replacement.to_s
612
+ input = Utils.to_s(input)
613
+ string = Utils.to_s(string)
614
+ replacement = Utils.to_s(replacement)
571
615
 
572
616
  start_index = input.rindex(string)
573
617
 
@@ -619,7 +663,9 @@ module Liquid
619
663
  # @liquid_syntax string | append: string
620
664
  # @liquid_return [string]
621
665
  def append(input, string)
622
- input.to_s + string.to_s
666
+ input = Utils.to_s(input)
667
+ string = Utils.to_s(string)
668
+ input + string
623
669
  end
624
670
 
625
671
  # @liquid_public_docs
@@ -648,7 +694,9 @@ module Liquid
648
694
  # @liquid_syntax string | prepend: string
649
695
  # @liquid_return [string]
650
696
  def prepend(input, string)
651
- string.to_s + input.to_s
697
+ input = Utils.to_s(input)
698
+ string = Utils.to_s(string)
699
+ string + input
652
700
  end
653
701
 
654
702
  # @liquid_public_docs
@@ -659,10 +707,20 @@ module Liquid
659
707
  # @liquid_syntax string | newline_to_br
660
708
  # @liquid_return [string]
661
709
  def newline_to_br(input)
662
- input.to_s.gsub(/\r?\n/, "<br />\n")
710
+ input = Utils.to_s(input)
711
+ input.gsub(/\r?\n/, "<br />\n")
663
712
  end
664
713
 
665
- # Reformat a date using Ruby's core Time#strftime( string ) -> string
714
+ # @liquid_public_docs
715
+ # @liquid_type filter
716
+ # @liquid_category date
717
+ # @liquid_summary
718
+ # Formats a date according to a specified format string.
719
+ # @liquid_description
720
+ # This filter formats a date using various format specifiers. If the format string is empty,
721
+ # the original input is returned. If the input cannot be converted to a date, the original input is returned.
722
+ #
723
+ # The following format specifiers can be used:
666
724
  #
667
725
  # %a - The abbreviated weekday name (``Sun'')
668
726
  # %A - The full weekday name (``Sunday'')
@@ -691,14 +749,15 @@ module Liquid
691
749
  # %Y - Year with century
692
750
  # %Z - Time zone name
693
751
  # %% - Literal ``%'' character
694
- #
695
- # See also: http://www.ruby-doc.org/core/Time.html#method-i-strftime
752
+ # @liquid_syntax date | date: string
753
+ # @liquid_return [string]
696
754
  def date(input, format)
697
- return input if format.to_s.empty?
755
+ str_format = Utils.to_s(format)
756
+ return input if str_format.empty?
698
757
 
699
758
  return input unless (date = Utils.to_date(input))
700
759
 
701
- date.strftime(format.to_s)
760
+ date.strftime(str_format)
702
761
  end
703
762
 
704
763
  # @liquid_public_docs
@@ -918,8 +977,27 @@ module Liquid
918
977
 
919
978
  attr_reader :context
920
979
 
980
+ def filter_array(input, property, target_value, default_value = [], &block)
981
+ ary = InputIterator.new(input, context)
982
+
983
+ return default_value if ary.empty?
984
+
985
+ block.call(ary) do |item|
986
+ if target_value.nil?
987
+ item[property]
988
+ else
989
+ item[property] == target_value
990
+ end
991
+ rescue TypeError
992
+ raise_property_error(property)
993
+ rescue NoMethodError
994
+ return nil unless item.respond_to?(:[])
995
+ raise
996
+ end
997
+ end
998
+
921
999
  def raise_property_error(property)
922
- raise Liquid::ArgumentError, "cannot select the property '#{property}'"
1000
+ raise Liquid::ArgumentError, "cannot select the property '#{Utils.to_s(property)}'"
923
1001
  end
924
1002
 
925
1003
  def apply_operation(input, operand, operation)
@@ -968,7 +1046,18 @@ module Liquid
968
1046
  end
969
1047
 
970
1048
  def join(glue)
971
- to_a.join(glue.to_s)
1049
+ first = true
1050
+ output = +""
1051
+ each do |item|
1052
+ if first
1053
+ first = false
1054
+ else
1055
+ output << glue
1056
+ end
1057
+
1058
+ output << Liquid::Utils.to_s(item)
1059
+ end
1060
+ output
972
1061
  end
973
1062
 
974
1063
  def concat(args)
@@ -980,7 +1069,10 @@ module Liquid
980
1069
  end
981
1070
 
982
1071
  def uniq(&block)
983
- to_a.uniq(&block)
1072
+ to_a.uniq do |item|
1073
+ item = Utils.to_liquid_value(item)
1074
+ block ? yield(item) : item
1075
+ end
984
1076
  end
985
1077
 
986
1078
  def compact
@@ -68,7 +68,13 @@ module Liquid
68
68
  def variables_from_string(markup)
69
69
  markup.split(',').collect do |var|
70
70
  var =~ /\s*(#{QuotedFragment})\s*/o
71
- Regexp.last_match(1) ? parse_expression(Regexp.last_match(1)) : nil
71
+ next unless Regexp.last_match(1)
72
+
73
+ # Expression Parser returns cached objects, and we need to dup them to
74
+ # start the cycle over for each new cycle call.
75
+ # Liquid-C does not have a cache, so we don't need to dup the object.
76
+ var = parse_expression(Regexp.last_match(1))
77
+ var.is_a?(VariableLookup) ? var.dup : var
72
78
  end.compact
73
79
  end
74
80
 
@@ -10,7 +10,7 @@ module Liquid
10
10
  # @liquid_description
11
11
  # Variables that are declared with `decrement` are unique to the [layout](/themes/architecture/layouts), [template](/themes/architecture/templates),
12
12
  # or [section](/themes/architecture/sections) file that they're created in. However, the variable is shared across
13
- # [snippets](/themes/architecture#snippets) included in the file.
13
+ # [snippets](/themes/architecture/snippets) included in the file.
14
14
  #
15
15
  # Similarly, variables that are created with `decrement` are independent from those created with [`assign`](/docs/api/liquid/tags/assign)
16
16
  # and [`capture`](/docs/api/liquid/tags/capture). However, `decrement` and [`increment`](/docs/api/liquid/tags/increment) share
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Liquid
4
+ # @liquid_public_docs
5
+ # @liquid_type tag
6
+ # @liquid_category syntax
7
+ # @liquid_name doc
8
+ # @liquid_summary
9
+ # Documents template elements with annotations.
10
+ # @liquid_description
11
+ # The `doc` tag allows developers to include documentation within Liquid
12
+ # templates. Any content inside `doc` tags is not rendered or outputted.
13
+ # Liquid code inside will be parsed but not executed. This facilitates
14
+ # tooling support for features like code completion, linting, and inline
15
+ # documentation.
16
+ #
17
+ # For detailed documentation syntax and examples, see the
18
+ # [`LiquidDoc` reference](/docs/storefronts/themes/tools/liquid-doc).
19
+ #
20
+ # @liquid_syntax
21
+ # {% doc %}
22
+ # Renders a message.
23
+ #
24
+ # @param {string} foo - A string value.
25
+ # @param {string} [bar] - An optional string value.
26
+ #
27
+ # @example
28
+ # {% render 'message', foo: 'Hello', bar: 'World' %}
29
+ # {% enddoc %}
30
+ class Doc < Block
31
+ NO_UNEXPECTED_ARGS = /\A\s*\z/
32
+
33
+ def initialize(tag_name, markup, parse_context)
34
+ super
35
+ ensure_valid_markup(tag_name, markup, parse_context)
36
+ end
37
+
38
+ def parse(tokens)
39
+ @body = +""
40
+
41
+ while (token = tokens.shift)
42
+ tag_name = token =~ BlockBody::FullTokenPossiblyInvalid && Regexp.last_match(2)
43
+
44
+ raise_nested_doc_error if tag_name == @tag_name
45
+
46
+ if tag_name == block_delimiter
47
+ parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
48
+ @body << Regexp.last_match(1) if Regexp.last_match(1) != ""
49
+ return
50
+ end
51
+ @body << token unless token.empty?
52
+ end
53
+
54
+ raise_tag_never_closed(block_name)
55
+ end
56
+
57
+ def render_to_output_buffer(_context, output)
58
+ output
59
+ end
60
+
61
+ def blank?
62
+ @body.empty?
63
+ end
64
+
65
+ def nodelist
66
+ [@body]
67
+ end
68
+
69
+ private
70
+
71
+ def ensure_valid_markup(tag_name, markup, parse_context)
72
+ unless NO_UNEXPECTED_ARGS.match?(markup)
73
+ raise SyntaxError, parse_context.locale.t("errors.syntax.block_tag_unexpected_args", tag: tag_name)
74
+ end
75
+ end
76
+
77
+ def raise_nested_doc_error
78
+ raise SyntaxError, parse_context.locale.t("errors.syntax.doc_invalid_nested")
79
+ end
80
+ end
81
+ end
@@ -88,7 +88,7 @@ module Liquid
88
88
  end
89
89
 
90
90
  def strict_parse(markup)
91
- p = Parser.new(markup)
91
+ p = @parse_context.new_parser(markup)
92
92
  @variable_name = p.consume(:id)
93
93
  raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in") unless p.id?('in')
94
94
 
@@ -102,7 +102,7 @@ module Liquid
102
102
  end
103
103
 
104
104
  def strict_parse(markup)
105
- p = Parser.new(markup)
105
+ p = @parse_context.new_parser(markup)
106
106
  condition = parse_binary_comparisons(p)
107
107
  p.consume(:end_of_string)
108
108
  condition
@@ -6,7 +6,7 @@ module Liquid
6
6
  # @liquid_category theme
7
7
  # @liquid_name include
8
8
  # @liquid_summary
9
- # Renders a [snippet](/themes/architecture#snippets).
9
+ # Renders a [snippet](/themes/architecture/snippets).
10
10
  # @liquid_description
11
11
  # Inside the snippet, you can access and alter variables that are [created](/docs/api/liquid/tags/variable-tags) outside of the
12
12
  # snippet.
@@ -10,7 +10,7 @@ module Liquid
10
10
  # @liquid_description
11
11
  # Variables that are declared with `increment` are unique to the [layout](/themes/architecture/layouts), [template](/themes/architecture/templates),
12
12
  # or [section](/themes/architecture/sections) file that they're created in. However, the variable is shared across
13
- # [snippets](/themes/architecture#snippets) included in the file.
13
+ # [snippets](/themes/architecture/snippets) included in the file.
14
14
  #
15
15
  # Similarly, variables that are created with `increment` are independent from those created with [`assign`](/docs/api/liquid/tags/assign)
16
16
  # and [`capture`](/docs/api/liquid/tags/capture). However, `increment` and [`decrement`](/docs/api/liquid/tags/decrement) share
@@ -6,7 +6,7 @@ module Liquid
6
6
  # @liquid_category theme
7
7
  # @liquid_name render
8
8
  # @liquid_summary
9
- # Renders a [snippet](/themes/architecture#snippets) or [app block](/themes/architecture/sections/section-schema#render-app-blocks).
9
+ # Renders a [snippet](/themes/architecture/snippets) or [app block](/themes/architecture/sections/section-schema#render-app-blocks).
10
10
  # @liquid_description
11
11
  # Inside snippets and app blocks, you can't directly access variables that are [created](/docs/api/liquid/tags/variable-tags) outside
12
12
  # of the snippet or app block. However, you can [specify variables as parameters](/docs/api/liquid/tags/render#render-passing-variables-to-a-snippet)
data/lib/liquid/tags.rb CHANGED
@@ -19,6 +19,7 @@ require_relative "tags/comment"
19
19
  require_relative "tags/raw"
20
20
  require_relative "tags/render"
21
21
  require_relative "tags/cycle"
22
+ require_relative "tags/doc"
22
23
 
23
24
  module Liquid
24
25
  module Tags
@@ -42,6 +43,7 @@ module Liquid
42
43
  'if' => If,
43
44
  'echo' => Echo,
44
45
  'tablerow' => TableRow,
46
+ 'doc' => Doc,
45
47
  }.freeze
46
48
  end
47
49
  end