ejx 0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7d977622dbdaa5af0afbc8c9c024439f104337c3b4133dbf2c7866656256f373
4
+ data.tar.gz: e02233b080ee6d8dce9e94135993771464e33497a9102419d75ad8cf058f8984
5
+ SHA512:
6
+ metadata.gz: e5dd9308fe7904ad51c24475de414887f92cdc62c76111f2c98ff03342d4d2874e17d44cbea939ae9dc3285670ebce7b027afb278630931b96898a40657babd1
7
+ data.tar.gz: f53c0b6ca412d595ae449f8db65f6038a152ba411f12debc9f57226d9679134c2a471f5e69a14572f8728c97bd0b797e9243322cf47e3af12532ce8719e4b6f4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Jon Bracy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,80 @@
1
+ EJX (Embedded JavaScript) template compiler for Ruby
2
+ ====================================================
3
+
4
+ EJX templates embed JavaScript code inside `<% ... %>` tags, much like ERB. This
5
+ library is inspired by [Underscore.js](https://underscorejs.org)'s
6
+ [`_.template` function](https://underscorejs.org/#template) and
7
+ [JSX](https://reactjs.org/docs/jsx-in-depth.html), but without the virtual DOM.
8
+
9
+ The EJX tag syntax is as follows:
10
+
11
+ * `<% ... %>` silently evaluates the statement inside the tags.
12
+ * `<%= ... %>` evaluates the expression inside the tags, escapes and inserts it
13
+ into the template output.
14
+ * `<%- ... %>` behaves like `<%= ... %>` but does not escape it's output.
15
+
16
+ The functions compiled with EJX will return an array containing `Node` objects
17
+ and/or `DOMString` which can be appended to a Node via `Node.append(...)`
18
+
19
+ Examples
20
+ --------
21
+
22
+ To compile an EJX template into a Javascript module pass the template to `EJX.compile`:
23
+
24
+ ```ruby
25
+ EJX.compile("Hello <span><%= name %></span>")
26
+ # => import {append as __ejx_append} from 'ejx';
27
+ # =>
28
+ # => export default async function (locals) {
29
+ # => var __output = [], __promises = [];
30
+ # =>
31
+ # => __output.push("Hello ");
32
+ # => var __a = document.createElement("span");
33
+ # => __ejx_append(name, __a, true, __promises);
34
+ # => __ejx_append(__a, __output, false, __promises);
35
+ # =>
36
+ # => await Promise.all(__promises);
37
+ # => return __output;
38
+ # => }
39
+ JS
40
+ ```
41
+
42
+ If a evalation tag (`<%=` or `<%-`) ends with an opening of a function, the
43
+ function returns a compiled template. For example:
44
+
45
+ ```erb
46
+ <% formTag = function(template) {
47
+ var a = document.createElement("form");
48
+ a.append.apply(a, template());
49
+ return a;
50
+ } %>
51
+
52
+ <%= formTag(function () { %>
53
+ <input type="submit" />
54
+ <% }) %>
55
+ ```
56
+
57
+ generates:
58
+
59
+ ```js
60
+ import {append as __ejx_append} from 'ejx';
61
+
62
+ export default async function (locals) {
63
+ var __output = [], __promises = [];
64
+
65
+ formTag = function(template) {
66
+ var a = document.createElement("form");
67
+ a.append.apply(a, template());
68
+ return a;
69
+ }
70
+ var __a = [];
71
+ __ejx_append(formTag(function () {
72
+ var __b = document.createElement("input");
73
+ __b.setAttribute("type", "submit");
74
+ __ejx_append(__b, __a, false, __promises);
75
+ }), __output, true, __promises, __a);
76
+
77
+ await Promise.all(__promises);
78
+ return __output;
79
+ }
80
+ ```
@@ -0,0 +1,23 @@
1
+ class Condenser::EjxTransformer < Condenser::NodeProcessor
2
+
3
+ def initialize(options = {})
4
+ @options = options
5
+ end
6
+
7
+ def self.setup(environment)
8
+ require 'ejx' unless defined?(::EJX)
9
+
10
+ if !environment.path.include?(EJX::ASSET_DIR)
11
+ environment.append_path(EJX::ASSET_DIR)
12
+ end
13
+ end
14
+
15
+ def self.call(environment, input)
16
+ new.call(environment, input)
17
+ end
18
+
19
+ def call(environment, input)
20
+ input[:source] = EJX::Template.new(input[:source], @options).to_module
21
+ end
22
+
23
+ end
@@ -0,0 +1,66 @@
1
+ module EJX
2
+
3
+ class TemplateError < StandardError
4
+ end
5
+
6
+ autoload :Template, File.expand_path('../ejx/template', __FILE__)
7
+
8
+ @@settings = {
9
+ open_tag: '<%',
10
+ close_tag: '%>',
11
+
12
+ open_tag_modifiers: {
13
+ escape: '=',
14
+ unescape: '-',
15
+ comment: '#',
16
+ literal: '%'
17
+ },
18
+
19
+ close_tag_modifiers: {
20
+ trim: '-',
21
+ literal: '%'
22
+ },
23
+
24
+ escape: nil
25
+ }
26
+
27
+ ASSET_DIR = File.join(__dir__, 'ejx', 'assets')
28
+
29
+ VOID_ELEMENTS = [
30
+ 'area',
31
+ 'base',
32
+ 'br',
33
+ 'col',
34
+ 'embed',
35
+ 'hr',
36
+ 'img',
37
+ 'input',
38
+ 'link',
39
+ 'meta',
40
+ 'param',
41
+ 'source',
42
+ 'track',
43
+ 'wbr'
44
+ ]
45
+
46
+ def self.compile(source, options = {})
47
+ EJX::Template.new(source, options).to_module
48
+ end
49
+
50
+ def self.settings
51
+ @@settings
52
+ end
53
+
54
+ def self.settings=(value)
55
+ @@settings = value
56
+ end
57
+ end
58
+
59
+
60
+ if defined?(Condenser)
61
+ Condenser.configure do
62
+ autoload :EjxTransformer, 'condenser/transformers/ejx'
63
+ register_mime_type 'application/ejx', extensions: '.ejx', charset: :unicode
64
+ register_template 'application/ejx', Condenser::EjxTransformer
65
+ end
66
+ end
@@ -0,0 +1,34 @@
1
+ function repalceejx(el, withItems) {
2
+ if ( Array.isArray(withItems) ) {
3
+ withItems.forEach((i) => {
4
+ if (i instanceof Node) {
5
+ el.insertAdjacentElement('beforebegin', i)
6
+ } else {
7
+ // el.insertAdjacentHTML()
8
+ el.insertAdjacentText('beforebegin', i)
9
+ }
10
+ })
11
+ el.remove();
12
+ } else {
13
+ el.replaceWith(withItems);
14
+ }
15
+ }
16
+
17
+ export function append(items, to, escape, promises, promise_results) {
18
+ if ( Array.isArray(items) ) {
19
+ items.forEach((i) => append(i, to, escape, promises));
20
+ } else {
21
+ let method = Array.isArray(to) ? 'push' : 'append';
22
+
23
+ if (items instanceof Promise) {
24
+ let holder = document.createElement( "div");
25
+ to[method](holder);
26
+ promises.push( items.then((resolvedItems) => {
27
+ repalceejx(holder, promise_results || resolvedItems)
28
+ }));
29
+ } else {
30
+ to[method](items);
31
+ }
32
+
33
+ }
34
+ }
@@ -0,0 +1,206 @@
1
+ class EJX::Template
2
+
3
+ autoload :JS, File.expand_path('../template/js', __FILE__)
4
+ autoload :Base, File.expand_path('../template/base', __FILE__)
5
+ autoload :String, File.expand_path('../template/string', __FILE__)
6
+ autoload :HTMLTag, File.expand_path('../template/html_tag', __FILE__)
7
+ autoload :ParseHelpers, File.expand_path('../template/parse_helpers', __FILE__)
8
+ autoload :Subtemplate, File.expand_path('../template/subtemplate', __FILE__)
9
+ autoload :VarGenerator, File.expand_path('../template/var_generator', __FILE__)
10
+
11
+ include EJX::Template::ParseHelpers
12
+
13
+ attr_accessor :source
14
+
15
+ def initialize(source, options={})
16
+ @source = source.strip
17
+
18
+ @js_start_tags = [options[:open_tag] || EJX.settings[:open_tag]]
19
+ @html_start_tags = ['<']
20
+ @start_tags = @js_start_tags + @html_start_tags
21
+
22
+ @js_close_tags = [options[:close_tag] || EJX.settings[:close_tag]]
23
+ @html_close_tags = ['/>', '>']
24
+ @close_tags = @js_close_tags + @html_close_tags
25
+
26
+ @open_tag_modifiers = EJX.settings[:open_tag_modifiers].merge(options[:open_tag_modifiers] || {})
27
+ @close_tag_modifiers = EJX.settings[:close_tag_modifiers].merge(options[:close_tag_modifiers] || {})
28
+
29
+ @escape = options[:escape]
30
+ process
31
+ end
32
+
33
+ def process
34
+ seek(0)
35
+ @tree = [EJX::Template::Base.new(escape: @escape)]
36
+ @stack = [:str]
37
+
38
+ while !eos?
39
+ case @stack.last
40
+ when :str
41
+ scan_until(Regexp.new("(#{@start_tags.map{|s| Regexp.escape(s) }.join('|')}|\\z)"))
42
+ if !pre_match.strip.empty?
43
+ @tree.last.children << EJX::Template::String.new(pre_match)
44
+ end
45
+
46
+ if !matched.nil?
47
+ if @js_start_tags.include?(matched)
48
+ @stack << :js
49
+ elsif @html_start_tags.include?(matched)
50
+ @stack << :html_tag
51
+ end
52
+ end
53
+ when :js
54
+ scan_until(Regexp.new("(#{@js_close_tags.map{|s| Regexp.escape(s) }.join('|')})"))
55
+ pm = pre_match
56
+ open_modifier = @open_tag_modifiers.find { |k,v| pm.start_with?(v) }&.first
57
+ close_modifier = @close_tag_modifiers.find { |k,v| matched.end_with?(v) }&.first
58
+ pm.slice!(0, open_modifier[1].size) if open_modifier
59
+ pm.slice!(pm.size - close_modifier[1].size, close_modifier[1].size) if close_modifier
60
+
61
+ if pm =~ /\A\s*import/
62
+ import = pm.strip
63
+ import += ';' if !import.end_with?(';')
64
+ @tree.first.imports << import
65
+ @stack.pop
66
+ elsif @tree.last.is_a?(EJX::Template::Subtemplate) && pm.match(/\A\s*\}\s*\)/m) && !pm.match(/\A\s*\}.*\{\s*\Z/m)
67
+ subtemplate = @tree.pop
68
+ subtemplate.children << pm.strip
69
+ @tree.last.children << subtemplate
70
+ @stack.pop
71
+ elsif pm.match(/function\s*\([^\)]*\)\s*\{\s*\Z/m)
72
+ @tree << EJX::Template::Subtemplate.new(pm.strip, [open_modifier, close_modifier].compact)
73
+ @stack.pop
74
+ else
75
+ value = EJX::Template::JS.new(pm.strip, [open_modifier, close_modifier].compact)
76
+
77
+ @stack.pop
78
+ case @stack.last
79
+ when :html_tag
80
+ @tree.last.tag_name = value
81
+ push(:html_tag_attr_key)
82
+ when :html_tag_attr_key
83
+ @tree.last.attrs << value
84
+ when :html_tag_attr_value
85
+ @tree.last.attrs << {@stack_info.last => value}
86
+ @stack.pop
87
+ else
88
+ @tree.last.children << value
89
+ end
90
+ end
91
+ when :html_tag
92
+ scan_until(Regexp.new("(#{@js_start_tags.map{|s| Regexp.escape(s) }.join('|')}|\\/|[^\\s>]+)"))
93
+ if @js_start_tags.include?(matched)
94
+ @tree << EJX::Template::HTMLTag.new
95
+ @stack << :js
96
+ elsif matched == '/'
97
+ @stack.pop
98
+ @stack << :html_close_tag
99
+ else
100
+ @tree << EJX::Template::HTMLTag.new
101
+ @tree.last.tag_name = matched
102
+ @stack << :html_tag_attr_key
103
+ end
104
+ when :html_close_tag
105
+ scan_until(Regexp.new("(#{@js_start_tags.map{|s| Regexp.escape(s) }.join('|')}|[^\\s>]+)"))
106
+
107
+ if @js_start_tags.include?(matched)
108
+ @stack << :js
109
+ else
110
+ el = @tree.pop
111
+ if el.tag_name != matched
112
+ raise EJX::TemplateError.new("Expected to close #{el.tag_name} tag, instead closed #{matched}\n#{cursor}")
113
+ end
114
+ @tree.last.children << el
115
+ scan_until(Regexp.new("(#{@html_close_tags.map{|s| Regexp.escape(s) }.join('|')})"))
116
+ @stack.pop
117
+ end
118
+ when :html_tag_attr_key
119
+ scan_until(Regexp.new("(#{(@js_start_tags+@html_close_tags).map{|s| Regexp.escape(s) }.join('|')}|[^\\s=>]+)"))
120
+ if @js_start_tags.include?(matched)
121
+ @stack << :js
122
+ elsif @html_close_tags.include?(matched)
123
+ if matched == '/>' || EJX::VOID_ELEMENTS.include?(@tree.last.tag_name)
124
+ el = @tree.pop
125
+ @tree.last.children << el
126
+ @stack.pop
127
+ @stack.pop
128
+ else
129
+ @stack << :str
130
+ end
131
+ else
132
+ key = if matched.start_with?('"') && matched.end_with?('"')
133
+ matched[1..-2]
134
+ elsif matched.start_with?('"') && matched.end_with?('"')
135
+ matched[1..-2]
136
+ else
137
+ matched
138
+ end
139
+ @tree.last.attrs << key
140
+ @stack << :html_tag_attr_value_tx
141
+ end
142
+ when :html_tag_attr_value_tx
143
+ scan_until(Regexp.new("(#{(@js_start_tags+@html_close_tags).map{|s| Regexp.escape(s) }.join('|')}|=|\\S)"))
144
+ tag_key = @tree.last.attrs.pop
145
+ if @js_start_tags.include?(matched)
146
+ @stack << :js
147
+ elsif @html_close_tags.include?(matched)
148
+ el = @tree.last
149
+ el.attrs << tag_key
150
+ if EJX::VOID_ELEMENTS.include?(el.tag_name)
151
+ @tree.pop
152
+ @tree.last.children << el
153
+ end
154
+ @stack.pop
155
+ @stack.pop
156
+ @stack.pop
157
+ elsif matched == '='
158
+ @stack.pop
159
+ @tree.last.attrs << tag_key
160
+ @stack << :html_tag_attr_value
161
+ else
162
+ @stack.pop
163
+ @tree.last.attrs << tag_key
164
+ rewind(1)
165
+ end
166
+
167
+ when :html_tag_attr_value
168
+ scan_until(Regexp.new("(#{(@js_start_tags+@html_close_tags).map{|s| Regexp.escape(s) }.join('|')}|'|\"|\\S+)"))
169
+
170
+ if @js_start_tags.include?(matched)
171
+ push(:js)
172
+ elsif matched == '"'
173
+ @stack.pop
174
+ @stack << :html_tag_attr_value_double_quoted
175
+ elsif matched == "'"
176
+ @stack.pop
177
+ @stack << :html_tag_attr_value_single_quoted
178
+ else
179
+ @stack.pop
180
+ key = @tree.last.attrs.pop
181
+ @tree.last.namespace = matched if key == 'xmlns'
182
+ @tree.last.attrs << { key => matched }
183
+ end
184
+ when :html_tag_attr_value_double_quoted
185
+ scan_until(/[^\"]*/)
186
+ key = @tree.last.attrs.pop
187
+ @tree.last.namespace = matched if key == 'xmlns'
188
+ @tree.last.attrs << { key => matched }
189
+ scan_until(/\"/)
190
+ @stack.pop
191
+ when :html_tag_attr_value_single_quoted
192
+ scan_until(/[^']*/)
193
+ key = @tree.last.attrs.pop
194
+ @tree.last.namespace = matched if key == 'xmlns'
195
+ @tree.last.attrs << { key => matched }
196
+ scan_until(/'/)
197
+ @stack.pop
198
+ end
199
+ end
200
+ end
201
+
202
+ def to_module
203
+ @tree.first.to_module
204
+ end
205
+
206
+ end
@@ -0,0 +1,41 @@
1
+ class EJX::Template::Base
2
+
3
+ attr_accessor :children, :imports
4
+
5
+ def initialize(escape: nil)
6
+ @children = []
7
+ @escape = escape
8
+ @imports = []
9
+ end
10
+
11
+ def to_module
12
+ var_generator = EJX::Template::VarGenerator.new
13
+
14
+ output = if @escape
15
+ "import {" + @escape.split('.').reverse.join(" as escape} from '") + "';\n"
16
+ else
17
+ "import {append as __ejx_append} from 'ejx';\n"
18
+ end
19
+
20
+ @imports.each do |import|
21
+ output << import << "\n"
22
+ end
23
+
24
+ output << "\nexport default async function (locals) {\n"
25
+ output << " var __output = [], __promises = [];\n \n"
26
+
27
+ @children.each do |child|
28
+ output << case child
29
+ when EJX::Template::String
30
+ " __output.push(#{child.to_js});\n"
31
+ else
32
+ child.to_js(var_generator: var_generator)
33
+ end
34
+ end
35
+ output << "\n await Promise.all(__promises);\n"
36
+ output << " return __output;\n"
37
+ output << "}"
38
+ output
39
+ end
40
+
41
+ end
@@ -0,0 +1,53 @@
1
+ class EJX::Template::HTMLTag
2
+
3
+ attr_accessor :tag_name, :attrs, :children, :namespace
4
+
5
+ def initialize
6
+ @attrs = []
7
+ @children = []
8
+ end
9
+
10
+ def to_s
11
+ @value
12
+ end
13
+
14
+ def inspect
15
+ "#<EJX::HTMLTag:#{self.object_id} @tag_name=#{tag_name}>"
16
+ end
17
+
18
+ def to_js(append: "__output", var_generator:, indentation: 4, namespace: nil)
19
+ namespace ||= self.namespace
20
+
21
+ output_var = var_generator.next
22
+ js = "#{' '*indentation}var #{output_var} = document.createElement"
23
+ js << if namespace
24
+ "NS(#{JSON.generate(namespace)}, #{JSON.generate(tag_name)});\n"
25
+ else
26
+ "(#{JSON.generate(tag_name)});\n"
27
+ end
28
+
29
+ @attrs.each do |attr|
30
+ if attr.is_a?(Hash)
31
+ attr.each do |k, v|
32
+ js << "#{' '*indentation}#{output_var}.setAttribute(#{JSON.generate(k)}, #{JSON.generate(v)});\n"
33
+ end
34
+ else
35
+ js << "#{' '*indentation}#{output_var}.setAttribute(#{JSON.generate(attr)}, \"\");\n"
36
+ end
37
+ end
38
+
39
+ @children.each do |child|
40
+ js << if child.is_a?(EJX::Template::String)
41
+ "#{' '*indentation}__ejx_append(#{child.to_js}, #{output_var}, false, __promises);\n"
42
+ elsif child.is_a?(EJX::Template::HTMLTag)
43
+ child.to_js(var_generator: var_generator, indentation: indentation, append: output_var, namespace: namespace)
44
+ else
45
+ child.to_js(var_generator: var_generator, indentation: indentation, append: output_var)
46
+ end
47
+ end
48
+
49
+ js << "#{' '*indentation}__ejx_append(#{output_var}, #{append}, false, __promises);\n"
50
+ js
51
+ end
52
+
53
+ end
@@ -0,0 +1,19 @@
1
+ class EJX::Template::JS
2
+
3
+ def initialize(value, modifiers)
4
+ @modifiers = modifiers
5
+ @value = value
6
+ end
7
+
8
+ def to_js(indentation: 4, var_generator: nil, append: "__output")
9
+ output = @value
10
+
11
+ if @modifiers.include? :escape
12
+ "#{' '*indentation}__ejx_append(#{output}, #{append}, true, __promises);\n"
13
+ elsif @modifiers.include? :unescape
14
+ "#{' '*indentation}__ejx_append(#{output}, #{append}, false, __promises);\n"
15
+ elsif !@modifiers.include? :comment
16
+ "#{' '*indentation}#{output}\n"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ module EJX::Template::ParseHelpers
2
+
3
+ attr_accessor :matched
4
+
5
+ def eos?
6
+ @index >= @source.size
7
+ end
8
+
9
+ def scan_until(r)
10
+ index = @source.index(r, @index)
11
+ match = @source.match(r, @index)
12
+ @matched = match.to_s
13
+ @old_index = @index
14
+ @index = index + @matched.size
15
+ match
16
+ end
17
+
18
+ def pre_match
19
+ @source[@old_index...(@index-@matched.size)]
20
+ end
21
+
22
+ def rewind(by)
23
+ @index -= 1
24
+ end
25
+
26
+ def seek(pos)
27
+ @old_index = nil
28
+ @matched = nil
29
+ @index = pos
30
+ end
31
+
32
+ def current_line
33
+ start = (@source.rindex("\n", @old_index) || 0) + 1
34
+ uptop = @source.index("\n", @index) || (@old_index + @matched.length)
35
+ @source[start..uptop]
36
+ end
37
+
38
+ def cursor
39
+ start = (@source.rindex("\n", @old_index) || 0) + 1
40
+ uptop = @source.index("\n", @index) || (@old_index + @matched.length)
41
+ lineno = @source[0..start].count("\n") + 1
42
+ "#{lineno.to_s.rjust(4)}: " + @source[start..uptop] + "\n #{'-'* (@old_index-start)}#{'^'*(@matched.length)}"
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+
3
+ class EJX::Template::String
4
+
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+
9
+ def to_js
10
+ JSON.generate(@value)
11
+ end
12
+
13
+ end
@@ -0,0 +1,33 @@
1
+ class EJX::Template::Subtemplate
2
+
3
+ attr_reader :children
4
+
5
+ def initialize(opening, modifiers)
6
+ @children = [opening]
7
+ @modifiers = modifiers
8
+ end
9
+
10
+ def to_js(indentation: 4, var_generator: nil, append: "__output")
11
+ output_var = var_generator.next
12
+ output = "#{' '*indentation}var #{output_var} = [];\n"
13
+ output << "#{' '*indentation}__ejx_append("
14
+ output << @children.first
15
+ output << "\n"
16
+
17
+ # var_generator ||= EJX::Template::VarGenerator.new
18
+ @children[1..-2].each do |child|
19
+ output << case child
20
+ when EJX::Template::String
21
+ "#{' '*(indentation+4)}__ejx_append(#{child.to_js}, #{output_var}, false, __promises);\n"
22
+ else
23
+ child.to_js(indentation: indentation + 4, var_generator: var_generator, append: output_var)
24
+ end
25
+ end
26
+ output << ' '*indentation
27
+ output << @children.last
28
+ output << ", #{append}, true, __promises, #{output_var});\n"
29
+
30
+ output
31
+ end
32
+
33
+ end
@@ -0,0 +1,10 @@
1
+ class EJX::Template::VarGenerator
2
+ def initialize
3
+ @current = nil
4
+ end
5
+
6
+ def next
7
+ @current = @current.nil? ? '__a' : @current.next
8
+ @current
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module EJX
2
+ VERSION = '0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ejx
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Bracy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: |
70
+ Compile EJX (Embedded JavaScript) templates to Javascript
71
+ functions with Ruby.
72
+ email:
73
+ - jonbracy@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - LICENSE
79
+ - README.md
80
+ - lib/condenser/transformers/ejx.rb
81
+ - lib/ejx.rb
82
+ - lib/ejx/assets/ejx.js
83
+ - lib/ejx/template.rb
84
+ - lib/ejx/template/base.rb
85
+ - lib/ejx/template/html_tag.rb
86
+ - lib/ejx/template/js.rb
87
+ - lib/ejx/template/parse_helpers.rb
88
+ - lib/ejx/template/string.rb
89
+ - lib/ejx/template/subtemplate.rb
90
+ - lib/ejx/template/var_generator.rb
91
+ - lib/ejx/version.rb
92
+ homepage: https://github.com/malomalo/ejx
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubygems_version: 3.1.2
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: EJX Template Compiler
115
+ test_files: []