klenod-build 0.0.22 → 0.0.24

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7873fce94ba35f8420b6aa896bca1866896d5c9f038102f0d13522fb1fa9a16
4
- data.tar.gz: 715c13a86148ae750ed6151f05e4fbcb32d1d73bf21d139d1b21d42f7bb405f4
3
+ metadata.gz: 6f22c9acfae008123fd3b68c5ab499c7bc8df3da4d5e135dea331f0fe6563596
4
+ data.tar.gz: da87ac500d4d0f26bdeb4ff3249afacd1e34d594bb2f4e18bff1c1c4dd818e64
5
5
  SHA512:
6
- metadata.gz: 29157efe18cfdd5982f05ef742f07bb56ee64f54c820b152569be703b76a97dc76f71c166b67ff57e8b5124bed59f16ecbcf39415118dba3672a304854d4fbfa
7
- data.tar.gz: 0a0b9e45f353aa70004c01ed9f78d1fe6ef667c7eb4faa5e7c64d038087ed82501c7f77755ed5e67dd26504ac122ee14a7c5414164b36c5933afae86df89df37
6
+ metadata.gz: 0dd4bce3f8c250ed256e4362e6337f8ddee38c2865b9aba9ae7153066b1fb4d34f0fb324714626b4787011fde4118b1bc3f80a487865e2ee409248aebb44375f
7
+ data.tar.gz: a65805c594f8d0823ce2df36a1b9d2f5c00e7b5ff71d3a178c1b8d7cc5f24a0f69d09d5d254d8bd16479d9c476b3ac14f67d097ea28efb2ccc7d89fd34f6dcec
@@ -40,13 +40,28 @@ module Klenod
40
40
  # `video` plus a `.id` class. Extend that form to ordinary Ruby
41
41
  # member and index expressions while leaving all other attributes on
42
42
  # Haml's native parsing path.
43
+ #
44
+ # Haml also continues a parenthesized list onto following lines only
45
+ # after the first attribute, so `%a(` followed by a line break is an
46
+ # invalid attribute list. Join the lines of an unclosed list first so
47
+ # both forms work across lines.
43
48
  def parse_new_attributes(text)
