vue_component_compiler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9c4f7b83e30ac6e415fc1d356d67f6da85b377682b5de1813a31e2ccd2160d78
4
+ data.tar.gz: fe4f450d390c613c09b21062c159879ed88ac5573ac04747dd89086b7d08466e
5
+ SHA512:
6
+ metadata.gz: 320dea5c591312eb4fbbdebc695296e2d485b78f6d4f24d90b88db744736cb44548ff114cb96689878e5a9ae588a5ba915cc9933774abb4ce0da9ebeb33123aa
7
+ data.tar.gz: 60a0086f3d387c73afe65ddb0e3a252d4373fb65e5b6c6ef70f2f5ceb213eb521129a42ddb50c4f224778d2143365fbd7a432e46d76c4bbfed75580a1fd506e4
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
@@ -0,0 +1,4 @@
1
+ *.vue
2
+ *.gem
3
+ .rspec_status
4
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gem "rake", "~> 12.3"
8
+
9
+ group :test do
10
+ gem "rspec", "~> 3.8"
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018-present Pig Fang
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,9 @@
1
+ # Vue Component Compiler
2
+
3
+ Vue component compiler written in Ruby. It's still experimental.
4
+
5
+ Unlike other gems, this compiler doesn't require V8, because it's written in pure Ruby.
6
+
7
+ ## License
8
+
9
+ MIT Licens (c) 2018-present Pig Fang
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ require 'vue_component_compiler/token'
2
+ require 'vue_component_compiler/tokenizer'
3
+ require 'vue_component_compiler/node'
4
+ require 'vue_component_compiler/parser'
5
+
6
+ module VueCompiler
7
+ def parse(code)
8
+ tokenizer = Tokenizer.new(code)
9
+ parser = Parser.new(tokenizer.tokenize)
10
+ parser.parse
11
+ end
12
+
13
+ module_function :parse
14
+ end
@@ -0,0 +1,108 @@
1
+ module VueCompiler
2
+ module Node
3
+ class Program
4
+ attr_reader :children, :comments
5
+
6
+ def initialize(children, comments = [])
7
+ @children = children
8
+ @comments = comments
9
+ end
10
+ end
11
+
12
+ class Comment
13
+ attr_reader :body
14
+
15
+ def initialize(body)
16
+ @body = body
17
+ end
18
+ end
19
+
20
+ class Element
21
+ attr_reader :name, :attributes, :children
22
+
23
+ def initialize(name, attributes = [], children = [])
24
+ @name = name
25
+ @attributes = attributes
26
+ @children = children
27
+ end
28
+ end
29
+
30
+ class Text
31
+ attr_reader :content
32
+
33
+ def initialize(content)
34
+ @content = content
35
+ end
36
+ end
37
+
38
+ class Interpolation
39
+ attr_reader :expression
40
+
41
+ def initialize(expression)
42
+ @expression = expression
43
+ end
44
+ end
45
+
46
+ class Attribute
47
+ attr_reader :name, :value
48
+
49
+ def initialize(name, value)
50
+ @name = name
51
+ @value = value
52
+ end
53
+ end
54
+
55
+ class AttributeName
56
+ attr_reader :name
57
+
58
+ def initialize(name)
59
+ @name = name
60
+ end
61
+ end
62
+
63
+ class Directive
64
+ attr_reader :name, :argument, :shorthand
65
+
66
+ def initialize(name, argument, shorthand = false)
67
+ @name = name
68
+ @argument = argument
69
+ @shorthand = shorthand
70
+ end
71
+ end
72
+
73
+ class AttributeValue
74
+ attr_reader :value
75
+
76
+ def initialize(value)
77
+ @value = value
78
+ end
79
+ end
80
+
81
+ class TemplateBlock
82
+ attr_reader :body
83
+
84
+ def initialize(body)
85
+ @body = body
86
+ end
87
+ end
88
+
89
+ class ScriptBlock
90
+ attr_reader :content, :lang
91
+
92
+ def initialize(content, lang = 'js')
93
+ @content = content
94
+ @lang = lang
95
+ end
96
+ end
97
+
98
+ class StyleBlock
99
+ attr_reader :content, :lang, :scoped
100
+
101
+ def initialize(content, lang = 'css', scoped = false)
102
+ @content = content
103
+ @lang = lang
104
+ @scoped = scoped
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,181 @@
1
+ module VueCompiler
2
+ class Parser
3
+ DIRECTIVE_RE = /v\-(\w+)(?:\:(\w+))?/
4
+
5
+ # @param tokens {Array}
6
+ def initialize(tokens)
7
+ @tokens = tokens
8
+ @comments = []
9
+ end
10
+
11
+ def parse
12
+ root_children = []
13
+
14
+ until @tokens[0].instance_of?(Token::EndOfSource)
15
+ token = @tokens[0]
16
+ if token.instance_of?(Token::ScriptBlock)
17
+ token = self.eat
18
+ root_children << Node::ScriptBlock.new(
19
+ token.content,
20
+ token.lang
21
+ )
22
+ next
23
+ elsif token.instance_of?(Token::StyleBlock)
24
+ token = self.eat
25
+ root_children << Node::StyleBlock.new(
26
+ token.content,
27
+ token.lang,
28
+ token.scoped
29
+ )
30
+ next
31
+ elsif token.instance_of?(Token::CommentStart)
32
+ self.parse_comment
33
+ next
34
+ elsif token.instance_of?(Token::CustomBlock)
35
+ root_children << token
36
+ self.eat
37
+ next
38
+ end
39
+
40
+ self.expect(Token::OpenTagStart)
41
+ self.expect(Token::OpenTagName)
42
+ self.expect(Token::TagEnd)
43
+
44
+ while token.instance_of?(Token::CommentStart)
45
+ self.parse_comment
46
+ end
47
+
48
+ if @tokens[0].instance_of?(Token::OpenTagStart)
49
+ element = Node::Element.new(
50
+ 'template',
51
+ [],
52
+ [self.parse_element]
53
+ )
54
+ root_children << Node::TemplateBlock.new(element)
55
+ end
56
+
57
+ while token.instance_of?(Token::CommentStart)
58
+ self.parse_comment
59
+ end
60
+
61
+ self.expect(Token::ClosingTagStart)
62
+ self.expect(Token::ClosingTagName)
63
+ self.expect(Token::TagEnd)
64
+ end
65
+
66
+ Node::Program.new(root_children, @comments)
67
+ end
68
+
69
+ def eat
70
+ @tokens.shift
71
+ end
72
+
73
+ def expect(token)
74
+ if @tokens[0].instance_of?(token)
75
+ @tokens.shift
76
+ else
77
+ raise Exception.new("Found token type #{@tokens[0].class}, expecting #{token}")
78
+ end
79
+ end
80
+
81
+ def parse_comment
82
+ self.eat
83
+ @comments << Node::Comment.new(self.eat.value)
84
+ self.eat
85
+ end
86
+
87
+ def parse_element
88
+ self.expect(Token::OpenTagStart)
89
+ tag_name = self.expect(Token::OpenTagName).name
90
+ attributes = []
91
+
92
+ while @tokens[0].instance_of?(Token::AttributeName)
93
+ attributes << self.parse_attribute
94
+ end
95
+
96
+ if self.eat.instance_of?(Token::SelfClosingTag)
97
+ return Node::Element.new(tag_name, attributes)
98
+ end
99
+
100
+ children = self.parse_element_children
101
+
102
+ self.expect(Token::ClosingTagStart)
103
+ self.expect(Token::ClosingTagName)
104
+ self.expect(Token::TagEnd)
105
+
106
+ Node::Element.new(tag_name, attributes, children)
107
+ end
108
+
109
+ def parse_attribute
110
+ name = self.eat.name
111
+ value = nil
112
+
113
+ if @tokens[0].instance_of?(Token::AttributeValue)
114
+ value = self.eat.value
115
+ end
116
+
117
+ if name.start_with?(':')
118
+ if value
119
+ Node::Attribute.new(
120
+ Node::Directive.new('bind', name[1..-1], true),
121
+ Node::AttributeValue.new(value)
122
+ )
123
+ else
124
+ raise Exception.new('Missing value of `v-bind` directive.')
125
+ end
126
+ elsif name.start_with?('@')
127
+ if value
128
+ Node::Attribute.new(
129
+ Node::Directive.new('on', name[1..-1], true),
130
+ Node::AttributeValue.new(value)
131
+ )
132
+ else
133
+ raise Exception.new('Missing value of `v-on` directive.')
134
+ end
135
+ elsif name.start_with?('v-')
136
+ matched = name.match(DIRECTIVE_RE)
137
+ name = matched[1]
138
+ argument = matched[2]
139
+ Node::Attribute.new(
140
+ Node::Directive.new(name, argument),
141
+ Node::AttributeValue.new(value)
142
+ )
143
+ else
144
+ Node::Attribute.new(
145
+ Node::AttributeName.new(name),
146
+ Node::AttributeValue.new(value)
147
+ )
148
+ end
149
+ end
150
+
151
+ def parse_element_children
152
+ children = []
153
+
154
+ until @tokens[0].instance_of?(Token::ClosingTagStart)
155
+ token = @tokens[0]
156
+
157
+ if token.instance_of?(Token::OpenTagStart)
158
+ children << self.parse_element
159
+ elsif token.instance_of?(Token::Text)
160
+ children << Node::Text.new(self.eat.content)
161
+ elsif token.instance_of?(Token::InterpolationStart)
162
+ children << self.parse_interpolation
163
+ elsif token.instance_of?(Token::CommentStart)
164
+ self.parse_comment
165
+ else
166
+ raise Exception.new('Unknown token type.')
167
+ end
168
+ end
169
+
170
+ children
171
+ end
172
+
173
+ def parse_interpolation
174
+ self.eat
175
+ interpolation = Node::Interpolation.new(self.eat.expression)
176
+ self.eat
177
+
178
+ interpolation
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,105 @@
1
+ module VueCompiler
2
+ module Token
3
+ class EndOfSource end
4
+
5
+ class CommentStart end
6
+
7
+ class Comment
8
+ attr_reader :value
9
+
10
+ def initialize(value)
11
+ @value = value
12
+ end
13
+ end
14
+
15
+ class CommentEnd end
16
+
17
+ class OpenTagStart end
18
+
19
+ class ClosingTagStart end
20
+
21
+ class TagEnd end
22
+
23
+ class SelfClosingTag end
24
+
25
+ class TagName
26
+ attr_reader :name
27
+
28
+ def initialize(name)
29
+ @name = name
30
+ end
31
+ end
32
+
33
+ class OpenTagName < TagName
34
+ end
35
+
36
+ class ClosingTagName < TagName
37
+ end
38
+
39
+ class AttributeName
40
+ attr_reader :name
41
+
42
+ def initialize(name)
43
+ @name = name
44
+ end
45
+ end
46
+
47
+ class AttributeValue
48
+ attr_reader :value
49
+
50
+ def initialize(value)
51
+ @value = value
52
+ end
53
+ end
54
+
55
+ class Text
56
+ attr_reader :content
57
+
58
+ def initialize(content)
59
+ @content = content
60
+ end
61
+ end
62
+
63
+ class InterpolationStart
64
+ end
65
+
66
+ class Interpolation
67
+ attr_reader :expression
68
+
69
+ def initialize(expression)
70
+ @expression = expression
71
+ end
72
+ end
73
+
74
+ class InterpolationEnd
75
+ end
76
+
77
+ class ScriptBlock
78
+ attr_reader :content, :lang
79
+
80
+ def initialize(content, lang = 'js')
81
+ @content = content
82
+ @lang = lang
83
+ end
84
+ end
85
+
86
+ class StyleBlock
87
+ attr_reader :content, :lang, :scoped
88
+
89
+ def initialize(content, lang = 'css', scoped = false)
90
+ @content = content
91
+ @lang = lang
92
+ @scoped = scoped
93
+ end
94
+ end
95
+
96
+ class CustomBlock
97
+ attr_reader :type, :attributes, :content
98
+
99
+ def initialize(type, content, attributes = {})
100
+ @type = type
101
+ @content = content
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,322 @@
1
+ module VueCompiler
2
+ class Tokenizer
3
+ TAG_RE = /^[a-z][a-z0-9:-]*/
4
+ TAG_NAME_RE = /^[a-z][a-z0-9:-]*/
5
+ ATTRIBUTE_NAME_RE = /^[a-z0-9@:\-]+/
6
+ ATTRIBUTE_VALUE_RE = /^"([^"\r\n]*)"|'([^'\r\n]*)'|([^\s\r\n\t<>'"]+)/
7
+ WHITESPACE_RE = /^[\s\n\t\r]+/
8
+ QUOTE_RE = /^'|"/
9
+
10
+ VOID_TAG = %w(area base br col command embed hr img input keygen link meta param source track wbr)
11
+
12
+ # @param code {String}
13
+ def initialize(code)
14
+ @code = code.delete_prefix("\uFEFF")
15
+ @tokens = []
16
+ end
17
+
18
+ def tokenize
19
+ while @code && !@code.empty?
20
+ if @code.start_with?('<template')
21
+ self.scan_top_level_template
22
+ elsif @code =~ WHITESPACE_RE
23
+ self.eat_whitespaces
24
+ elsif @code.start_with?('<script')
25
+ self.scan_script_block
26
+ elsif @code.start_with?('<style')
27
+ self.scan_style_block
28
+ elsif @code.start_with?('<!--')
29
+ self.scan_comment
30
+ elsif @code =~ TAG_RE
31
+ self.scan_custom_block
32
+ end
33
+ end
34
+ @tokens << Token::EndOfSource.new
35
+
36
+ @tokens
37
+ end
38
+
39
+ def eat(str)
40
+ @code.delete_prefix!(str)
41
+ end
42
+
43
+ def eat_whitespaces
44
+ @code.sub!(WHITESPACE_RE, '')
45
+ end
46
+
47
+ def expect(str)
48
+ if @code.start_with?(str)
49
+ self.eat(str)
50
+ elsif
51
+ raise Exception.new("Found character `#{@code[0]}`, expecting `#{str}`")
52
+ end
53
+ end
54
+
55
+ def scan_top_level_template
56
+ @tokens << Token::OpenTagStart.new
57
+ @tokens << Token::OpenTagName.new('template')
58
+ @tokens << Token::TagEnd.new
59
+ self.eat('<template')
60
+ self.eat_whitespaces
61
+ self.expect('>')
62
+
63
+ self.eat_whitespaces
64
+ root_scanned = false
65
+ until @code.start_with?('</')
66
+ if @code.start_with?('<!--')
67
+ self.scan_comment
68
+ else
69
+ unless root_scanned
70
+ self.scan_tag
71
+ root_scanned = true
72
+ end
73
+ end
74
+ self.eat_whitespaces
75
+ end
76
+
77
+ self.eat('</')
78
+ @tokens << Token::ClosingTagStart.new
79
+ self.expect('template')
80
+ @tokens << Token::ClosingTagName.new('template')
81
+ self.eat_whitespaces
82
+ self.expect('>')
83
+ @tokens << Token::TagEnd.new
84
+ end
85
+
86
+ def scan_tag
87
+ tag_name = self.scan_tag_name
88
+ is_v_pre = false
89
+ self.eat_whitespaces
90
+
91
+ while (@code =~ ATTRIBUTE_NAME_RE) == 0
92
+ attr = self.scan_attribute
93
+ if attr[:name] == 'v-pre'
94
+ is_v_pre = true
95
+ end
96
+ self.eat_whitespaces
97
+ end
98
+
99
+ if @code.start_with?('/>')
100
+ @tokens << Token::SelfClosingTag.new
101
+ self.eat('/>')
102
+ return
103
+ elsif @code.start_with?('>')
104
+ if VOID_TAG.include?(tag_name)
105
+ @tokens << Token::SelfClosingTag.new
106
+ self.eat('>')
107
+ return
108
+ else
109
+ @tokens << Token::TagEnd.new
110
+ self.eat('>')
111
+ end
112
+ end
113
+
114
+ until @code.start_with?('</')
115
+ if @code.start_with?('<!--')
116
+ self.scan_comment
117
+ elsif @code.start_with?('<')
118
+ self.scan_tag
119
+ elsif @code.start_with?('{{')
120
+ self.scan_interpolation
121
+ else
122
+ self.scan_text(is_v_pre)
123
+ end
124
+ end
125
+
126
+ self.expect('</')
127
+ @tokens << Token::ClosingTagStart.new
128
+ self.expect(tag_name)
129
+ @tokens << Token::ClosingTagName.new(tag_name)
130
+ self.eat_whitespaces
131
+ self.expect('>')
132
+ @tokens << Token::TagEnd.new
133
+ end
134
+
135
+ def scan_tag_name
136
+ self.expect('<')
137
+ @tokens << Token::OpenTagStart.new
138
+
139
+ tag_name = @code.slice(TAG_NAME_RE)
140
+ @tokens << Token::OpenTagName.new(tag_name)
141
+ self.eat(tag_name)
142
+ tag_name
143
+ end
144
+
145
+ def scan_attribute
146
+ name = @code.slice(ATTRIBUTE_NAME_RE)
147
+ value = nil
148
+ @tokens << Token::AttributeName.new(name)
149
+ self.eat(name)
150
+
151
+ self.eat_whitespaces
152
+ return { name: name, value: value } unless @code.start_with?('=')
153
+
154
+ self.expect('=')
155
+ self.eat_whitespaces
156
+ if (@code =~ ATTRIBUTE_VALUE_RE) == 0
157
+ self.scan_attribute_value
158
+ value = self.eat_whitespaces
159
+ end
160
+
161
+ { name: name, value: value }
162
+ end
163
+
164
+ def scan_attribute_value
165
+ quoted = @code.start_with?("'") || @code.start_with?('"')
166
+ matched = @code.match(ATTRIBUTE_VALUE_RE)
167
+ value = matched[1] || matched[2] || matched[3]
168
+ @tokens << Token::AttributeValue.new(value)
169
+
170
+ @code = @code[((quoted ? 2 : 0) + value.size)..-1]
171
+
172
+ value
173
+ end
174
+
175
+ def scan_text(ignore_interpolation = false)
176
+ text = ''
177
+ until @code.start_with?('<') || (!ignore_interpolation && @code.start_with?('{{'))
178
+ char = @code[0]
179
+ self.eat(char)
180
+ next if char == ' ' && text.end_with?(' ')
181
+ text << char
182
+ end
183
+ @tokens << Token::Text.new(text)
184
+ end
185
+
186
+ def scan_interpolation
187
+ expr = ''
188
+ is_string = false
189
+
190
+ @tokens << Token::InterpolationStart.new
191
+ self.eat('{{')
192
+
193
+ while is_string || (!is_string && !@code.start_with?('}}'))
194
+ char = @code[0]
195
+ expr << char
196
+ self.eat(char)
197
+ if char == '"' || char == "'" || char == '`'
198
+ is_string = !is_string
199
+ end
200
+ end
201
+ expr.strip!
202
+ @tokens << Token::Interpolation.new(expr)
203
+
204
+ @tokens << Token::InterpolationEnd.new
205
+ self.eat('}}')
206
+ end
207
+
208
+ def scan_comment
209
+ @tokens << Token::CommentStart.new
210
+ end_pos = @code.index('-->')
211
+ if end_pos
212
+ @tokens << Token::Comment.new(@code[4...end_pos])
213
+ @tokens << Token::CommentEnd.new
214
+ @code = @code[end_pos + 3..-1]
215
+ end
216
+ end
217
+
218
+ def scan_script_block
219
+ self.eat('<script')
220
+ self.eat_whitespaces
221
+
222
+ lang = if @code.start_with?('lang')
223
+ self.eat('lang')
224
+ self.eat_whitespaces
225
+ self.expect('=')
226
+ self.eat_whitespaces
227
+ quoted = @code.start_with?("'") || @code.start_with?('"')
228
+ matched = @code.match(ATTRIBUTE_VALUE_RE)
229
+ lang = matched[1] || matched[2] || matched[3]
230
+ @code = @code[((quoted ? 2 : 0) + lang.size)..-1]
231
+ self.eat_whitespaces
232
+ self.expect('>')
233
+ lang
234
+ elsif @code.start_with?('>')
235
+ self.eat('>')
236
+ nil
237
+ end
238
+
239
+ content = ''
240
+ is_string = false
241
+ while is_string || (!is_string && !@code.start_with?('</script'))
242
+ char = @code[0]
243
+ if char == '"' || char == "'" || char == '`'
244
+ is_string = !is_string
245
+ end
246
+ content << char
247
+ self.eat(char)
248
+ end
249
+
250
+ self.eat('</script')
251
+ self.eat_whitespaces
252
+ self.expect('>')
253
+
254
+ @tokens << Token::ScriptBlock.new(content, lang)
255
+ end
256
+
257
+ def scan_style_block
258
+ content = ''
259
+ scoped = false
260
+ lang = 'css'
261
+
262
+ self.eat('<style')
263
+ self.eat_whitespaces
264
+
265
+ until @code.start_with?('>')
266
+ if @code.start_with?('scoped')
267
+ scoped = true
268
+ self.eat('scoped')
269
+ elsif @code.start_with?('lang')
270
+ self.eat('lang')
271
+ self.eat_whitespaces
272
+ self.expect('=')
273
+ self.eat_whitespaces
274
+ quoted = @code.start_with?("'") || @code.start_with?('"')
275
+ matched = @code.match(ATTRIBUTE_VALUE_RE)
276
+ lang = matched[1] || matched[2] || matched[3]
277
+ @code.sub!(QUOTE_RE, '')
278
+ self.eat(lang)
279
+ @code.sub!(QUOTE_RE, '')
280
+ end
281
+ self.eat_whitespaces
282
+ end
283
+
284
+ self.eat('>')
285
+
286
+ until @code.start_with?('</style')
287
+ char = @code[0]
288
+ content << char
289
+ self.eat(char)
290
+ end
291
+
292
+ self.eat('</style')
293
+ self.eat_whitespaces
294
+ self.expect('>')
295
+
296
+ @tokens << Token::StyleBlock.new(content, lang, scoped)
297
+ end
298
+
299
+ def scan_custom_block
300
+ self.eat('<')
301
+ type = @code.slice(TAG_NAME_RE)
302
+ content = ''
303
+ self.eat(type)
304
+
305
+ self.eat_whitespaces
306
+ # TODO: support attributes on custom block.
307
+ self.eat('>')
308
+
309
+ until @code.start_with?("</#{type}")
310
+ char = @code[0]
311
+ content << char
312
+ self.eat(char)
313
+ end
314
+
315
+ self.eat("</#{type}")
316
+ self.eat_whitespaces
317
+ self.eat('>')
318
+
319
+ @tokens << Token::CustomBlock.new(type, content)
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,3 @@
1
+ module VueCompiler
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "vue_component_compiler/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'vue_component_compiler'
7
+ spec.version = VueCompiler::VERSION
8
+ spec.authors = ['Pig Fang']
9
+ spec.email = ['g-plane@hotmail.com']
10
+ spec.licenses = ['MIT']
11
+ spec.summary = 'Vue component compiler'
12
+ spec.homepage = 'https://github.com/g-plane/vue-component-compiler-rb'
13
+
14
+ # Specify which files should be added to the gem when it is released.
15
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.16"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vue_component_compiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pig Fang
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - g-plane@hotmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".editorconfig"
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - lib/vue_component_compiler.rb
71
+ - lib/vue_component_compiler/node.rb
72
+ - lib/vue_component_compiler/parser.rb
73
+ - lib/vue_component_compiler/token.rb
74
+ - lib/vue_component_compiler/tokenizer.rb
75
+ - lib/vue_component_compiler/version.rb
76
+ - vue_component_compiler.gemspec
77
+ homepage: https://github.com/g-plane/vue-component-compiler-rb
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.7.6
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Vue component compiler
101
+ test_files: []