luoma 0.1.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +2 -0
- data/.rdoc_options +16 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +68 -0
- data/Rakefile +69 -0
- data/Steepfile +41 -0
- data/certs/jgrp.pem +27 -0
- data/docs/configuration.md +180 -0
- data/docs/custom_filters.md +3 -0
- data/docs/custom_tags.md +3 -0
- data/docs/expressions.md +3 -0
- data/docs/extension_types.md +41 -0
- data/docs/filter_reference.md +1702 -0
- data/docs/index.md +73 -0
- data/docs/luoma_for_template_authors.md +3 -0
- data/docs/markdown.md +111 -0
- data/docs/predicate_reference.md +3 -0
- data/docs/static_analysis.md +3 -0
- data/docs/tag_reference.md +352 -0
- data/docs/template_loaders.md +177 -0
- data/docs/undefined_variables.md +3 -0
- data/docs-requirements.txt +11 -0
- data/docs_/cycle.md +17 -0
- data/docs_/font_rendering_example.md +157 -0
- data/docs_/header_block_example.md +51 -0
- data/docs_/increment_and_decrement.md +49 -0
- data/docs_/logo_style_example.md +40 -0
- data/docs_/migration.md +11 -0
- data/docs_/notes.md +19 -0
- data/lib/luoma/cache.rb +80 -0
- data/lib/luoma/chain_hash.rb +54 -0
- data/lib/luoma/context.rb +227 -0
- data/lib/luoma/drop.rb +84 -0
- data/lib/luoma/drops/block.rb +33 -0
- data/lib/luoma/drops/expression.rb +29 -0
- data/lib/luoma/drops/html_safe.rb +36 -0
- data/lib/luoma/drops/range.rb +69 -0
- data/lib/luoma/drops/undefined.rb +119 -0
- data/lib/luoma/environment.rb +479 -0
- data/lib/luoma/errors.rb +79 -0
- data/lib/luoma/escape.rb +35 -0
- data/lib/luoma/expression.rb +1271 -0
- data/lib/luoma/filter.rb +97 -0
- data/lib/luoma/filters/array.rb +372 -0
- data/lib/luoma/filters/date.rb +19 -0
- data/lib/luoma/filters/default.rb +16 -0
- data/lib/luoma/filters/json.rb +14 -0
- data/lib/luoma/filters/math.rb +84 -0
- data/lib/luoma/filters/size.rb +13 -0
- data/lib/luoma/filters/slice.rb +52 -0
- data/lib/luoma/filters/sort.rb +113 -0
- data/lib/luoma/filters/string.rb +186 -0
- data/lib/luoma/fnv.rb +15 -0
- data/lib/luoma/lexer.rb +106 -0
- data/lib/luoma/lexer_legacy.rb +396 -0
- data/lib/luoma/lexer_unified.rb +279 -0
- data/lib/luoma/loader.rb +50 -0
- data/lib/luoma/loaders/choice_loader.rb +20 -0
- data/lib/luoma/loaders/file_system_loader.rb +75 -0
- data/lib/luoma/loaders/mixins.rb +52 -0
- data/lib/luoma/markup.rb +109 -0
- data/lib/luoma/parser.rb +252 -0
- data/lib/luoma/parser_unified.rb +979 -0
- data/lib/luoma/predicates/blank.rb +19 -0
- data/lib/luoma/predicates/defined.rb +10 -0
- data/lib/luoma/predicates/empty.rb +15 -0
- data/lib/luoma/predicates/type.rb +35 -0
- data/lib/luoma/static_analysis.rb +427 -0
- data/lib/luoma/tags/assign.rb +63 -0
- data/lib/luoma/tags/break.rb +23 -0
- data/lib/luoma/tags/capture.rb +43 -0
- data/lib/luoma/tags/case.rb +137 -0
- data/lib/luoma/tags/comment.rb +17 -0
- data/lib/luoma/tags/continue.rb +23 -0
- data/lib/luoma/tags/define.rb +42 -0
- data/lib/luoma/tags/else.rb +30 -0
- data/lib/luoma/tags/for.rb +108 -0
- data/lib/luoma/tags/if.rb +109 -0
- data/lib/luoma/tags/import.rb +91 -0
- data/lib/luoma/tags/include.rb +77 -0
- data/lib/luoma/tags/output.rb +20 -0
- data/lib/luoma/tags/raw.rb +26 -0
- data/lib/luoma/tags/render.rb +92 -0
- data/lib/luoma/tags/with.rb +55 -0
- data/lib/luoma/template.rb +178 -0
- data/lib/luoma/token.rb +84 -0
- data/lib/luoma/version.rb +5 -0
- data/lib/luoma.rb +75 -0
- data/sig/luoma/cache.rbs +44 -0
- data/sig/luoma/chain_hash.rbs +26 -0
- data/sig/luoma/context.rbs +115 -0
- data/sig/luoma/drop.rbs +44 -0
- data/sig/luoma/drops/block.rbs +10 -0
- data/sig/luoma/drops/expression.rbs +10 -0
- data/sig/luoma/drops/html_safe.rbs +14 -0
- data/sig/luoma/drops/range.rbs +15 -0
- data/sig/luoma/drops/undefined.rbs +27 -0
- data/sig/luoma/environment.rbs +212 -0
- data/sig/luoma/errors.rbs +67 -0
- data/sig/luoma/escape.rbs +15 -0
- data/sig/luoma/expression.rbs +514 -0
- data/sig/luoma/filter.rbs +66 -0
- data/sig/luoma/filters/array.rbs +74 -0
- data/sig/luoma/filters/date.rbs +9 -0
- data/sig/luoma/filters/default.rbs +8 -0
- data/sig/luoma/filters/json.rbs +7 -0
- data/sig/luoma/filters/math.rbs +37 -0
- data/sig/luoma/filters/size.rbs +6 -0
- data/sig/luoma/filters/slice.rbs +10 -0
- data/sig/luoma/filters/sort.rbs +17 -0
- data/sig/luoma/filters/string.rbs +103 -0
- data/sig/luoma/fnv.rbs +3 -0
- data/sig/luoma/lexer.rbs +42 -0
- data/sig/luoma/lexer_legacy.rbs +81 -0
- data/sig/luoma/lexer_unified.rbs +49 -0
- data/sig/luoma/loader.rbs +40 -0
- data/sig/luoma/loaders/choice_loader.rbs +9 -0
- data/sig/luoma/loaders/file_system_loader.rbs +19 -0
- data/sig/luoma/loaders/mixins.rbs +16 -0
- data/sig/luoma/markup.rbs +68 -0
- data/sig/luoma/parser.rbs +105 -0
- data/sig/luoma/parser_unified.rbs +150 -0
- data/sig/luoma/predicates/blank.rbs +6 -0
- data/sig/luoma/predicates/defined.rbs +6 -0
- data/sig/luoma/predicates/empty.rbs +6 -0
- data/sig/luoma/predicates/type.rbs +21 -0
- data/sig/luoma/static_analysis.rbs +141 -0
- data/sig/luoma/tags/assign.rbs +12 -0
- data/sig/luoma/tags/break.rbs +11 -0
- data/sig/luoma/tags/capture.rbs +14 -0
- data/sig/luoma/tags/case.rbs +36 -0
- data/sig/luoma/tags/comment.rbs +11 -0
- data/sig/luoma/tags/continue.rbs +11 -0
- data/sig/luoma/tags/define.rbs +16 -0
- data/sig/luoma/tags/else.rbs +17 -0
- data/sig/luoma/tags/for.rbs +26 -0
- data/sig/luoma/tags/if.rbs +45 -0
- data/sig/luoma/tags/import.rbs +13 -0
- data/sig/luoma/tags/include.rbs +13 -0
- data/sig/luoma/tags/output.rbs +13 -0
- data/sig/luoma/tags/raw.rbs +11 -0
- data/sig/luoma/tags/render.rbs +13 -0
- data/sig/luoma/tags/with.rbs +15 -0
- data/sig/luoma/template.rbs +117 -0
- data/sig/luoma/token.rbs +81 -0
- data/sig/luoma.rbs +11 -0
- data/zensical.toml +363 -0
- data.tar.gz.sig +0 -0
- metadata +233 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
module Filters
|
|
3
|
+
# Return the absolute value of `left`.
|
|
4
|
+
def self.abs: (FilterContext context, untyped left) -> untyped
|
|
5
|
+
|
|
6
|
+
# Return the maximum of `left` and `right`.
|
|
7
|
+
def self.at_least: (FilterContext context, untyped left, untyped right) -> untyped
|
|
8
|
+
|
|
9
|
+
# Return the minimum of `left` and `right`.
|
|
10
|
+
def self.at_most: (FilterContext context, untyped left, untyped right) -> untyped
|
|
11
|
+
|
|
12
|
+
# Return `left` rounded up to the next whole number.
|
|
13
|
+
def self.ceil: (FilterContext context, untyped left) -> untyped
|
|
14
|
+
|
|
15
|
+
# Return the result of dividing `left` by `right`.
|
|
16
|
+
# If both `left` and `right` are integers, integer division is performed.
|
|
17
|
+
def self.divided_by: (FilterContext context, untyped left, untyped right) -> untyped
|
|
18
|
+
|
|
19
|
+
# Return the result of multiplying `left` by `right`.
|
|
20
|
+
def self.times: (FilterContext context, untyped left, untyped right) -> untyped
|
|
21
|
+
|
|
22
|
+
# Return `left` rounded down to the next whole number.
|
|
23
|
+
def self.floor: (FilterContext context, untyped left) -> untyped
|
|
24
|
+
|
|
25
|
+
# Return `right` subtracted from `left`.
|
|
26
|
+
def self.minus: (FilterContext context, untyped left, untyped right) -> untyped
|
|
27
|
+
|
|
28
|
+
# Return the remainder of dividing `left` by `right`.
|
|
29
|
+
def self.modulo: (FilterContext context, untyped left, untyped right) -> untyped
|
|
30
|
+
|
|
31
|
+
# Return `right` added to `left`.
|
|
32
|
+
def self.plus: (FilterContext context, untyped left, untyped right) -> untyped
|
|
33
|
+
|
|
34
|
+
# Return `left` rounded to `ndigits` decimal digits.
|
|
35
|
+
def self.round: (FilterContext context, untyped left, ?::Integer ndigits) -> untyped
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
module Filters
|
|
3
|
+
INFINITY_ARRAY: ::Array[untyped]
|
|
4
|
+
|
|
5
|
+
def self.sort: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
6
|
+
|
|
7
|
+
def self.sort_natural: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
8
|
+
|
|
9
|
+
def self.sort_numeric: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
10
|
+
|
|
11
|
+
def self.nil_safe_casecmp: (untyped left, untyped right) -> (untyped | 0 | 1 | -1)
|
|
12
|
+
|
|
13
|
+
def self.numeric_compare: (untyped left, untyped right, FilterContext context) -> untyped
|
|
14
|
+
|
|
15
|
+
def self.ints: (untyped obj, FilterContext context) -> (::Array[untyped] | untyped)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
module Filters
|
|
3
|
+
# Return _left_ concatenated with _right_.
|
|
4
|
+
# Coerce _left_ and _right_ to strings if they aren't strings already.
|
|
5
|
+
def self.append: (FilterContext context, untyped left, untyped right) -> untyped
|
|
6
|
+
|
|
7
|
+
# Return _left_ with the first character in uppercase and the rest lowercase.
|
|
8
|
+
# Coerce _left_ to a string if it is not one already.
|
|
9
|
+
def self.capitalize: (FilterContext context, untyped left) -> untyped
|
|
10
|
+
|
|
11
|
+
# Return _left_ with all characters converted to lowercase.
|
|
12
|
+
# Coerce _left_ to a string if it is not one already.
|
|
13
|
+
def self.downcase: (FilterContext context, untyped left) -> untyped
|
|
14
|
+
|
|
15
|
+
# Return _left_ with all characters converted to uppercase.
|
|
16
|
+
# Coerce _left_ to a string if it is not one already.
|
|
17
|
+
def self.upcase: (FilterContext context, untyped left) -> untyped
|
|
18
|
+
|
|
19
|
+
# Return _left_ with special HTML characters replaced with their HTML-safe escape sequences.
|
|
20
|
+
# Coerce _left_ to a string if it is not one already.
|
|
21
|
+
def self.escape: (FilterContext context, untyped left) -> (untyped | nil)
|
|
22
|
+
|
|
23
|
+
# Return _left_ with special HTML characters replaced with their HTML-safe escape sequences.
|
|
24
|
+
# Coerce _left_ to a string if it is not one already.
|
|
25
|
+
#
|
|
26
|
+
# It is safe to use `escape_once` on string values that already contain HTML-escape sequences.
|
|
27
|
+
def self.escape_once: (FilterContext context, untyped left) -> untyped
|
|
28
|
+
|
|
29
|
+
# Return _left_ with leading whitespace removed.
|
|
30
|
+
# Coerce _left_ to a string if it is not one already.
|
|
31
|
+
def self.lstrip: (FilterContext context, untyped left) -> untyped
|
|
32
|
+
|
|
33
|
+
# Return _left_ with trailing whitespace removed.
|
|
34
|
+
# Coerce _left_ to a string if it is not one already.
|
|
35
|
+
def self.rstrip: (FilterContext context, untyped left) -> untyped
|
|
36
|
+
|
|
37
|
+
# Return _left_ with leading and trailing whitespace removed.
|
|
38
|
+
# Coerce _left_ to a string if it is not one already.
|
|
39
|
+
def self.strip: (FilterContext context, untyped left) -> untyped
|
|
40
|
+
|
|
41
|
+
# Return _left_ with LF or CRLF replaced with `<br />\n`.
|
|
42
|
+
def self.newline_to_br: (FilterContext context, untyped left) -> untyped
|
|
43
|
+
|
|
44
|
+
# Return _right_ concatenated with _left_.
|
|
45
|
+
# Coerce _left_ and _right_ to strings if they aren't strings already.
|
|
46
|
+
def self.prepend_: (FilterContext context, untyped left, untyped right) -> untyped
|
|
47
|
+
|
|
48
|
+
# Return _left_ with all occurrences of _pattern_ replaced with _replacement_.
|
|
49
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
50
|
+
def self.replace: (FilterContext context, untyped left, untyped pattern, ?::String replacement) -> untyped
|
|
51
|
+
|
|
52
|
+
# Return _left_ with the first occurrence of _pattern_ replaced with _replacement_.
|
|
53
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
54
|
+
def self.replace_first: (FilterContext context, untyped left, untyped pattern, ?::String replacement) -> untyped
|
|
55
|
+
|
|
56
|
+
# Return _left_ with the last occurrence of _pattern_ replaced with _replacement_.
|
|
57
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
58
|
+
def self.replace_last: (FilterContext context, untyped left, untyped pattern, untyped replacement) -> untyped
|
|
59
|
+
|
|
60
|
+
# Return _left_ with all occurrences of _pattern_ removed.
|
|
61
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
62
|
+
def self.remove: (FilterContext context, untyped left, untyped pattern) -> untyped
|
|
63
|
+
|
|
64
|
+
# Return _left_ with the first occurrence of _pattern_ removed.
|
|
65
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
66
|
+
def self.remove_first: (FilterContext context, untyped left, untyped pattern) -> untyped
|
|
67
|
+
|
|
68
|
+
# Return _left_ with the last occurrence of _pattern_ removed.
|
|
69
|
+
# All arguments are coerced to strings if they aren't strings already.
|
|
70
|
+
def self.remove_last: (FilterContext context, untyped left, untyped pattern) -> untyped
|
|
71
|
+
|
|
72
|
+
# Split _left_ on every occurrence of _pattern_.
|
|
73
|
+
def self.split: (FilterContext context, untyped left, untyped pattern) -> untyped
|
|
74
|
+
|
|
75
|
+
RE_HTML_BLOCKS: ::Regexp
|
|
76
|
+
|
|
77
|
+
RE_HTML_TAGS: ::Regexp
|
|
78
|
+
|
|
79
|
+
# Return _left_ with HTML tags removed.
|
|
80
|
+
def self.strip_html: (FilterContext context, untyped left) -> untyped
|
|
81
|
+
|
|
82
|
+
# Return _left_ with CR and LF removed.
|
|
83
|
+
def self.strip_newlines: (FilterContext context, untyped left) -> untyped
|
|
84
|
+
|
|
85
|
+
def self.truncate: (FilterContext context, untyped left, ?::Integer max_length, ?::String ellipsis) -> untyped
|
|
86
|
+
|
|
87
|
+
def self.truncatewords: (FilterContext context, untyped left, ?::Integer max_words, ?::String ellipsis) -> untyped
|
|
88
|
+
|
|
89
|
+
def self.url_encode: (FilterContext context, untyped left) -> untyped
|
|
90
|
+
|
|
91
|
+
def self.url_decode: (FilterContext context, untyped left) -> untyped
|
|
92
|
+
|
|
93
|
+
def self.base64_encode: (FilterContext context, untyped left) -> untyped
|
|
94
|
+
|
|
95
|
+
def self.base64_decode: (FilterContext context, untyped left) -> untyped
|
|
96
|
+
|
|
97
|
+
def self.base64_url_safe_encode: (FilterContext context, untyped left) -> untyped
|
|
98
|
+
|
|
99
|
+
def self.base64_url_safe_decode: (FilterContext context, untyped left) -> untyped
|
|
100
|
+
|
|
101
|
+
def self.squish: (FilterContext context, untyped left) -> untyped
|
|
102
|
+
end
|
|
103
|
+
end
|
data/sig/luoma/fnv.rbs
ADDED
data/sig/luoma/lexer.rbs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
class BaseLexer
|
|
3
|
+
@env: Environment
|
|
4
|
+
|
|
5
|
+
@source: String
|
|
6
|
+
|
|
7
|
+
@scanner: StringScanner
|
|
8
|
+
|
|
9
|
+
@start: Integer
|
|
10
|
+
|
|
11
|
+
@tokens: Array[t_token]
|
|
12
|
+
|
|
13
|
+
attr_reader tokens: Array[t_token]
|
|
14
|
+
|
|
15
|
+
def self.tokenize: (Environment env, String source) -> Array[t_token]
|
|
16
|
+
|
|
17
|
+
def initialize: (Environment env, String source) -> void
|
|
18
|
+
|
|
19
|
+
def go: () -> void
|
|
20
|
+
|
|
21
|
+
# () -> Symbol?
|
|
22
|
+
def scan_markup: () -> Symbol?
|
|
23
|
+
|
|
24
|
+
# (t_token_kind) -> void
|
|
25
|
+
def emit: (t_token_kind kind) -> void
|
|
26
|
+
|
|
27
|
+
# (Regexp) -> Integer?
|
|
28
|
+
def index: (Regexp pattern) -> Integer?
|
|
29
|
+
|
|
30
|
+
# (Regexp) -> String?
|
|
31
|
+
def scan: (Regexp pattern) -> String?
|
|
32
|
+
|
|
33
|
+
# (Regexp) -> bool
|
|
34
|
+
def scan_until?: (Regexp pattern) -> bool
|
|
35
|
+
|
|
36
|
+
# (Regexp) -> bool
|
|
37
|
+
def skip?: (Regexp pattern) -> bool
|
|
38
|
+
|
|
39
|
+
# (Regexp) -> bool
|
|
40
|
+
def skip_until?: (Regexp pattern) -> bool
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
# A single-pass template tokenizer that matches Shopify/liquid v5.12.0 strict
|
|
3
|
+
# mode syntax and semantics.
|
|
4
|
+
#
|
|
5
|
+
# We use lookahead and byte offset limits to achieve behavior equivalent to
|
|
6
|
+
# Shopify's two-pass tokenizer/parser.
|
|
7
|
+
class LegacyLexer < BaseLexer
|
|
8
|
+
RE_MARKUP: ::Regexp
|
|
9
|
+
|
|
10
|
+
RE_OUT_END: ::Regexp
|
|
11
|
+
|
|
12
|
+
RE_UP_TO_OUT_END: ::Regexp
|
|
13
|
+
|
|
14
|
+
RE_TAG_END: ::Regexp
|
|
15
|
+
|
|
16
|
+
RE_UP_TO_TAG_END: ::Regexp
|
|
17
|
+
|
|
18
|
+
RE_TRIVIA: ::Regexp
|
|
19
|
+
|
|
20
|
+
RE_LINE_TRIVIA: ::Regexp
|
|
21
|
+
|
|
22
|
+
RE_TAG_NAME: ::Regexp
|
|
23
|
+
|
|
24
|
+
RE_PUNCTUATION: ::Regexp
|
|
25
|
+
|
|
26
|
+
RE_IDENT: ::Regexp
|
|
27
|
+
|
|
28
|
+
RE_FLOAT: ::Regexp
|
|
29
|
+
|
|
30
|
+
RE_INT: ::Regexp
|
|
31
|
+
|
|
32
|
+
RE_COMMENT_SEGMENT: ::Regexp
|
|
33
|
+
|
|
34
|
+
RE_LINE_COMMENT_SEGMENT: ::Regexp
|
|
35
|
+
|
|
36
|
+
RE_END_DOC: ::Regexp
|
|
37
|
+
|
|
38
|
+
RE_END_RAW: ::Regexp
|
|
39
|
+
|
|
40
|
+
TOKEN_MAP: Hash[String, t_token_kind]
|
|
41
|
+
|
|
42
|
+
# () -> Symbol?
|
|
43
|
+
def scan_markup: () -> Symbol?
|
|
44
|
+
|
|
45
|
+
# (Integer) -> void
|
|
46
|
+
def accept_tag: (Integer limit) -> void
|
|
47
|
+
|
|
48
|
+
# (Integer) -> void
|
|
49
|
+
def accept_expression: (Integer limit , ?Regexp trivia) -> void
|
|
50
|
+
|
|
51
|
+
# (Integer) -> void
|
|
52
|
+
def accept_inline_comment: (Integer limit) -> void
|
|
53
|
+
|
|
54
|
+
# (Integer) -> void
|
|
55
|
+
def accept_block_comment: (Integer limit) -> void
|
|
56
|
+
|
|
57
|
+
# (Integer) -> void
|
|
58
|
+
def accept_doc_comment: (Integer limit) -> void
|
|
59
|
+
|
|
60
|
+
# (Integer) -> void
|
|
61
|
+
def accept_raw_tag: (Integer limit) -> void
|
|
62
|
+
|
|
63
|
+
# (Integer) -> void
|
|
64
|
+
def accept_line_statements: (Integer limit) -> void
|
|
65
|
+
|
|
66
|
+
# (Integer) -> void
|
|
67
|
+
def accept_line_block_comment: (Integer limit) -> void
|
|
68
|
+
|
|
69
|
+
# (Integer) -> void
|
|
70
|
+
def accept_line_doc_comment: (Integer limit) -> void
|
|
71
|
+
|
|
72
|
+
# (Integer) -> void
|
|
73
|
+
def accept_line_raw_tag: (Integer limit) -> void
|
|
74
|
+
|
|
75
|
+
# (Integer) -> void
|
|
76
|
+
def accept_string_literal: (Integer limit) -> void
|
|
77
|
+
|
|
78
|
+
# () -> bool
|
|
79
|
+
def accept_whitespace_control?: () -> bool
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
class UnifiedLexer < BaseLexer
|
|
3
|
+
RE_FLOAT: ::Regexp
|
|
4
|
+
|
|
5
|
+
RE_INT: ::Regexp
|
|
6
|
+
|
|
7
|
+
RE_MARKUP_START: ::Regexp
|
|
8
|
+
|
|
9
|
+
RE_OUTPUT_END: ::Regexp
|
|
10
|
+
|
|
11
|
+
RE_PUNCTUATION: ::Regexp
|
|
12
|
+
|
|
13
|
+
RE_RAW_END: ::Regexp
|
|
14
|
+
|
|
15
|
+
RE_TAG_END: ::Regexp
|
|
16
|
+
|
|
17
|
+
RE_TAG_NAME: ::Regexp
|
|
18
|
+
|
|
19
|
+
RE_TRIVIA: ::Regexp
|
|
20
|
+
|
|
21
|
+
RE_WHITESPACE_CONTROL: ::Regexp
|
|
22
|
+
|
|
23
|
+
RE_WORD: ::Regexp
|
|
24
|
+
|
|
25
|
+
RE_HASH_COUNT: Hash[Integer, Regexp]
|
|
26
|
+
|
|
27
|
+
# Keywords and symbols that get their own token kind.
|
|
28
|
+
TOKEN_MAP: Hash[String, t_token_kind]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# () -> void?
|
|
32
|
+
def accept_tag: () -> void
|
|
33
|
+
|
|
34
|
+
# () -> void
|
|
35
|
+
def accept_expression: () -> void
|
|
36
|
+
|
|
37
|
+
# () -> void
|
|
38
|
+
def accept_comment: () -> void
|
|
39
|
+
|
|
40
|
+
# () -> void
|
|
41
|
+
def accept_string: () -> void
|
|
42
|
+
|
|
43
|
+
# () -> void
|
|
44
|
+
def accept_object: () -> void
|
|
45
|
+
|
|
46
|
+
# () -> bool
|
|
47
|
+
def accept_whitespace_control?: () -> bool
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
# The base class for all template loaders.
|
|
3
|
+
class TemplateLoader
|
|
4
|
+
# Load and return template source text and any associated data.
|
|
5
|
+
# (Environment, String, ?context: RenderContext?, **untyped) -> TemplateSource
|
|
6
|
+
def get_source: (Environment env, String name, ?context: RenderContext?, **untyped kwargs) -> TemplateSource
|
|
7
|
+
|
|
8
|
+
# (Environment, String, ?globals: t_namespace?, ?context: RenderContext?, **kwargs) -> Template
|
|
9
|
+
def load: (Environment env, String name, ?globals: t_namespace?, ?context: RenderContext?, **untyped kwargs) -> Template
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Template source text and meta data.
|
|
13
|
+
class TemplateSource
|
|
14
|
+
@source: String
|
|
15
|
+
|
|
16
|
+
@name: String
|
|
17
|
+
|
|
18
|
+
@up_to_date: Proc::_Callable?
|
|
19
|
+
|
|
20
|
+
@matter: t_namespace?
|
|
21
|
+
|
|
22
|
+
attr_accessor source: String
|
|
23
|
+
|
|
24
|
+
attr_accessor name: String
|
|
25
|
+
|
|
26
|
+
attr_accessor up_to_date: Proc::_Callable?
|
|
27
|
+
|
|
28
|
+
attr_accessor matter: t_namespace?
|
|
29
|
+
|
|
30
|
+
def initialize: (source: String, name: String, ?up_to_date: Proc::_Callable?, ?matter: t_namespace?) -> void
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# A template loader that reads templates from a hash.
|
|
34
|
+
class HashLoader < TemplateLoader
|
|
35
|
+
@templates: Hash[String, String]
|
|
36
|
+
|
|
37
|
+
#: (Hash<String, String>) -> void
|
|
38
|
+
def initialize: (Hash[String, String] templates) -> void
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
# A template loader that reads template from a file system.
|
|
3
|
+
class FileSystemLoader < TemplateLoader
|
|
4
|
+
@search_path: Array[Pathname]
|
|
5
|
+
|
|
6
|
+
@default_extension: String?
|
|
7
|
+
|
|
8
|
+
def initialize: (String | Array[String] search_path, ?default_extension: String?) -> void
|
|
9
|
+
|
|
10
|
+
def resolve_path: (String template_name) -> Pathname
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# A file system template loader that caches parsed templates.
|
|
14
|
+
class CachingFileSystemLoader < FileSystemLoader
|
|
15
|
+
include CachingLoaderMixin
|
|
16
|
+
|
|
17
|
+
def initialize: (String | Array[String] search_path, ?default_extension: String?, ?auto_reload: bool, ?namespace_key: ::String, ?capacity: ::Integer, ?thread_safe: bool) -> void
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
# A mixin that adds caching to a template loader.
|
|
3
|
+
module CachingLoaderMixin
|
|
4
|
+
@auto_reload: bool
|
|
5
|
+
|
|
6
|
+
@namespace_key: String?
|
|
7
|
+
|
|
8
|
+
@cache: LRUCache
|
|
9
|
+
|
|
10
|
+
def initialize_cache: (?auto_reload: bool, ?namespace_key: ::String, ?capacity: ::Integer, ?thread_safe: bool) -> untyped
|
|
11
|
+
|
|
12
|
+
def load: (Environment env, String name, ?globals: _Namespace?, ?context: RenderContext?, **untyped kwargs) -> Template
|
|
13
|
+
|
|
14
|
+
def cache_key: (String name, ?context: RenderContext?, **untyped kwargs) -> String
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
interface _Tag
|
|
3
|
+
def parse: (t_token, String, Parser) -> Markup
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# The base class for all tag nodes and the output statement.
|
|
7
|
+
class Markup
|
|
8
|
+
@token: t_token
|
|
9
|
+
|
|
10
|
+
@blank: bool
|
|
11
|
+
|
|
12
|
+
@tag_name: String
|
|
13
|
+
|
|
14
|
+
attr_reader token: t_token
|
|
15
|
+
|
|
16
|
+
attr_reader blank: bool
|
|
17
|
+
|
|
18
|
+
attr_reader tag_name: String
|
|
19
|
+
|
|
20
|
+
# (t_token) -> void
|
|
21
|
+
def initialize: (t_token token) -> void
|
|
22
|
+
|
|
23
|
+
# (RenderContext, String) -> void
|
|
24
|
+
def render: (RenderContext context, String buffer) -> void
|
|
25
|
+
|
|
26
|
+
# (RenderContext) -> Array[Markup]
|
|
27
|
+
def children: (RenderContext static_context) -> ::Array[Markup]
|
|
28
|
+
|
|
29
|
+
# () -> Array[Expression]
|
|
30
|
+
def expressions: () -> ::Array[Expression]
|
|
31
|
+
|
|
32
|
+
# () -> Array[Name]
|
|
33
|
+
def block_scope: () -> ::Array[Name]
|
|
34
|
+
|
|
35
|
+
# () -> Array[Name]
|
|
36
|
+
def template_scope: () -> ::Array[Name]
|
|
37
|
+
|
|
38
|
+
# (RenderContext) -> Partial?
|
|
39
|
+
def partial: (RenderContext static_context) -> Partial?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class Partial
|
|
43
|
+
@template: Template
|
|
44
|
+
|
|
45
|
+
@scope_kind: (:shared | :isolated | :inherited)
|
|
46
|
+
|
|
47
|
+
@in_scope: Array[Name]
|
|
48
|
+
|
|
49
|
+
@key: Integer
|
|
50
|
+
|
|
51
|
+
attr_reader template: Template
|
|
52
|
+
|
|
53
|
+
attr_reader scope_kind: :shared | :isolated | :inherited
|
|
54
|
+
|
|
55
|
+
attr_reader in_scope: Array[Name]
|
|
56
|
+
|
|
57
|
+
attr_reader key: Integer
|
|
58
|
+
|
|
59
|
+
# (Template, :shared | :isolated | :inherited, Array[Name], Integer) -> void
|
|
60
|
+
def initialize: (Template template, :shared | :isolated | :inherited scope_kind, Array[Name] in_scope, Integer key) -> void
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# (t_block, RenderContext, String) -> void
|
|
64
|
+
def self.render_block: (t_block block, RenderContext context, String buffer, ?root: bool) -> void
|
|
65
|
+
|
|
66
|
+
# (t_block) -> bool
|
|
67
|
+
def self.blank_block?: (t_block block) -> bool
|
|
68
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Luoma
|
|
2
|
+
class Parser
|
|
3
|
+
@env: Environment
|
|
4
|
+
|
|
5
|
+
@source: String
|
|
6
|
+
|
|
7
|
+
@template_name: String
|
|
8
|
+
|
|
9
|
+
@tokens: Array[t_token]
|
|
10
|
+
|
|
11
|
+
@pos: Integer
|
|
12
|
+
|
|
13
|
+
@eoi: t_token
|
|
14
|
+
|
|
15
|
+
@whitespace_control_carry: "-" | "+" | "~" | nil
|
|
16
|
+
|
|
17
|
+
TERMINATE_EXPRESSION: Set[t_token_kind]
|
|
18
|
+
|
|
19
|
+
attr_reader env: Environment
|
|
20
|
+
|
|
21
|
+
attr_reader source: String
|
|
22
|
+
|
|
23
|
+
attr_reader template_name: String
|
|
24
|
+
|
|
25
|
+
# (Environment, String, String, Array[t_token]) -> t_block
|
|
26
|
+
def self.parse: (Environment env, String source, String template_name, Array[t_token] tokens) -> t_block
|
|
27
|
+
|
|
28
|
+
# (Environment, String, String, Array[t_token]) -> void
|
|
29
|
+
def initialize: (Environment env, String source, String template_name, Array[t_token] tokens) -> void
|
|
30
|
+
|
|
31
|
+
# () -> void
|
|
32
|
+
def carry_whitespace_control: () -> void
|
|
33
|
+
|
|
34
|
+
# () -> t_token
|
|
35
|
+
def current: () -> t_token
|
|
36
|
+
|
|
37
|
+
# () -> t_token_kind
|
|
38
|
+
def kind: () -> t_token_kind
|
|
39
|
+
|
|
40
|
+
# () -> String
|
|
41
|
+
def current_value: () -> String
|
|
42
|
+
|
|
43
|
+
# () -> t_token
|
|
44
|
+
def next: () -> t_token
|
|
45
|
+
|
|
46
|
+
def peek: (?::Integer offset) -> t_token
|
|
47
|
+
|
|
48
|
+
# (t_token_kind, ?message: String?) -> t_token
|
|
49
|
+
def eat: (t_token_kind kind, ?message: String?) -> t_token
|
|
50
|
+
|
|
51
|
+
# (String) -> t_token
|
|
52
|
+
def eat_empty_tag: (String name) -> t_token
|
|
53
|
+
|
|
54
|
+
# (Set[t_token_kind]) -> t_token
|
|
55
|
+
def eat_one_of: (Set[t_token_kind] kinds) -> t_token
|
|
56
|
+
|
|
57
|
+
# (String) -> t_token
|
|
58
|
+
def eat_tag: (String name) -> t_token
|
|
59
|
+
|
|
60
|
+
# Raise an error if we're not at the start of an expression.
|
|
61
|
+
# () -> void
|
|
62
|
+
def expect_expression: () -> void
|
|
63
|
+
|
|
64
|
+
# (?require_commas: bool?) -> Array[Expression | KeywordArgument]
|
|
65
|
+
def parse_arguments: (?require_commas: bool?) -> Array[Expression | KeywordArgument]
|
|
66
|
+
|
|
67
|
+
# (?stop: Set[String]?) -> t_block
|
|
68
|
+
def parse_block: (?stop: Set[String]?) -> t_block
|
|
69
|
+
|
|
70
|
+
# (?precedence: Integer) -> Expression
|
|
71
|
+
def parse_expression: (?precedence: Integer) -> Expression
|
|
72
|
+
|
|
73
|
+
# () -> Name
|
|
74
|
+
def parse_ident: () -> Name
|
|
75
|
+
|
|
76
|
+
# (?require_commas: bool?) -> Array[KeywordArgument]
|
|
77
|
+
def parse_keyword_arguments: (?require_commas: bool?) -> Array[KeywordArgument]
|
|
78
|
+
|
|
79
|
+
# Parse an identifier, possibly surrounded by quotes.
|
|
80
|
+
# () -> Name
|
|
81
|
+
def parse_name: () -> Name
|
|
82
|
+
|
|
83
|
+
# (?require_commas: bool?) -> Array[Expression]
|
|
84
|
+
def parse_positional_arguments: (?require_commas: bool?) -> Array[Expression]
|
|
85
|
+
|
|
86
|
+
# () -> StringLiteral
|
|
87
|
+
def parse_string_literal: () -> StringLiteral
|
|
88
|
+
|
|
89
|
+
# () -> String
|
|
90
|
+
def peek_tag_name: () -> String
|
|
91
|
+
|
|
92
|
+
# () -> String?
|
|
93
|
+
def peek_whitespace_control: () -> String?
|
|
94
|
+
|
|
95
|
+
# () -> void
|
|
96
|
+
def skip_whitespace_control: () -> void
|
|
97
|
+
|
|
98
|
+
# Return `true` if we're at the start of a tag named `name`.
|
|
99
|
+
# (String) -> bool
|
|
100
|
+
def tag?: (String name) -> bool
|
|
101
|
+
|
|
102
|
+
# (Set[String]) -> String?
|
|
103
|
+
def tags: (Set[String] names) -> String?
|
|
104
|
+
end
|
|
105
|
+
end
|