44
- balanced, rest = ::Haml::Util.balance(text, "(", ")")
45
- pairs = balanced && extended_attribute_pairs(balanced[1...-1])
46
- return super unless pairs&.any? { |_name, value| value.match?(/[.\[]/) }
49
+ joined_lines = 0
50
+ until (close_index = attribute_list_close_index(text)) || @next_line.eod?
51
+ text = "#{text} #{@next_line.text}"
52
+ joined_lines += 1
53
+ next_line
54
+ end
55
+
56
+ pairs = close_index && extended_attribute_pairs(text[1...close_index])
57
+ rest = close_index && text[(close_index + 1)..]
58
+ unless pairs&.any? { |_name, value| value.match?(/[.\[]/) }
59
+ attributes, rest, last_line = super
60
+ return [attributes, rest, last_line + joined_lines]
61
+ end
47
62
 
48
63
  dynamic = pairs.reduce("{") { |source, (name, value)| "#{source}#{::Haml::Util.inspect_obj(name)} => #{value}," } << "}"
49
- [[{}, dynamic], rest, @line.index + 1]
64
+ [[{}, dynamic], rest, @line.index + 1 + joined_lines]
50
65
  end
51
66
 
52
67
  def annotate_tag_nodes(root)
@@ -132,6 +147,36 @@ module Klenod
132
147
  pairs
133
148
  end
134
149
 
150
+ # Returns the index of the `)` that closes the list opened at index 0,
151
+ # ignoring brackets inside quoted values.
152
+ def attribute_list_close_index(source)
153
+ depth = 0
154
+ quote = nil
155
+ escaped = false
156
+
157
+ source.each_char.with_index do |character, index|
158
+ if quote
159
+ if escaped
160
+ escaped = false
161
+ elsif character == "\\"
162
+ escaped = true
163
+ elsif character == quote
164
+ quote = nil
165
+ end
166
+ else
167
+ case character
168
+ when "'", '"' then quote = character
169
+ when "(", "[", "{" then depth += 1
170
+ when ")", "]", "}"
171
+ depth -= 1
172
+ return index if depth.zero?
173
+ end
174
+ end
175
+ end
176
+
177
+ nil
178
+ end
179
+
135
180
  def attribute_boundary?(remaining_source)
136
181
  attribute_sequence?(remaining_source)
137
182
  end
@@ -585,7 +585,7 @@ module Klenod
585
585
  return source unless source.include?("__LINE__")
586
586
 
587
587
  line_offsets = [0]
588
- source.each_line(chomp: false) { |line| line_offsets << line_offsets.last + line.length }
588
+ source.each_line(chomp: false) { |line| line_offsets << line_offsets.last + line.bytesize }
589
589
 
590
590
  Ripper
591
591
  .lex(source)
@@ -593,7 +593,7 @@ module Klenod
593
593
  .reverse_each
594
594
  .each_with_object(source.dup) do |((line, column), _type, token, _state), rewritten|
595
595
  offset = line_offsets.fetch(line - 1) + column
596
- rewritten[offset, token.length] = line_no.to_s
596
+ rewritten.bytesplice(offset, token.bytesize, line_no.to_s)
597
597
  end
598
598
  end
599
599
 
@@ -607,7 +607,7 @@ module Klenod
607
607
  return source if @variables.empty?
608
608
 
609
609
  line_offsets = [0]
610
- source.each_line(chomp: false) { |line| line_offsets << line_offsets.last + line.length }
610
+ source.each_line(chomp: false) { |line| line_offsets << line_offsets.last + line.bytesize }
611
611
 
612
612
  tokens = Ripper.lex(source)
613
613
 
@@ -617,17 +617,17 @@ module Klenod
617
617
  kind, prefix, pattern = VARIABLE_TOKEN_KINDS[type]
618
618
  receiver = @variables[kind]
619
619
  if type == :on_gvar && token == "$*" && receiver
620
- [offset_for(line_offsets, line, column), token.length, receiver]
620
+ [offset_for(line_offsets, line, column), token.bytesize, receiver]
621
621
  elsif receiver && token.match?(pattern)
622
622
  name = token.delete_prefix(prefix)
623
623
  replacement = "(#{receiver})[#{symbol_source(name)}]"
624
624
  replacement = "{#{replacement}}" if tokens[index - 1]&.fetch(1) == :on_embvar
625
- [offset_for(line_offsets, line, column), token.length, replacement]
625
+ [offset_for(line_offsets, line, column), token.bytesize, replacement]
626
626
  end
627
627
  end
628
628
  .reverse_each
629
629
  .each_with_object(source.dup) do |(offset, length, replacement), rewritten|
630
- rewritten[offset, length] = replacement
630
+ rewritten.bytesplice(offset, length, replacement)
631
631
  end
632
632
  end
633
633
 
@@ -5,6 +5,7 @@ require "ripper"
5
5
 
6
6
  require "klenod/runtime/source_map"
7
7
  require_relative "../markdown_compiler"
8
+ require_relative "../text_interpolation"
8
9
  require_relative "parser"
9
10
 
10
11
  module Klenod
@@ -613,11 +614,18 @@ module Klenod
613
614
  def compile_filter_node(node, builder:, markdown_compiler:)
614
615
  return builder.render_ruby_filter(compile_ruby_filter(node, builder: builder)) if ruby_filter?(node)
615
616
  return builder.expression(markdown_compiler.compile(node.value.fetch(:text), interpolate: true)) if markdown_filter?(node)
616
- return builder.literal(node.value.fetch(:text).to_s) if plain_filter?(node)
617
+ return compile_plain_filter(node.value.fetch(:text).to_s, builder: builder) if plain_filter?(node)
617
618
 
618
619
  raise ArgumentError, "Only :ruby, :markdown, and :plain Haml filters are supported"
619
620
  end
620
621
 
622
+ def compile_plain_filter(text, builder:)
623
+ source = TextInterpolation::Source.new(text)
624
+ return builder.literal(source.literal(source.text)) unless source.interpolated?
625
+
626
+ builder.expression("[#{source.expressions(source.text).join(", ")}]")
627
+ end
628
+
621
629
  def ruby_filter?(node)
622
630
  node.type == :filter && node.value.fetch(:name) == "ruby"
623
631
  end
@@ -9,11 +9,13 @@ ensure
9
9
  $VERBOSE = previous_verbose
10
10
  end
11
11
 
12
+ require_relative "text_interpolation"
13
+
12
14
  module Klenod
13
15
  module Build
14
16
  module Plugins
15
17
  class MarkdownCompiler
16
- ESCAPED_INTERPOLATION_SENTINEL = "\uE000klenod_escaped_interpolation\uE000"
18
+ TYPOGRAPHIC_TEXT = Kramdown::Converter::Html::TYPOGRAPHIC_SYMS.transform_values { |entities| entities.map(&:char).join }.freeze
17
19
 
18
20
  def initialize(factory:, components_source: "{}")
19
21
  @factory = factory
@@ -21,69 +23,95 @@ module Klenod
21
23
  end
22
24
 
23
25
  def compile(source, interpolate: false)
24
- source = protect_escaped_interpolation(source) if interpolate
25
- document = Kramdown::Document.new(source, input: "GFM", hard_wrap: false)
26
- compile_children(document.root.children, interpolate: interpolate)
26
+ @interpolation = TextInterpolation::Source.new(source) if interpolate
27
+ document = Kramdown::Document.new(@interpolation&.text || source, input: "GFM", hard_wrap: false)
28
+ compile_children(document.root.children)
29
+ ensure
30
+ @interpolation = nil
27
31
  end
28
32
 
29
33
  private
30
34
 
31
- def compile_children(children, parent: nil, interpolate: false)
32
- expressions = compile_child_expressions(children, parent: parent, interpolate: interpolate)
35
+ def compile_children(children, parent: nil)
36
+ expressions = compile_child_expressions(children, parent: parent)
33
37
  return "nil" if expressions.empty?
34
38
  return expressions.fetch(0) if expressions.length == 1
35
39
 
36
40
  "[#{expressions.join(", ")}]"
37
41
  end
38
42
 
39
- def compile_child_expressions(children, parent:, interpolate:, table_section: nil)
40
- children.flat_map { |child| compile_node(child, parent: parent, table_section: table_section, interpolate: interpolate) }.compact
43
+ def compile_child_expressions(children, parent:, table_section: nil)
44
+ merge_text_nodes(children).flat_map { |child| compile_node(child, parent: parent, table_section: table_section) }.compact
45
+ end
46
+
47
+ # Kramdown splits typographic replacements and entities out of text.
48
+ # Fold them back into neighboring text so "it's" stays one string.
49
+ def merge_text_nodes(children)
50
+ children.each_with_object([]) do |child, merged|
51
+ text = inline_text(child)
52
+ if text.nil?
53
+ merged << child
54
+ elsif merged.last&.type == :text
55
+ merged[-1] = Kramdown::Element.new(:text, merged.last.value + text)
56
+ else
57
+ merged << Kramdown::Element.new(:text, text)
58
+ end
59
+ end
60
+ end
61
+
62
+ def inline_text(node)
63
+ case node.type
64
+ when :text then node.value
65
+ when :smart_quote then Kramdown::Utils::Entities.entity(node.value.to_s).char
66
+ when :typographic_sym then TYPOGRAPHIC_TEXT.fetch(node.value)
67
+ when :entity then node.value.char
68
+ end
41
69
  end
42
70
 
43
- def compile_node(node, parent: nil, table_section: nil, interpolate: false)
71
+ def compile_node(node, parent: nil, table_section: nil)
44
72
  case node.type
45
73
  when :root
46
- [compile_children(node.children, parent: node, interpolate: interpolate)]
74
+ [compile_children(node.children, parent: node)]
47
75
  when :blank
48
76
  nil
49
77
  when :text
50
- text_expressions(node.value, interpolate: interpolate)
78
+ text_expressions(node.value)
51
79
  when :p
52
- return compile_child_expressions(node.children, parent: node, interpolate: interpolate) if node.options[:transparent]
80
+ return compile_child_expressions(node.children, parent: node) if node.options[:transparent]
53
81
 
54
- [factory_call(:p, node.children, attrs: node.attr, parent: node, interpolate: interpolate)]
82
+ [factory_call(:p, node.children, attrs: node.attr, parent: node)]
55
83
  when :header
56
- [factory_call(:"h#{node.options.fetch(:level)}", node.children, attrs: node.attr, parent: node, interpolate: interpolate)]
84
+ [factory_call(:"h#{node.options.fetch(:level)}", node.children, attrs: header_attrs(node), parent: node)]
57
85
  when :em, :strong, :a, :blockquote, :ul, :ol, :li, :table
58
- [factory_call(node.type, node.children, attrs: node.attr, parent: node, interpolate: interpolate)]
86
+ [factory_call(node.type, node.children, attrs: node.attr, parent: node)]
59
87
  when :thead, :tbody
60
- [factory_call(node.type, node.children, attrs: node.attr, parent: node, table_section: node.type, interpolate: interpolate)]
88
+ [factory_call(node.type, node.children, attrs: node.attr, parent: node, table_section: node.type)]
61
89
  when :tr
62
- [factory_call(node.type, node.children, attrs: node.attr, parent: node, table_section: table_section, interpolate: interpolate)]
90
+ [factory_call(node.type, node.children, attrs: node.attr, parent: node, table_section: table_section)]
63
91
  when :td
64
- [factory_call((table_section == :thead) ? :th : :td, node.children, attrs: node.attr, parent: node, table_section: table_section, interpolate: interpolate)]
92
+ [factory_call((table_section == :thead) ? :th : :td, node.children, attrs: node.attr, parent: node, table_section: table_section)]
65
93
  when :img, :hr, :br
66
- [factory_call(node.type, [], attrs: node.attr, parent: node, interpolate: interpolate)]
94
+ [factory_call(node.type, [], attrs: node.attr, parent: node)]
67
95
  when :codespan
68
- [factory_call(:code, [node], raw_text: node.value, attrs: node.attr, parent: node, interpolate: interpolate)]
96
+ [factory_call(:code, [node], raw_text: node.value, attrs: node.attr, parent: node)]
69
97
  when :codeblock
70
- code = factory_call(:code, [node], raw_text: node.value, attrs: node.attr, parent: node, interpolate: interpolate)
71
- [factory_call(:pre, [], child_sources: [code], parent: node, interpolate: interpolate)]
98
+ code = factory_call(:code, [node], raw_text: node.value, attrs: node.attr, parent: node)
99
+ [factory_call(:pre, [], child_sources: [code], parent: node)]
72
100
  when :html_element
73
- [factory_call(node.value.to_sym, node.children, attrs: node.attr, parent: node, interpolate: interpolate)]
101
+ [factory_call(node.value.to_sym, node.children, attrs: node.attr, parent: node)]
74
102
  when :raw
75
- [restore_escaped_interpolation(node.value.to_s).inspect]
103
+ [literal_text(node.value.to_s).inspect]
76
104
  else
77
- [compile_children(node.children, parent: node, interpolate: interpolate)]
105
+ [compile_children(node.children, parent: node)]
78
106
  end
79
107
  end
80
108
 
81
- def factory_call(tag, children, parent:, attrs: {}, raw_text: nil, child_sources: nil, table_section: nil, interpolate: false)
109
+ def factory_call(tag, children, parent:, attrs: {}, raw_text: nil, child_sources: nil, table_section: nil)
82
110
  child_sources ||=
83
111
  if raw_text.nil?
84
- compile_child_expressions(children, parent: parent, table_section: table_section, interpolate: interpolate)
112
+ compile_child_expressions(children, parent: parent, table_section: table_section)
85
113
  else
86
- [restore_escaped_interpolation(raw_text).inspect]
114
+ [literal_text(raw_text).inspect]
87
115
  end
88
116
  tag_source = tag_source(tag)
89
117
  parts = [tag_source, *child_sources]
@@ -97,82 +125,33 @@ module Klenod
97
125
  end
98
126
 
99
127
  def attrs_source(attrs)
100
- attrs.transform_keys(&:to_sym).inspect
101
- end
102
-
103
- def text_expressions(text, interpolate:)
104
- return [restore_escaped_interpolation(text).inspect] unless interpolate && text.include?("\#{")
105
-
106
- expressions = []
107
- buffer = +""
108
- index = 0
109
-
110
- while index < text.length
111
- if text[index, 2] == "\#{"
112
- expression, next_index = read_interpolation(text, index + 2)
113
- if expression
114
- expressions << restore_escaped_interpolation(buffer).inspect unless buffer.empty?
115
- buffer.clear
116
- expressions << "(#{expression})"
117
- index = next_index
118
- else
119
- buffer << text[index]
120
- index += 1
121
- end
122
- else
123
- buffer << text[index]
124
- index += 1
125
- end
128
+ pairs = attrs.map do |name, value|
129
+ value_source = value.is_a?(String) ? string_source(value) : value.inspect
130
+ "#{name.to_sym.inspect} => #{value_source}"
126
131
  end
127
132
 
128
- expressions << restore_escaped_interpolation(buffer).inspect unless buffer.empty?
129
- expressions
133
+ "{#{pairs.join(", ")}}"
130
134
  end
131
135
 
132
- def read_interpolation(text, index)
133
- expression = +""
134
- depth = 1
135
- quote = nil
136
- escaped = false
137
-
138
- while index < text.length
139
- char = text[index]
140
-
141
- if quote
142
- expression << char
143
- if escaped
144
- escaped = false
145
- elsif char == "\\"
146
- escaped = true
147
- elsif char == quote
148
- quote = nil
149
- end
150
- else
151
- case char
152
- when "\"", "'", "`"
153
- quote = char
154
- when "{"
155
- depth += 1
156
- when "}"
157
- depth -= 1
158
- return [expression.strip, index + 1] if depth.zero?
159
- end
160
-
161
- expression << char
162
- end
136
+ # Kramdown derives heading IDs from text that still contains
137
+ # interpolation tokens, which leaves stray separators behind.
138
+ def header_attrs(node)
139
+ id = node.attr["id"]
140
+ return node.attr unless id && @interpolation&.interpolated?(node.options[:raw_text].to_s)
163
141
 
164
- index += 1
165
- end
142
+ node.attr.merge("id" => id.gsub(/-{2,}/, "-").delete_prefix("-").delete_suffix("-"))
143
+ end
166
144
 
167
- nil
145
+ def text_expressions(text)
146
+ @interpolation ? @interpolation.expressions(text) : [text.inspect]
168
147
  end
169
148
 
170
- def protect_escaped_interpolation(source)
171
- source.gsub("\\\#{", ESCAPED_INTERPOLATION_SENTINEL)
149
+ def string_source(text)
150
+ @interpolation ? @interpolation.string_source(text) : text.inspect
172
151
  end
173
152
 
174
- def restore_escaped_interpolation(text)
175
- text.gsub(ESCAPED_INTERPOLATION_SENTINEL, "\#{")
153
+ def literal_text(text)
154
+ @interpolation ? @interpolation.literal(text) : text
176
155
  end
177
156
  end
178
157
  end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Klenod
4
+ module Build
5
+ module Plugins
6
+ # Compiles Ruby-style `#{...}` interpolation in filter text into Ruby
7
+ # source. `\#{` stays literal.
8
+ #
9
+ # Each interpolation is replaced by an opaque private-use token before
10
+ # the text is parsed further, so parsers such as Markdown never see the
11
+ # Ruby expression. Compile the parsed pieces back with the same Source.
12
+ module TextInterpolation
13
+ TOKEN_START = ""
14
+ TOKEN_END = ""
15
+ ESCAPE_TOKEN = ""
16
+ FIRST_INDEX_CODEPOINT = 0xE100
17
+ LAST_INDEX_CODEPOINT = 0xF8FF
18
+ TOKEN_PATTERN = /#{TOKEN_START}([\u{E100}-\u{F8FF}])#{TOKEN_END}/o
19
+ SEGMENT_PATTERN = /#{TOKEN_START}[\u{E100}-\u{F8FF}]#{TOKEN_END}|#{ESCAPE_TOKEN}/o
20
+
21
+ class Source
22
+ # The source with interpolations and escapes replaced by tokens.
23
+ attr_reader :text
24
+
25
+ def initialize(source)
26
+ @interpolations = []
27
+ @text = tokenize(source)
28
+ end
29
+
30
+ def interpolated?(text = @text)
31
+ text.match?(TOKEN_PATTERN)
32
+ end
33
+
34
+ # Returns Ruby source for each literal and interpolated segment of
35
+ # tokenized text.
36
+ def expressions(text)
37
+ segments(text).map { |kind, value| (kind == :ruby) ? "(#{value})" : value.inspect }
38
+ end
39
+
40
+ # Returns Ruby source for one String built from tokenized text.
41
+ def string_source(text)
42
+ parts = segments(text)
43
+ return literal(text).inspect if parts.none? { |kind, _| kind == :ruby }
44
+
45
+ body = parts.map { |kind, value| (kind == :ruby) ? "\#{#{value}}" : value.inspect[1...-1] }.join
46
+ "\"#{body}\""
47
+ end
48
+
49
+ # Restores tokenized text to its original characters, keeping
50
+ # interpolations as literal `#{...}` text.
51
+ def literal(text)
52
+ text.gsub(SEGMENT_PATTERN) do |token|
53
+ (token == ESCAPE_TOKEN) ? "\#{" : @interpolations.fetch(token_index(token)).fetch(:raw)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def segments(text)
60
+ segments = []
61
+ buffer = +""
62
+
63
+ text.split(/(#{SEGMENT_PATTERN})/o).each do |part|
64
+ if part == ESCAPE_TOKEN
65
+ buffer << "\#{"
66
+ elsif part.match?(TOKEN_PATTERN)
67
+ segments << [:text, buffer] unless buffer.empty?
68
+ buffer = +""
69
+ segments << [:ruby, @interpolations.fetch(token_index(part)).fetch(:expression)]
70
+ else
71
+ buffer << part
72
+ end
73
+ end
74
+
75
+ segments << [:text, buffer] unless buffer.empty?
76
+ segments
77
+ end
78
+
79
+ def token_index(token)
80
+ token[TOKEN_PATTERN, 1].ord - FIRST_INDEX_CODEPOINT
81
+ end
82
+
83
+ def tokenize(source)
84
+ output = +""
85
+ index = 0
86
+
87
+ while index < source.length
88
+ if source[index, 3] == "\\\#{"
89
+ output << ESCAPE_TOKEN
90
+ index += 3
91
+ elsif source[index, 2] == "\#{" && (interpolation = read_interpolation(source, index + 2))
92
+ expression, next_index = interpolation
93
+ output << token(expression, raw: source[index...next_index])
94
+ index = next_index
95
+ else
96
+ output << source[index]
97
+ index += 1
98
+ end
99
+ end
100
+
101
+ output
102
+ end
103
+
104
+ def token(expression, raw:)
105
+ codepoint = FIRST_INDEX_CODEPOINT + @interpolations.length
106
+ raise ArgumentError, "Too many interpolations in one filter" if codepoint > LAST_INDEX_CODEPOINT
107
+
108
+ @interpolations << {expression: expression, raw: raw}
109
+ "#{TOKEN_START}#{codepoint.chr(Encoding::UTF_8)}#{TOKEN_END}"
110
+ end
111
+
112
+ def read_interpolation(text, index)
113
+ expression = +""
114
+ depth = 1
115
+ quote = nil
116
+ escaped = false
117
+
118
+ while index < text.length
119
+ char = text[index]
120
+
121
+ if quote
122
+ expression << char
123
+ if escaped
124
+ escaped = false
125
+ elsif char == "\\"
126
+ escaped = true
127
+ elsif char == quote
128
+ quote = nil
129
+ end
130
+ else
131
+ case char
132
+ when "\"", "'", "`"
133
+ quote = char
134
+ when "{"
135
+ depth += 1
136
+ when "}"
137
+ depth -= 1
138
+ return [expression.strip, index + 1] if depth.zero?
139
+ end
140
+
141
+ expression << char
142
+ end
143
+
144
+ index += 1
145
+ end
146
+
147
+ nil
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Klenod
4
4
  module Build
5
- VERSION = "0.0.22"
5
+ VERSION = "0.0.24"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klenod-build
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrés Alin
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.0.22
18
+ version: 0.0.24
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.0.22
25
+ version: 0.0.24
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: async
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -293,6 +293,7 @@ files:
293
293
  - lib/klenod/build/plugins/ruby_plugin.rb
294
294
  - lib/klenod/build/plugins/static_asset_plugin.rb
295
295
  - lib/klenod/build/plugins/svg_plugin.rb
296
+ - lib/klenod/build/plugins/text_interpolation.rb
296
297
  - lib/klenod/build/profiler.rb
297
298
  - lib/klenod/build/resolution_error_formatter.rb
298
299
  - lib/klenod/build/resolver.rb