condenser 1.2 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/condenser/asset.rb +19 -16
- data/lib/condenser/build_cache.rb +1 -1
- data/lib/condenser/context.rb +9 -25
- data/lib/condenser/helpers/parse_helpers.rb +1 -1
- data/lib/condenser/manifest.rb +3 -1
- data/lib/condenser/pipeline.rb +8 -3
- data/lib/condenser/processors/babel_processor.rb +1 -1
- data/lib/condenser/processors/css_media_combiner_processor.rb +81 -0
- data/lib/condenser/processors/js_analyzer.rb +0 -2
- data/lib/condenser/processors/purgecss_processor.rb +6 -4
- data/lib/condenser/processors/rollup_processor.rb +37 -35
- data/lib/condenser/resolve.rb +1 -3
- data/lib/condenser/templating_engine/ejs.rb +1 -1
- data/lib/condenser/transformers/dart_sass_transformer.rb +285 -0
- data/lib/condenser/transformers/jst_transformer.rb +67 -17
- data/lib/condenser/transformers/sass/functions.rb +133 -0
- data/lib/condenser/transformers/sass/importer.rb +48 -0
- data/lib/condenser/transformers/sass.rb +4 -0
- data/lib/condenser/transformers/sass_transformer.rb +124 -281
- data/lib/condenser/transformers/svg_transformer/base.rb +26 -0
- data/lib/condenser/transformers/svg_transformer/tag.rb +54 -0
- data/lib/condenser/transformers/svg_transformer/template.rb +151 -0
- data/lib/condenser/transformers/svg_transformer/template_error.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/value.rb +13 -0
- data/lib/condenser/transformers/svg_transformer/var_generator.rb +10 -0
- data/lib/condenser/transformers/svg_transformer.rb +19 -0
- data/lib/condenser/version.rb +1 -1
- data/lib/condenser.rb +17 -5
- data/test/cache_test.rb +46 -2
- data/test/dependency_test.rb +2 -2
- data/test/manifest_test.rb +34 -0
- data/test/minifiers/terser_minifier_test.rb +0 -1
- data/test/minifiers/uglify_minifier_test.rb +0 -1
- data/test/postprocessors/css_media_combiner_test.rb +107 -0
- data/test/postprocessors/purgecss_test.rb +62 -0
- data/test/preprocessor/babel_test.rb +693 -299
- data/test/preprocessor/js_analyzer_test.rb +0 -2
- data/test/processors/rollup_test.rb +50 -20
- data/test/resolve_test.rb +8 -9
- data/test/server_test.rb +6 -1
- data/test/templates/ejs_test.rb +2 -11
- data/test/templates/erb_test.rb +0 -5
- data/test/test_helper.rb +3 -1
- data/test/transformers/dart_scss_test.rb +139 -0
- data/test/transformers/jst_test.rb +165 -21
- data/test/transformers/scss_test.rb +14 -0
- data/test/transformers/svg_test.rb +40 -0
- metadata +23 -6
- data/lib/condenser/transformers/sass_transformer/importer.rb +0 -50
@@ -1,309 +1,152 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
# Transformer engine class for the SASS/SCSS compiler. Depends on the `sass`
|
2
|
+
# gem.
|
3
|
+
#
|
4
|
+
# For more infomation see:
|
5
|
+
#
|
6
|
+
# https://github.com/sass/sass
|
7
|
+
# https://github.com/rails/sass-rails
|
8
|
+
#
|
9
|
+
class Condenser::SassTransformer
|
10
|
+
|
11
|
+
attr_accessor :options
|
12
|
+
|
13
|
+
# Internal: Defines default sass syntax to use. Exposed so the ScssProcessor
|
14
|
+
# may override it.
|
15
|
+
def self.syntax
|
16
|
+
:sass
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.setup(environment)
|
20
|
+
require "sassc" unless defined?(::SassC::Engine)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Return singleton instance with default options.
|
9
24
|
#
|
10
|
-
|
11
|
-
|
25
|
+
# Returns SassProcessor object.
|
26
|
+
def self.instance
|
27
|
+
@instance ||= new
|
28
|
+
end
|
12
29
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# may override it.
|
17
|
-
def self.syntax
|
18
|
-
:sass
|
19
|
-
end
|
30
|
+
def self.call(environment, input)
|
31
|
+
instance.call(environment, input)
|
32
|
+
end
|
20
33
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
# Public: Return singleton instance with default options.
|
26
|
-
#
|
27
|
-
# Returns SassProcessor object.
|
28
|
-
def self.instance
|
29
|
-
@instance ||= new
|
30
|
-
end
|
34
|
+
def self.cache_key
|
35
|
+
instance.cache_key
|
36
|
+
end
|
31
37
|
|
32
|
-
|
33
|
-
instance.call(environment, input)
|
34
|
-
end
|
38
|
+
attr_reader :cache_key
|
35
39
|
|
36
|
-
|
37
|
-
|
40
|
+
def name
|
41
|
+
self.class.name
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: Initialize template with custom options.
|
45
|
+
#
|
46
|
+
# options - Hash
|
47
|
+
# cache_version - String custom cache version. Used to force a cache
|
48
|
+
# change after code changes are made to Sass Functions.
|
49
|
+
#
|
50
|
+
def initialize(options = {}, &block)
|
51
|
+
@options = options
|
52
|
+
@cache_version = options[:cache_version]
|
53
|
+
# @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::VERSION}:#{@cache_version}".freeze
|
54
|
+
@importer_class = options[:importer] || Condenser::Sass::Importer
|
55
|
+
|
56
|
+
@sass_config = options[:sass_config] || {}
|
57
|
+
@functions = Module.new do
|
58
|
+
include Functions
|
59
|
+
include options[:functions] if options[:functions]
|
60
|
+
class_eval(&block) if block_given?
|
38
61
|
end
|
62
|
+
end
|
39
63
|
|
40
|
-
|
64
|
+
def call(environment, input)
|
65
|
+
context = environment.new_context_class
|
66
|
+
engine_options = merge_options({
|
67
|
+
syntax: self.class.syntax,
|
68
|
+
filename: input[:filename],
|
69
|
+
source_map_file: "#{input[:filename]}.map",
|
70
|
+
source_map_contents: true,
|
71
|
+
# cache_store: Cache.new(environment.cache),
|
72
|
+
load_paths: environment.path,
|
73
|
+
importer: @importer_class,
|
74
|
+
condenser: { context: context, environment: environment },
|
75
|
+
asset: input
|
76
|
+
})
|
77
|
+
|
78
|
+
engine = SassC::Engine.new(input[:source], engine_options)
|
41
79
|
|
42
|
-
|
43
|
-
|
80
|
+
css = Condenser::Utils.module_include(SassC::Script::Functions, @functions) do
|
81
|
+
engine.render
|
44
82
|
end
|
83
|
+
css.delete_suffix!("\n/*# sourceMappingURL=#{File.basename(input[:filename])}.map */")
|
84
|
+
# engine.source_map
|
85
|
+
# css = css.delete_suffix!("\n/*# sourceMappingURL= */\n")
|
45
86
|
|
46
|
-
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
#
|
52
|
-
def initialize(options = {}, &block)
|
53
|
-
@options = options
|
54
|
-
@cache_version = options[:cache_version]
|
55
|
-
# @cache_key = "#{self.class.name}:#{VERSION}:#{Autoload::Sass::VERSION}:#{@cache_version}".freeze
|
56
|
-
@importer_class = options[:importer] || Condenser::SassTransformer::Importer
|
57
|
-
|
58
|
-
@sass_config = options[:sass_config] || {}
|
59
|
-
@functions = Module.new do
|
60
|
-
include Functions
|
61
|
-
include options[:functions] if options[:functions]
|
62
|
-
class_eval(&block) if block_given?
|
63
|
-
end
|
64
|
-
# puts @functions.method(:asset_path).source_location
|
65
|
-
end
|
87
|
+
input[:source] = css
|
88
|
+
# input[:map] = map.to_json({})
|
89
|
+
input[:linked_assets] += context.links
|
90
|
+
input[:process_dependencies] += context.dependencies
|
91
|
+
end
|
66
92
|
|
67
|
-
|
68
|
-
# context = input[:environment].context_class.new(input)
|
69
|
-
engine_options = merge_options({
|
70
|
-
syntax: self.class.syntax,
|
71
|
-
filename: input[:filename],
|
72
|
-
source_map_file: "#{input[:filename]}.map",
|
73
|
-
source_map_contents: true,
|
74
|
-
# cache_store: Cache.new(environment.cache),
|
75
|
-
load_paths: environment.path,
|
76
|
-
importer: @importer_class,
|
77
|
-
condenser: {
|
78
|
-
context: environment.new_context_class,
|
79
|
-
environment: environment
|
80
|
-
},
|
81
|
-
asset: input
|
82
|
-
})
|
93
|
+
private
|
83
94
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
95
|
+
# Public: Build the cache store to be used by the Sass engine.
|
96
|
+
#
|
97
|
+
# input - the input hash.
|
98
|
+
# version - the cache version.
|
99
|
+
#
|
100
|
+
# Override this method if you need to use a different cache than the
|
101
|
+
# Condenser cache.
|
102
|
+
def build_cache_store(input, version)
|
103
|
+
CacheStore.new(input[:cache], version)
|
104
|
+
end
|
92
105
|
|
106
|
+
def merge_options(options)
|
107
|
+
defaults = @sass_config.dup
|
93
108
|
|
94
|
-
|
95
|
-
|
109
|
+
if load_paths = defaults.delete(:load_paths)
|
110
|
+
options[:load_paths] += load_paths
|
96
111
|
end
|
97
112
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
#
|
102
|
-
# input - the input hash.
|
103
|
-
# version - the cache version.
|
104
|
-
#
|
105
|
-
# Override this method if you need to use a different cache than the
|
106
|
-
# Condenser cache.
|
107
|
-
def build_cache_store(input, version)
|
108
|
-
CacheStore.new(input[:cache], version)
|
109
|
-
end
|
113
|
+
options.merge!(defaults)
|
114
|
+
options
|
115
|
+
end
|
110
116
|
|
111
|
-
|
112
|
-
|
117
|
+
# Functions injected into Sass context during Condenser evaluation.
|
118
|
+
module Functions
|
119
|
+
include Condenser::Sass::Functions
|
113
120
|
|
114
|
-
|
115
|
-
|
116
|
-
|
121
|
+
# Returns a Sass::Script::String.
|
122
|
+
def asset_path(path, options = {})
|
123
|
+
condenser_context.link_asset(path.value)
|
117
124
|
|
118
|
-
|
119
|
-
|
125
|
+
path = condenser_context.asset_path(path.value, options)
|
126
|
+
query = "?#{query}" if query
|
127
|
+
fragment = "##{fragment}" if fragment
|
128
|
+
SassC::Script::Value::String.new("#{path}#{query}#{fragment}", :string)
|
120
129
|
end
|
121
130
|
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
# is preferred.
|
127
|
-
#
|
128
|
-
# module Condenser::SassProcessor::Functions
|
129
|
-
# def asset_path(path, options = {})
|
130
|
-
# end
|
131
|
-
# end
|
132
|
-
#
|
133
|
-
module Functions
|
134
|
-
# Public: Generate a url for asset path.
|
135
|
-
#
|
136
|
-
# Default implementation is deprecated. Currently defaults to
|
137
|
-
# Context#asset_path.
|
138
|
-
#
|
139
|
-
# Will raise NotImplementedError in the future. Users should provide their
|
140
|
-
# own base implementation.
|
141
|
-
#
|
142
|
-
# Returns a Sass::Script::String.
|
143
|
-
def asset_path(path, options = {})
|
144
|
-
path = path.value
|
145
|
-
|
146
|
-
path, _, query, fragment = URI.split(path)[5..8]
|
147
|
-
asset = condenser_environment.find!(path)
|
148
|
-
condenser_context.link_asset(path)
|
149
|
-
path = condenser_context.asset_path(asset.path, options)
|
150
|
-
query = "?#{query}" if query
|
151
|
-
fragment = "##{fragment}" if fragment
|
152
|
-
SassC::Script::Value::String.new("#{path}#{query}#{fragment}", :string)
|
153
|
-
end
|
154
|
-
|
155
|
-
# Public: Generate a asset url() link.
|
156
|
-
#
|
157
|
-
# path - Sass::Script::String URL path
|
158
|
-
#
|
159
|
-
# Returns a Sass::Script::String.
|
160
|
-
def asset_url(path, options = {})
|
161
|
-
SassC::Script::Value::String.new("url(#{asset_path(path, options).value})")
|
162
|
-
end
|
163
|
-
|
164
|
-
# Public: Generate url for image path.
|
165
|
-
#
|
166
|
-
# path - Sass::Script::String URL path
|
167
|
-
#
|
168
|
-
# Returns a Sass::Script::String.
|
169
|
-
def image_path(path)
|
170
|
-
asset_path(path, type: :image)
|
171
|
-
end
|
172
|
-
|
173
|
-
# Public: Generate a image url() link.
|
174
|
-
#
|
175
|
-
# path - Sass::Script::String URL path
|
176
|
-
#
|
177
|
-
# Returns a Sass::Script::String.
|
178
|
-
def image_url(path)
|
179
|
-
asset_url(path, type: :image)
|
180
|
-
end
|
181
|
-
|
182
|
-
# Public: Generate url for video path.
|
183
|
-
#
|
184
|
-
# path - Sass::Script::String URL path
|
185
|
-
#
|
186
|
-
# Returns a Sass::Script::String.
|
187
|
-
def video_path(path)
|
188
|
-
asset_path(path, type: :video)
|
189
|
-
end
|
190
|
-
|
191
|
-
# Public: Generate a video url() link.
|
192
|
-
#
|
193
|
-
# path - Sass::Script::String URL path
|
194
|
-
#
|
195
|
-
# Returns a Sass::Script::String.
|
196
|
-
def video_url(path)
|
197
|
-
asset_url(path, type: :video)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Public: Generate url for audio path.
|
201
|
-
#
|
202
|
-
# path - Sass::Script::String URL path
|
203
|
-
#
|
204
|
-
# Returns a Sass::Script::String.
|
205
|
-
def audio_path(path)
|
206
|
-
asset_path(path, type: :audio)
|
207
|
-
end
|
208
|
-
|
209
|
-
# Public: Generate a audio url() link.
|
210
|
-
#
|
211
|
-
# path - Sass::Script::String URL path
|
212
|
-
#
|
213
|
-
# Returns a Sass::Script::String.
|
214
|
-
def audio_url(path)
|
215
|
-
asset_url(path, type: :audio)
|
216
|
-
end
|
217
|
-
|
218
|
-
# Public: Generate url for font path.
|
219
|
-
#
|
220
|
-
# path - Sass::Script::String URL path
|
221
|
-
#
|
222
|
-
# Returns a Sass::Script::String.
|
223
|
-
def font_path(path)
|
224
|
-
asset_path(path, type: :font)
|
225
|
-
end
|
226
|
-
|
227
|
-
# Public: Generate a font url() link.
|
228
|
-
#
|
229
|
-
# path - Sass::Script::String URL path
|
230
|
-
#
|
231
|
-
# Returns a Sass::Script::String.
|
232
|
-
def font_url(path)
|
233
|
-
asset_url(path, type: :font)
|
234
|
-
end
|
235
|
-
|
236
|
-
# Public: Generate url for javascript path.
|
237
|
-
#
|
238
|
-
# path - Sass::Script::String URL path
|
239
|
-
#
|
240
|
-
# Returns a Sass::Script::String.
|
241
|
-
def javascript_path(path)
|
242
|
-
asset_path(path, type: :javascript)
|
243
|
-
end
|
244
|
-
|
245
|
-
# Public: Generate a javascript url() link.
|
246
|
-
#
|
247
|
-
# path - Sass::Script::String URL path
|
248
|
-
#
|
249
|
-
# Returns a Sass::Script::String.
|
250
|
-
def javascript_url(path)
|
251
|
-
asset_url(path, type: :javascript)
|
252
|
-
end
|
253
|
-
|
254
|
-
# Public: Generate url for stylesheet path.
|
255
|
-
#
|
256
|
-
# path - Sass::Script::String URL path
|
257
|
-
#
|
258
|
-
# Returns a Sass::Script::String.
|
259
|
-
def stylesheet_path(path)
|
260
|
-
asset_path(path, type: :stylesheet)
|
261
|
-
end
|
262
|
-
|
263
|
-
# Public: Generate a stylesheet url() link.
|
264
|
-
#
|
265
|
-
# path - Sass::Script::String URL path
|
266
|
-
#
|
267
|
-
# Returns a Sass::Script::String.
|
268
|
-
def stylesheet_url(path)
|
269
|
-
asset_url(path, type: :stylesheet)
|
270
|
-
end
|
271
|
-
|
272
|
-
# Public: Generate a data URI for asset path.
|
273
|
-
#
|
274
|
-
# path - Sass::Script::String logical asset path
|
275
|
-
#
|
276
|
-
# Returns a Sass::Script::String.
|
277
|
-
def asset_data_url(path)
|
278
|
-
url = condenser_environment.asset_data_uri(path.value)
|
279
|
-
Sass::Script::String.new("url(" + url + ")")
|
280
|
-
end
|
281
|
-
|
282
|
-
protected
|
283
|
-
# Public: The Environment.
|
284
|
-
#
|
285
|
-
# Returns Condenser::Environment.
|
286
|
-
def condenser_context
|
287
|
-
options[:condenser][:context]
|
288
|
-
end
|
289
|
-
|
290
|
-
def condenser_environment
|
291
|
-
options[:condenser][:environment]
|
292
|
-
end
|
131
|
+
# Returns a Sass::Script::String.
|
132
|
+
def asset_url(path, options = {})
|
133
|
+
SassC::Script::Value::String.new("url(#{asset_path(path, options).value})")
|
134
|
+
end
|
293
135
|
|
294
|
-
|
295
|
-
#
|
296
|
-
# Returns a Set.
|
297
|
-
def condenser_dependencies
|
298
|
-
options[:condenser][:process_dependencies]
|
299
|
-
end
|
136
|
+
protected
|
300
137
|
|
138
|
+
def condenser_context
|
139
|
+
options[:condenser][:context]
|
140
|
+
end
|
141
|
+
|
142
|
+
def condenser_environment
|
143
|
+
options[:condenser][:environment]
|
301
144
|
end
|
302
145
|
end
|
146
|
+
end
|
303
147
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end
|
148
|
+
class Condenser::ScssTransformer < Condenser::SassTransformer
|
149
|
+
def self.syntax
|
150
|
+
:scss
|
308
151
|
end
|
309
152
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Condenser::SVGTransformer::Base
|
2
|
+
|
3
|
+
attr_accessor :children
|
4
|
+
|
5
|
+
def initialize(escape: nil)
|
6
|
+
@children = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_module()
|
10
|
+
var_generator = Condenser::SVGTransformer::VarGenerator.new
|
11
|
+
|
12
|
+
<<~JS
|
13
|
+
export default function (svgAttributes) {
|
14
|
+
#{@children.last.to_js(var_generator: var_generator)}
|
15
|
+
if (svgAttributes) {
|
16
|
+
Object.keys(svgAttributes).forEach(function (key) {
|
17
|
+
__a.setAttribute(key, svgAttributes[key]);
|
18
|
+
});
|
19
|
+
}
|
20
|
+
|
21
|
+
return __a;
|
22
|
+
}
|
23
|
+
JS
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Condenser::SVGTransformer::Tag
|
2
|
+
|
3
|
+
attr_accessor :tag_name, :attrs, :children, :namespace
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
@tag_name = name
|
7
|
+
@attrs = []
|
8
|
+
@children = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
@value
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#<SVG::Tag:#{self.object_id} @tag_name=#{tag_name}>"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_js(append: nil, var_generator:, indentation: 4, namespace: nil)
|
20
|
+
namespace ||= self.namespace
|
21
|
+
|
22
|
+
output_var = var_generator.next
|
23
|
+
js = "#{' '*indentation}var #{output_var} = document.createElement"
|
24
|
+
js << if namespace
|
25
|
+
"NS(#{namespace.to_js}, #{JSON.generate(tag_name)});\n"
|
26
|
+
else
|
27
|
+
"(#{JSON.generate(tag_name)});\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
@attrs.each do |attr|
|
31
|
+
if attr.is_a?(Hash)
|
32
|
+
attr.each do |k, v|
|
33
|
+
js << "#{' '*indentation}#{output_var}.setAttribute(#{JSON.generate(k)}, #{v.is_a?(String) ? v : v.to_js});\n"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
js << "#{' '*indentation}#{output_var}.setAttribute(#{JSON.generate(attr)}, \"\");\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@children.each do |child|
|
41
|
+
js << if child.is_a?(Condenser::SVGTransformer::Tag)
|
42
|
+
child.to_js(var_generator: var_generator, indentation: indentation, append: output_var, namespace: namespace)
|
43
|
+
else
|
44
|
+
child.to_js(var_generator: var_generator, indentation: indentation, append: output_var)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
js << "#{' '*indentation}#{append}.append(#{output_var});\n" if append
|
49
|
+
|
50
|
+
js
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
class Condenser::SVGTransformer::Template
|
2
|
+
|
3
|
+
include Condenser::ParseHelpers
|
4
|
+
|
5
|
+
attr_accessor :source
|
6
|
+
|
7
|
+
START_TAGS = ['<']
|
8
|
+
CLOSE_TAGS = ['/>', '>']
|
9
|
+
VOID_ELEMENTS = ['!DOCTYPE', '?xml']
|
10
|
+
|
11
|
+
def initialize(source)
|
12
|
+
@source = source.strip
|
13
|
+
process
|
14
|
+
end
|
15
|
+
|
16
|
+
def process
|
17
|
+
seek(0)
|
18
|
+
@tree = [Condenser::SVGTransformer::Base.new]
|
19
|
+
@stack = [:str]
|
20
|
+
|
21
|
+
while !eos?
|
22
|
+
case @stack.last
|
23
|
+
when :str
|
24
|
+
scan_until(Regexp.new("(#{START_TAGS.map{|s| Regexp.escape(s) }.join('|')}|\\z)"))
|
25
|
+
if !matched.nil? && START_TAGS.include?(matched)
|
26
|
+
@stack << :tag
|
27
|
+
end
|
28
|
+
when :tag
|
29
|
+
scan_until(Regexp.new("(\\/|[^\\s>]+)"))
|
30
|
+
if matched == '/'
|
31
|
+
@stack.pop
|
32
|
+
@stack << :close_tag
|
33
|
+
else
|
34
|
+
@tree << Condenser::SVGTransformer::Tag.new(matched)
|
35
|
+
@stack << :tag_attr_key
|
36
|
+
end
|
37
|
+
when :close_tag
|
38
|
+
scan_until(Regexp.new("([^\\s>]+)"))
|
39
|
+
|
40
|
+
el = @tree.pop
|
41
|
+
if el.tag_name != matched
|
42
|
+
raise Condenser::SVGTransformer::TemplateError.new("Expected to close #{el.tag_name.inspect} tag, instead closed #{matched.inspect}\n#{cursor}")
|
43
|
+
end
|
44
|
+
if !['!DOCTYPE', '?xml'].include?(el.tag_name)
|
45
|
+
@tree.last.children << el
|
46
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')})"))
|
47
|
+
@stack.pop
|
48
|
+
end
|
49
|
+
when :tag_attr_key
|
50
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')}|[^\\s=>]+)"))
|
51
|
+
if CLOSE_TAGS.include?(matched)
|
52
|
+
if matched == '/>' || VOID_ELEMENTS.include?(@tree.last.tag_name)
|
53
|
+
el = @tree.pop
|
54
|
+
@tree.last.children << el
|
55
|
+
@stack.pop
|
56
|
+
@stack.pop
|
57
|
+
else
|
58
|
+
@stack << :str
|
59
|
+
end
|
60
|
+
else
|
61
|
+
key = if matched.start_with?('"') && matched.end_with?('"')
|
62
|
+
matched[1..-2]
|
63
|
+
elsif matched.start_with?('"') && matched.end_with?('"')
|
64
|
+
matched[1..-2]
|
65
|
+
else
|
66
|
+
matched
|
67
|
+
end
|
68
|
+
@tree.last.attrs << key
|
69
|
+
@stack << :tag_attr_value_tx
|
70
|
+
end
|
71
|
+
when :tag_attr_value_tx
|
72
|
+
scan_until(Regexp.new("(#{(CLOSE_TAGS).map{|s| Regexp.escape(s) }.join('|')}|=|\\S)"))
|
73
|
+
tag_key = @tree.last.attrs.pop
|
74
|
+
if CLOSE_TAGS.include?(matched)
|
75
|
+
el = @tree.last
|
76
|
+
el.attrs << tag_key
|
77
|
+
if VOID_ELEMENTS.include?(el.tag_name)
|
78
|
+
@tree.pop
|
79
|
+
@tree.last.children << el
|
80
|
+
end
|
81
|
+
@stack.pop
|
82
|
+
@stack.pop
|
83
|
+
@stack.pop
|
84
|
+
elsif matched == '='
|
85
|
+
@stack.pop
|
86
|
+
@tree.last.attrs << tag_key
|
87
|
+
@stack << :tag_attr_value
|
88
|
+
else
|
89
|
+
@stack.pop
|
90
|
+
@tree.last.attrs << tag_key
|
91
|
+
rewind(1)
|
92
|
+
end
|
93
|
+
|
94
|
+
when :tag_attr_value
|
95
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')}|'|\"|\\S+)"))
|
96
|
+
|
97
|
+
if matched == '"'
|
98
|
+
@stack.pop
|
99
|
+
@stack << :tag_attr_value_double_quoted
|
100
|
+
elsif matched == "'"
|
101
|
+
@stack.pop
|
102
|
+
@stack << :tag_attr_value_single_quoted
|
103
|
+
else
|
104
|
+
@stack.pop
|
105
|
+
key = @tree.last.attrs.pop
|
106
|
+
@tree.last.namespace = matched if key == 'xmlns'
|
107
|
+
@tree.last.attrs << { key => matched }
|
108
|
+
end
|
109
|
+
when :tag_attr_value_double_quoted
|
110
|
+
quoted_value = ''
|
111
|
+
scan_until(/"/)
|
112
|
+
quoted_value << pre_match if !pre_match.strip.empty?
|
113
|
+
rewind(1)
|
114
|
+
|
115
|
+
quoted_value = Condenser::SVGTransformer::Value.new(quoted_value)
|
116
|
+
|
117
|
+
key = @tree.last.attrs.pop
|
118
|
+
@tree.last.namespace = quoted_value if key == 'xmlns'
|
119
|
+
if @tree.last.attrs.last.is_a?(Hash) && !@tree.last.attrs.last.has_key?(key)
|
120
|
+
@tree.last.attrs.last[key] = quoted_value
|
121
|
+
else
|
122
|
+
@tree.last.attrs << { key => quoted_value }
|
123
|
+
end
|
124
|
+
scan_until(/\"/)
|
125
|
+
@stack.pop
|
126
|
+
when :tag_attr_value_single_quoted
|
127
|
+
quoted_value = ''
|
128
|
+
scan_until(/(')/)
|
129
|
+
quoted_value << pre_match if !pre_match.strip.empty?
|
130
|
+
rewind(1)
|
131
|
+
|
132
|
+
quoted_value = Condenser::SVGTransformer::Value.new(quoted_value)
|
133
|
+
|
134
|
+
key = @tree.last.attrs.pop
|
135
|
+
@tree.last.namespace = quoted_value if key == 'xmlns'
|
136
|
+
if @tree.last.attrs.last.is_a?(Hash) && !@tree.last.attrs.last.has_key?(key)
|
137
|
+
@tree.last.attrs.last[key] = quoted_value
|
138
|
+
else
|
139
|
+
@tree.last.attrs << { key => quoted_value }
|
140
|
+
end
|
141
|
+
scan_until(/\'/)
|
142
|
+
@stack.pop
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def to_module
|
148
|
+
@tree.first.to_module
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|