condenser 1.4 → 1.5.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.
- checksums.yaml +4 -4
- data/lib/condenser/asset.rb +55 -8
- data/lib/condenser/build_cache.rb +2 -0
- data/lib/condenser/cache/file_store.rb +1 -0
- data/lib/condenser/cache/memory_store.rb +1 -0
- data/lib/condenser/cache/null_store.rb +1 -0
- data/lib/condenser/cache_store.rb +1 -0
- data/lib/condenser/context.rb +1 -0
- data/lib/condenser/encoding_utils.rb +2 -0
- data/lib/condenser/environment.rb +2 -0
- data/lib/condenser/errors.rb +2 -0
- data/lib/condenser/export.rb +11 -6
- data/lib/condenser/helpers/parse_helpers.rb +19 -4
- data/lib/condenser/manifest.rb +6 -4
- data/lib/condenser/minifiers/sass_minifier.rb +2 -0
- data/lib/condenser/minifiers/terser_minifier.rb +2 -0
- data/lib/condenser/minifiers/uglify_minifier.rb +2 -0
- data/lib/condenser/pipeline.rb +2 -0
- data/lib/condenser/processors/babel_processor.rb +11 -2
- data/lib/condenser/processors/css_media_combiner_processor.rb +7 -5
- data/lib/condenser/processors/js_analyzer.rb +109 -37
- data/lib/condenser/processors/node_processor.rb +2 -0
- data/lib/condenser/processors/purgecss_processor.rb +2 -0
- data/lib/condenser/processors/rollup_processor.rb +289 -136
- data/lib/condenser/resolve.rb +15 -7
- data/lib/condenser/server.rb +22 -20
- data/lib/condenser/templating_engine/ejs.rb +2 -0
- data/lib/condenser/templating_engine/erb.rb +2 -0
- data/lib/condenser/transformers/dart_sass_transformer.rb +5 -3
- data/lib/condenser/transformers/jst_transformer.rb +2 -0
- data/lib/condenser/transformers/sass/functions.rb +2 -0
- data/lib/condenser/transformers/sass/importer.rb +2 -0
- data/lib/condenser/transformers/sass.rb +2 -0
- data/lib/condenser/transformers/sass_transformer.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/base.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/tag.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/template.rb +3 -1
- data/lib/condenser/transformers/svg_transformer/template_error.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/value.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/var_generator.rb +2 -0
- data/lib/condenser/transformers/svg_transformer.rb +2 -0
- data/lib/condenser/utils.rb +2 -0
- data/lib/condenser/version.rb +3 -1
- data/lib/condenser/writers/brotli_writer.rb +2 -0
- data/lib/condenser/writers/file_writer.rb +2 -0
- data/lib/condenser/writers/zlib_writer.rb +2 -0
- data/lib/condenser.rb +2 -0
- data/lib/rake/condensertask.rb +2 -0
- data/test/cache_test.rb +14 -14
- data/test/manifest_test.rb +17 -2
- data/test/postprocessors/css_media_combiner_test.rb +9 -12
- data/test/preprocessor/babel_test.rb +843 -327
- data/test/preprocessor/js_analyzer_test.rb +174 -5
- data/test/processors/rollup/dynamic_import_test.rb +358 -0
- data/test/processors/rollup_test.rb +37 -56
- data/test/resolve_test.rb +4 -9
- data/test/server_test.rb +6 -5
- data/test/transformers/dart_scss_test.rb +2 -2
- data/test/transformers/scss_test.rb +2 -2
- metadata +6 -11
- data/lib/condenser/minifiers/package-lock.json +0 -25
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Condenser::JSAnalyzer
|
2
4
|
|
3
5
|
include Condenser::ParseHelpers
|
@@ -14,7 +16,9 @@ class Condenser::JSAnalyzer
|
|
14
16
|
@sourcefile = input[:source_file]
|
15
17
|
@source = input[:source]
|
16
18
|
@stack = [:main]
|
19
|
+
@previous = [[]]
|
17
20
|
|
21
|
+
input[:linked_assets] ||= Set.new
|
18
22
|
input[:export_dependencies] ||= Set.new
|
19
23
|
|
20
24
|
scan_until(/\A(\/\/[^\n]*(\n|\z))*/)
|
@@ -36,14 +40,19 @@ class Condenser::JSAnalyzer
|
|
36
40
|
scan_until(/(\$\{|\`)/)
|
37
41
|
case matched
|
38
42
|
when '`'
|
39
|
-
@stack.pop
|
43
|
+
@stack.pop if pre_match[-1] != "\\" && pre_match[-1] != "\\"
|
40
44
|
when '${'
|
41
45
|
@stack << :tick_statment
|
42
46
|
end
|
43
47
|
|
44
48
|
when :import
|
45
|
-
scan_until(/[\"\'
|
46
|
-
|
49
|
+
scan_until(/[\"\'\`\(]/)
|
50
|
+
dynamic = if matched == "("
|
51
|
+
scan_until(/[\"\'\`]/)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
filename = case matched
|
47
56
|
when "\""
|
48
57
|
double_quoted_value
|
49
58
|
when "'"
|
@@ -51,16 +60,26 @@ class Condenser::JSAnalyzer
|
|
51
60
|
when '`'
|
52
61
|
tick_quoted_value
|
53
62
|
end
|
54
|
-
|
63
|
+
|
64
|
+
input[:type] = "module"
|
65
|
+
if dynamic
|
66
|
+
input[:process_dependencies] << filename
|
67
|
+
input[:linked_assets] << filename
|
68
|
+
else
|
69
|
+
input[:export_dependencies] << filename
|
70
|
+
end
|
71
|
+
scan_until(/(;|\n|\))/)
|
55
72
|
@stack.pop
|
56
73
|
|
57
74
|
when :export
|
75
|
+
input[:type] = "module"
|
58
76
|
input[:exports] = true;
|
59
77
|
input[:default_export] = true if gobble(/\s+default/)
|
60
78
|
gobble(/\s+/)
|
61
79
|
|
62
80
|
if gobble(/\{/)
|
63
81
|
@stack << :brackets
|
82
|
+
@previous << []
|
64
83
|
elsif gobble(/\*/)
|
65
84
|
@stack << :export_from
|
66
85
|
else
|
@@ -81,42 +100,77 @@ class Condenser::JSAnalyzer
|
|
81
100
|
@stack.pop
|
82
101
|
|
83
102
|
else
|
84
|
-
scan_until(/(\/\/|\/\*|\/|\(|\)|\{|\}|\"|\'|\`|export|import|\z)/)
|
103
|
+
scan_until(/(\/\/|\/\*|\/|\(|\)|\{|\}|\"|\'|\`|export(?![[:alnum:]])|import(?![[:alnum:]])|\z)/)
|
85
104
|
|
86
105
|
case matched
|
87
106
|
when '//'
|
88
107
|
scan_until(/(\n|\z)/)
|
108
|
+
@previous.last << :single_line_comment
|
89
109
|
when '/*'
|
90
110
|
scan_until(/\*\//)
|
111
|
+
@previous.last << :multi_line_comment
|
91
112
|
when '"'
|
92
113
|
double_quoted_value
|
114
|
+
@previous.last << :double_quoted_value
|
93
115
|
when "'"
|
94
116
|
single_quoted_value
|
117
|
+
@previous.last << :single_quoted_value
|
95
118
|
when '`'
|
96
119
|
@stack << :tick_value
|
97
120
|
when '/'
|
98
|
-
if
|
99
|
-
|
100
|
-
|
121
|
+
if pre_match.match(/(\W|\A)(void|typeof|return|export)\z/)
|
122
|
+
regex_value
|
123
|
+
elsif match_index = @source.rindex(/(\w+|\)|\])(\s*)\//m, @index)
|
124
|
+
match = @source.match(/(\w+|\)|\])(\s*)\//, match_index)
|
125
|
+
|
126
|
+
x = @previous.last.dup
|
127
|
+
while match[2]&.index("\n") && [:single_line_comment, :multi_line_comment].include?(x.last)
|
128
|
+
case x.last
|
129
|
+
when :single_line_comment
|
130
|
+
match_index = @source.rindex(/[^\n]*\/\/[^\n]*\s*/m, match.begin(2))
|
131
|
+
match = @source.match(/(\w+|\)|\])\s*\//, match_index)
|
132
|
+
when :multi_line_comment
|
133
|
+
match_index = @source.rindex(/\/\*/m, match.begin(2))
|
134
|
+
match = @source.match(/(\w+|\)|\])\s*\//, match_index)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if @previous.last.last == :loop && match[1] =~ /\)\z/
|
139
|
+
regex_value
|
140
|
+
elsif %w(void typeof return export).include?(match[1])
|
141
|
+
regex_value
|
142
|
+
elsif match[0].length + match_index != @index
|
143
|
+
regex_value
|
144
|
+
elsif match[1].strip.empty?
|
101
145
|
regex_value
|
102
146
|
end
|
103
147
|
else
|
104
148
|
regex_value
|
105
149
|
end
|
106
150
|
when '('
|
107
|
-
@stack
|
151
|
+
@stack << if pre_match =~ /\W*(for|while)\s*\z/
|
152
|
+
:loop
|
153
|
+
else
|
154
|
+
:parenthesis
|
155
|
+
end
|
108
156
|
when ')'
|
109
|
-
raise unexptected_token(")") if @stack.last != :parenthesis
|
110
|
-
@stack.pop
|
157
|
+
raise unexptected_token(")") if @stack.last != :parenthesis && @stack.last != :loop
|
158
|
+
@previous.last << @stack.pop
|
111
159
|
when '{'
|
112
160
|
@stack.push :brackets
|
161
|
+
@previous << []
|
113
162
|
when '}'
|
114
163
|
case @stack.last
|
115
164
|
when :tick_statment
|
116
165
|
@stack.pop
|
117
166
|
when :brackets
|
118
167
|
@stack.pop
|
119
|
-
@
|
168
|
+
@previous.pop
|
169
|
+
@previous.last << :brackets
|
170
|
+
if @stack.last == :export
|
171
|
+
@stack.pop
|
172
|
+
@stack << :export_from if peek(/\s+from/i)
|
173
|
+
end
|
120
174
|
else
|
121
175
|
raise unexptected_token("}")
|
122
176
|
end
|
@@ -125,9 +179,7 @@ class Condenser::JSAnalyzer
|
|
125
179
|
@stack << :export
|
126
180
|
end
|
127
181
|
when 'import'
|
128
|
-
|
129
|
-
@stack << :import
|
130
|
-
end
|
182
|
+
@stack << :import
|
131
183
|
else
|
132
184
|
@stack.pop
|
133
185
|
end
|
@@ -142,6 +194,8 @@ class Condenser::JSAnalyzer
|
|
142
194
|
last_stack = @stack.last
|
143
195
|
end
|
144
196
|
end
|
197
|
+
|
198
|
+
raise Condenser::SyntaxError, "Unexpected EOF" if !@stack.empty? && @stack.last != :main
|
145
199
|
end
|
146
200
|
|
147
201
|
def unexptected_token(token)
|
@@ -151,7 +205,7 @@ class Condenser::JSAnalyzer
|
|
151
205
|
|
152
206
|
message = "Unexpected token #{token} #{@sourcefile} #{lineno.to_s.rjust(4)}:#{(@index-start)}"
|
153
207
|
message << "\n#{lineno.to_s.rjust(4)}: " << @source[start..uptop]
|
154
|
-
message << "\n #{'-'* (@index-1-start)}#{'^'*(@matched.length)}"
|
208
|
+
message << "\n #{'-'* ([@index-1-start,1].max)}#{'^'*([@matched.length,1].max)}"
|
155
209
|
message << "\n"
|
156
210
|
|
157
211
|
syntax_error = Condenser::SyntaxError.new(message)
|
@@ -160,20 +214,17 @@ class Condenser::JSAnalyzer
|
|
160
214
|
end
|
161
215
|
|
162
216
|
def double_quoted_value
|
163
|
-
ret_value =
|
217
|
+
ret_value = String.new
|
164
218
|
|
165
|
-
while scan_until(/[\"\n]/)
|
166
|
-
|
219
|
+
while scan_until(/[\"\n\\]/)
|
220
|
+
case matched
|
221
|
+
when "\n"
|
167
222
|
raise unexptected_token("\\n")
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
ret_value << pre_match << "\\\""
|
174
|
-
end
|
175
|
-
|
176
|
-
|
223
|
+
when "\\"
|
224
|
+
ret_value << pre_match << matched << gobble(1)
|
225
|
+
when "\""
|
226
|
+
ret_value << pre_match
|
227
|
+
return ret_value
|
177
228
|
else
|
178
229
|
ret_value << match
|
179
230
|
end
|
@@ -181,7 +232,7 @@ class Condenser::JSAnalyzer
|
|
181
232
|
end
|
182
233
|
|
183
234
|
def single_quoted_value
|
184
|
-
ret_value =
|
235
|
+
ret_value = String.new
|
185
236
|
|
186
237
|
while scan_until(/[\'\n]/)
|
187
238
|
if matched == "\n"
|
@@ -196,7 +247,7 @@ class Condenser::JSAnalyzer
|
|
196
247
|
end
|
197
248
|
|
198
249
|
def tick_quoted_value
|
199
|
-
ret_value =
|
250
|
+
ret_value = String.new
|
200
251
|
|
201
252
|
while scan_until(/[\`]/)
|
202
253
|
if matched == "\`" && pre_match[-1] != "\\"
|
@@ -209,16 +260,37 @@ class Condenser::JSAnalyzer
|
|
209
260
|
end
|
210
261
|
|
211
262
|
def regex_value
|
212
|
-
ret_value =
|
263
|
+
ret_value = String.new
|
213
264
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
265
|
+
regex_stack = ['/']
|
266
|
+
while !regex_stack.empty?
|
267
|
+
|
268
|
+
scan_until(/[\/\[\]]/)
|
269
|
+
escaped = pre_match[-1] == "\\" && pre_match[-2] != "\\"
|
270
|
+
ret_value << pre_match
|
271
|
+
case matched
|
272
|
+
when "["
|
273
|
+
regex_stack << '[' if !escaped && regex_stack.last != "["
|
274
|
+
ret_value << matched
|
275
|
+
when "]"
|
276
|
+
regex_stack.pop if !escaped && regex_stack.last == "["
|
277
|
+
ret_value << matched
|
278
|
+
when "/"
|
279
|
+
# From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Character_class
|
280
|
+
#
|
281
|
+
# The lexical grammar does a very rough parse of regex literals, so
|
282
|
+
# that it does not end the regex literal at a / character which appears
|
283
|
+
# within a character class. This means /[/]/ is valid without needing
|
284
|
+
# to escape the /.
|
285
|
+
if !escaped && regex_stack.last != "[" && regex_stack.pop != "/"
|
286
|
+
raise unexptected_token("/")
|
287
|
+
else
|
288
|
+
ret_value << matched
|
289
|
+
end
|
220
290
|
end
|
221
291
|
end
|
292
|
+
|
293
|
+
ret_value
|
222
294
|
end
|
223
295
|
|
224
296
|
end
|