condenser 1.2 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/condenser/asset.rb +69 -35
  3. data/lib/condenser/build_cache.rb +22 -9
  4. data/lib/condenser/context.rb +9 -25
  5. data/lib/condenser/helpers/parse_helpers.rb +8 -1
  6. data/lib/condenser/manifest.rb +3 -1
  7. data/lib/condenser/pipeline.rb +8 -3
  8. data/lib/condenser/processors/babel_processor.rb +9 -15
  9. data/lib/condenser/processors/css_media_combiner_processor.rb +81 -0
  10. data/lib/condenser/processors/js_analyzer.rb +41 -8
  11. data/lib/condenser/processors/node_processor.rb +1 -0
  12. data/lib/condenser/processors/purgecss_processor.rb +6 -4
  13. data/lib/condenser/processors/rollup_processor.rb +38 -36
  14. data/lib/condenser/resolve.rb +27 -6
  15. data/lib/condenser/templating_engine/ejs.rb +1 -1
  16. data/lib/condenser/transformers/dart_sass_transformer.rb +285 -0
  17. data/lib/condenser/transformers/jst_transformer.rb +67 -17
  18. data/lib/condenser/transformers/sass/functions.rb +133 -0
  19. data/lib/condenser/transformers/sass/importer.rb +48 -0
  20. data/lib/condenser/transformers/sass.rb +4 -0
  21. data/lib/condenser/transformers/sass_transformer.rb +124 -281
  22. data/lib/condenser/transformers/svg_transformer/base.rb +26 -0
  23. data/lib/condenser/transformers/svg_transformer/tag.rb +54 -0
  24. data/lib/condenser/transformers/svg_transformer/template.rb +151 -0
  25. data/lib/condenser/transformers/svg_transformer/template_error.rb +2 -0
  26. data/lib/condenser/transformers/svg_transformer/value.rb +13 -0
  27. data/lib/condenser/transformers/svg_transformer/var_generator.rb +10 -0
  28. data/lib/condenser/transformers/svg_transformer.rb +19 -0
  29. data/lib/condenser/version.rb +1 -1
  30. data/lib/condenser.rb +17 -5
  31. data/test/cache_test.rb +157 -18
  32. data/test/dependency_test.rb +51 -2
  33. data/test/manifest_test.rb +34 -0
  34. data/test/minifiers/terser_minifier_test.rb +0 -1
  35. data/test/minifiers/uglify_minifier_test.rb +0 -1
  36. data/test/postprocessors/css_media_combiner_test.rb +107 -0
  37. data/test/postprocessors/purgecss_test.rb +62 -0
  38. data/test/preprocessor/babel_test.rb +703 -298
  39. data/test/preprocessor/js_analyzer_test.rb +35 -2
  40. data/test/processors/rollup_test.rb +50 -20
  41. data/test/resolve_test.rb +18 -9
  42. data/test/server_test.rb +15 -10
  43. data/test/templates/ejs_test.rb +2 -11
  44. data/test/templates/erb_test.rb +0 -5
  45. data/test/test_helper.rb +8 -3
  46. data/test/transformers/dart_scss_test.rb +139 -0
  47. data/test/transformers/jst_test.rb +165 -21
  48. data/test/transformers/scss_test.rb +14 -0
  49. data/test/transformers/svg_test.rb +40 -0
  50. metadata +23 -6
  51. data/lib/condenser/transformers/sass_transformer/importer.rb +0 -50
@@ -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
@@ -0,0 +1,2 @@
1
+ class Condenser::SVGTransformer::TemplateError < StandardError
2
+ end
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+
3
+ class Condenser::SVGTransformer::Value
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,10 @@
1
+ class Condenser::SVGTransformer::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,19 @@
1
+ class Condenser::SVGTransformer
2
+
3
+ autoload :Base, File.expand_path('../svg_transformer/base', __FILE__)
4
+ autoload :Tag, File.expand_path('../svg_transformer/tag', __FILE__)
5
+ autoload :Template, File.expand_path('../svg_transformer/template', __FILE__)
6
+ autoload :TemplateError, File.expand_path('../svg_transformer/template_error', __FILE__)
7
+ autoload :Value, File.expand_path('../svg_transformer/value', __FILE__)
8
+ autoload :VarGenerator, File.expand_path('../svg_transformer/var_generator', __FILE__)
9
+
10
+ def self.setup(env)
11
+ end
12
+
13
+ def self.call(environment, input)
14
+ input[:source] = Condenser::SVGTransformer::Template.new(input[:source]).to_module
15
+ end
16
+
17
+ end
18
+
19
+
@@ -1,3 +1,3 @@
1
1
  class Condenser
2
- VERSION = '1.2'
2
+ VERSION = '1.4'
3
3
  end
data/lib/condenser.rb CHANGED
@@ -19,19 +19,25 @@ class Condenser
19
19
  autoload :RollupProcessor, 'condenser/processors/rollup_processor'
20
20
  autoload :JSAnalyzer, 'condenser/processors/js_analyzer'
21
21
  autoload :PurgeCSSProcessor,'condenser/processors/purgecss_processor'
22
+ autoload :CSSMediaCombinerProcessor,'condenser/processors/css_media_combiner_processor'
22
23
  autoload :NodeProcessor, 'condenser/processors/node_processor'
23
24
  autoload :UglifyMinifier, 'condenser/minifiers/uglify_minifier'
24
25
  autoload :TerserMinifier, 'condenser/minifiers/terser_minifier'
25
26
  autoload :Erubi, 'condenser/templating_engine/erb'
27
+ autoload :Sass, 'condenser/transformers/sass'
26
28
  autoload :SassMinifier, 'condenser/minifiers/sass_minifier'
27
- autoload :SassTransformer, 'condenser/transformers/sass_transformer'
29
+ autoload :DartSassTransformer, 'condenser/transformers/dart_sass_transformer'
30
+ autoload :DartScssTransformer, 'condenser/transformers/dart_sass_transformer'
31
+ autoload :SassTransformer, 'condenser/transformers/sass_transformer'
28
32
  autoload :ScssTransformer, 'condenser/transformers/sass_transformer'
29
- autoload :EjsTemplare, 'condenser/templating_engine/ejs'
33
+ autoload :EjsTemplate, 'condenser/templating_engine/ejs'
30
34
  autoload :JstTransformer, 'condenser/transformers/jst_transformer'
35
+ autoload :SVGTransformer, 'condenser/transformers/svg_transformer'
31
36
  autoload :FileWriter, 'condenser/writers/file_writer'
32
37
  autoload :ZlibWriter, 'condenser/writers/zlib_writer'
33
38
  autoload :BrotliWriter, 'condenser/writers/brotli_writer'
34
39
  autoload :BuildCache, 'condenser/build_cache'
40
+ autoload :ParseHelpers, 'condenser/helpers/parse_helpers'
35
41
 
36
42
  def self.configure(&block)
37
43
  instance_eval(&block)
@@ -56,8 +62,8 @@ class Condenser
56
62
  configure(&block)
57
63
  elsif pipeline != false
58
64
  self.configure do
59
- # register_preprocessor 'application/javascript', Condenser::JSAnalyzer
60
- register_preprocessor 'application/javascript', Condenser::BabelProcessor
65
+ register_preprocessor 'application/javascript', Condenser::JSAnalyzer
66
+ # register_preprocessor 'application/javascript', Condenser::BabelProcessor
61
67
  register_exporter 'application/javascript', Condenser::RollupProcessor
62
68
  register_minifier 'application/javascript', Condenser::UglifyMinifier
63
69
 
@@ -132,6 +138,9 @@ Condenser.configure do
132
138
  # CSS
133
139
  register_mime_type 'text/css', extension: '.css', charset: :css
134
140
 
141
+ # PDF
142
+ register_mime_type 'application/pdf', extensions: %w(.pdf)
143
+
135
144
  # SASS
136
145
  register_mime_type 'text/sass', extensions: %w(.sass .css.sass)
137
146
  # register_transformer 'text/sass', 'text/css', SassProcessor
@@ -145,12 +154,15 @@ Condenser.configure do
145
154
 
146
155
  # EJS
147
156
  register_mime_type 'application/ejs', extensions: '.ejs', charset: :unicode
148
- register_template 'application/ejs', Condenser::EjsTemplare
157
+ register_template 'application/ejs', Condenser::EjsTemplate
149
158
 
150
159
  # JST
151
160
  register_mime_type 'application/jst', extensions: '.jst', charset: :unicode
152
161
  register_transformer 'application/jst', 'application/javascript', Condenser::JstTransformer
153
162
 
163
+ # SVG
164
+ register_transformer 'image/svg+xml', 'application/javascript', Condenser::SVGTransformer
165
+
154
166
  # Writers
155
167
  register_mime_type 'application/gzip', extensions: %w(.gz .gzip)
156
168
  register_mime_type 'application/brotli', extension: %w(.br)
data/test/cache_test.rb CHANGED
@@ -60,6 +60,19 @@ class CacheTest < ActiveSupport::TestCase
60
60
  CSS
61
61
  end
62
62
 
63
+ test 'changing a source file on calls needs_reprocessing! and needs_reexporting! once' do
64
+ file 'test.txt.erb', "1<%= 1 + 1 %>3\n"
65
+ assert_file 'test.txt', 'text/plain', <<~CSS
66
+ 123
67
+ CSS
68
+
69
+ asset = @env.find('test.txt')
70
+
71
+ asset.expects(:needs_reprocessing!).once
72
+ asset.expects(:needs_reexporting!).once
73
+ file 'test.txt.erb', "1<%= 1 + 2 %>5\n"
74
+ end
75
+
63
76
  test 'changing a js dependency reflects in the next call' do
64
77
  file 'main.js', <<-JS
65
78
  import { cube } from 'math';
@@ -74,11 +87,11 @@ class CacheTest < ActiveSupport::TestCase
74
87
  JS
75
88
 
76
89
  assert_exported_file 'main.js', 'application/javascript', <<~CSS
77
- !function(){"use strict";var o;console.log((o=5)*o)}();
90
+ !function(){var o;console.log((o=5)*o)}();
78
91
  CSS
79
92
 
80
93
  assert_exported_file 'main.js', 'application/javascript', <<~CSS
81
- !function(){"use strict";var o;console.log((o=5)*o)}();
94
+ !function(){var o;console.log((o=5)*o)}();
82
95
  CSS
83
96
 
84
97
  file 'math.js', <<-JS
@@ -88,7 +101,7 @@ class CacheTest < ActiveSupport::TestCase
88
101
  JS
89
102
 
90
103
  assert_exported_file 'main.js', 'application/javascript', <<~CSS
91
- !function(){"use strict";var o;console.log((o=5)*o*o)}();
104
+ !function(){var o;console.log((o=5)*o*o)}();
92
105
  CSS
93
106
  end
94
107
 
@@ -123,10 +136,10 @@ class CacheTest < ActiveSupport::TestCase
123
136
  JS
124
137
 
125
138
  assert_exported_file 'a.js', 'application/javascript', <<~JS
126
- !function(){"use strict";console.log(5)}();
139
+ console.log(5);
127
140
  JS
128
141
  assert_exported_file 'b.js', 'application/javascript', <<~JS
129
- !function(){"use strict";console.log(5)}();
142
+ console.log(5);
130
143
  JS
131
144
 
132
145
  file 'dep.js', <<-JS
@@ -134,15 +147,14 @@ class CacheTest < ActiveSupport::TestCase
134
147
  JS
135
148
 
136
149
  assert_exported_file 'a.js', 'application/javascript', <<~JS
137
- !function(){"use strict";console.log(10)}();
150
+ console.log(10);
138
151
  JS
139
152
  assert_exported_file 'b.js', 'application/javascript', <<~JS
140
- !function(){"use strict";console.log(10)}();
153
+ console.log(10);
141
154
  JS
142
-
143
155
  end
144
156
 
145
- test 'a dependency is supurceeded by a new file' do
157
+ test 'a dependency is superceeded by a new file' do
146
158
  Dir.mkdir(File.join(@path, 'a'))
147
159
  Dir.mkdir(File.join(@path, 'b'))
148
160
  @env.clear_path
@@ -158,7 +170,7 @@ class CacheTest < ActiveSupport::TestCase
158
170
  JS
159
171
 
160
172
  assert_exported_file 'a.js', 'application/javascript', <<~JS
161
- !function(){"use strict";console.log(5)}();
173
+ console.log(5);
162
174
  JS
163
175
 
164
176
  file 'a/dep.js', <<-JS
@@ -166,7 +178,7 @@ class CacheTest < ActiveSupport::TestCase
166
178
  JS
167
179
 
168
180
  assert_exported_file 'a.js', 'application/javascript', <<~JS
169
- !function(){"use strict";console.log(10)}();
181
+ console.log(10);
170
182
  JS
171
183
  end
172
184
 
@@ -186,7 +198,7 @@ class CacheTest < ActiveSupport::TestCase
186
198
  JS
187
199
 
188
200
  assert_exported_file 'a.js', 'application/javascript', <<~JS
189
- !function(){"use strict";console.log(5)}();
201
+ console.log(5);
190
202
  JS
191
203
 
192
204
  file 'a/deps/dep.js', <<-JS
@@ -194,7 +206,7 @@ class CacheTest < ActiveSupport::TestCase
194
206
  JS
195
207
 
196
208
  assert_exported_file 'a.js', 'application/javascript', <<~JS
197
- !function(){"use strict";console.log(10)}();
209
+ console.log(10);
198
210
  JS
199
211
 
200
212
  file 'a/deps/dep.js', <<-JS
@@ -202,7 +214,7 @@ class CacheTest < ActiveSupport::TestCase
202
214
  JS
203
215
 
204
216
  assert_exported_file 'a.js', 'application/javascript', <<~JS
205
- !function(){"use strict";console.log(20)}();
217
+ console.log(20);
206
218
  JS
207
219
  end
208
220
 
@@ -221,6 +233,21 @@ class CacheTest < ActiveSupport::TestCase
221
233
  CSS
222
234
  end
223
235
 
236
+ test '2a new dependency for a glob call is reflected in the next call' do
237
+ file "dir/a.svg", "<svg>test</svg>"
238
+ file 'test.scss', 'body { background: image-url("dir/a.svg") }'
239
+
240
+ assert_exported_file 'test.css', 'text/css', <<~CSS
241
+ body{background:url(/assets/dir/a-01a4bd3cb9faa518c5df2d2fcc8e6cd0ba24cfc3e9438dd01455ab1e59a39068.svg)}
242
+ CSS
243
+
244
+ file "dir/a.svg", "<svg>tests</svg>"
245
+
246
+ assert_exported_file 'test.css', 'text/css', <<~CSS
247
+ body{background:url(/assets/dir/a-1d7d038c7ace080963e116cbb962075a38d5e5dc68c6ff688e42d213dd432256.svg)}
248
+ CSS
249
+ end
250
+
224
251
  test 'a dependency is removed for a glob call when one of it dependencies is delted' do
225
252
  file "css/a.scss", "body { color: blue; }"
226
253
  file "css/b.scss", "body { color: green; }"
@@ -237,14 +264,14 @@ class CacheTest < ActiveSupport::TestCase
237
264
  CSS
238
265
  end
239
266
 
240
- test 'a dependency is added then changed should flush the parent' do
267
+ test 'a dependency is added then changed should flush the parent (JS)' do
241
268
  file 'a.js', "console.log('a');\n"
242
269
  file 'b.js', <<~JS
243
270
  export default function b () { console.log('b'); }
244
271
  JS
245
272
 
246
273
  assert_exported_file 'a.js', 'application/javascript', <<~JS
247
- !function(){"use strict";console.log("a")}();
274
+ console.log("a");
248
275
  JS
249
276
 
250
277
  file 'a.js', <<~JS
@@ -254,7 +281,7 @@ class CacheTest < ActiveSupport::TestCase
254
281
  JS
255
282
 
256
283
  assert_exported_file 'a.js', 'application/javascript', <<~JS
257
- !function(){"use strict";console.log("a"),console.log("b")}();
284
+ console.log("a"),console.log("b");
258
285
  JS
259
286
 
260
287
  file 'b.js', <<~JS
@@ -262,7 +289,119 @@ class CacheTest < ActiveSupport::TestCase
262
289
  JS
263
290
 
264
291
  assert_exported_file 'a.js', 'application/javascript', <<~JS
265
- !function(){"use strict";console.log("a"),console.log("c")}();
292
+ console.log("a"),console.log("c");
266
293
  JS
267
294
  end
295
+
296
+ test 'a dependency is added then changed should flush the parent (CSS)' do
297
+ file 'a.scss', "body { background: aqua; }"
298
+ file 'b.scss', <<~JS
299
+ body { background: blue; }
300
+ JS
301
+
302
+ assert_exported_file 'a.css', 'text/css', <<~JS
303
+ body{background:aqua}
304
+ JS
305
+
306
+ file 'a.scss', <<~JS
307
+ @import "b";
308
+ body { background: aqua; }
309
+ JS
310
+
311
+ assert_exported_file 'a.css', 'text/css', <<~JS
312
+ body{background:blue}body{background:aqua}
313
+ JS
314
+
315
+ file 'b.scss', <<~JS
316
+ body { background: green; }
317
+ JS
318
+
319
+ assert_exported_file 'a.css', 'text/css', <<~JS
320
+ body{background:green}body{background:aqua}
321
+ JS
322
+ end
323
+
324
+ test 'ensure the build cache only walks the dependency tree once' do
325
+ # a
326
+ # | |
327
+ # b c
328
+ # |
329
+ # d
330
+
331
+ file 'd.js', "export default function d () { console.log('d'); }\n"
332
+ file 'b.js', "export default function b () { console.log('b'); }\n"
333
+ file 'c.js', <<~JS
334
+ import d from 'd';
335
+
336
+ export default function c () { console.log('c'); d(); }
337
+ JS
338
+ file 'a.js', <<~JS
339
+ import b from 'b';
340
+ import c from 'c';
341
+
342
+ console.log('a'); b(); c();
343
+ JS
344
+
345
+ assert_exported_file 'a.js', 'application/javascript', <<~JS
346
+ console.log("a"),console.log("b"),console.log("c"),console.log("d");
347
+ JS
348
+
349
+ file 'd.js', "export default function e () { console.log('e'); }\n"
350
+
351
+ pd = @env.build_cache.instance_variable_get(:@process_dependencies)
352
+ pd["#{@path}/a.js"] ||= Set.new
353
+ pd["#{@path}/b.js"] ||= Set.new
354
+ pd["#{@path}/c.js"] ||= Set.new
355
+ pd["#{@path}/d.js"] ||= Set.new
356
+ pd["#{@path}/a.js"].expects(:<<).with { |a| a.source_file == "#{@path}/a.js" }.once
357
+ pd["#{@path}/b.js"].expects(:<<).with { |a| a.source_file == "#{@path}/b.js" }.never
358
+ pd["#{@path}/c.js"].expects(:<<).with { |a| a.source_file == "#{@path}/c.js" }.never
359
+ pd["#{@path}/d.js"].expects(:<<).with { |a| a.source_file == "#{@path}/d.js" }.once
360
+
361
+ assert_exported_file 'a.js', 'application/javascript', <<~JS
362
+ console.log("a"),console.log("b"),console.log("c"),console.log("e");
363
+ JS
364
+ end
365
+
366
+ test 'same files in diffrent dirs sharing a cache doesnt poison the cache (ie capistrano deploys)' do
367
+ cachepath = Dir.mktmpdir
368
+
369
+ dir = File.realpath(Dir.mktmpdir)
370
+ base1 = File.join(dir, 'a')
371
+ base2 = File.join(dir, 'b')
372
+ base3 = File.join(dir, 'c')
373
+ Dir.mkdir(base1)
374
+ Dir.mkdir(base2)
375
+
376
+ [base1, base2, base3].each do |b|
377
+ file 'test.js', "export default function c () { console.log('t'); }\n", base: b
378
+ file 'test/b.js', <<~JS, base: b
379
+ import c from './c';
380
+ export default function b () { console.log('b'); c(); }
381
+ JS
382
+ file 'test/a.js', <<~JS, base: b
383
+ import t from 'test';
384
+ import b from './b';
385
+
386
+ console.log('a');
387
+ b();
388
+ JS
389
+ end
390
+
391
+ file 'test/c.js', "export default function c () { console.log('c'); }\n", base: base1
392
+ file 'test/c.js', "export default function c () { console.log('d'); }\n", base: base2
393
+ file 'test/c.js', "export default function c () { console.log('e'); }\n", base: base3
394
+
395
+ # Set the cache
396
+ env1 = Condenser.new(base1, logger: Logger.new(STDOUT, level: :debug), base: base1, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
397
+ assert_equal 'console.log("a"),console.log("b"),console.log("c");', env1.find('test/a.js').export.source
398
+
399
+ # Poison the cache
400
+ env2 = Condenser.new(base2, logger: Logger.new(STDOUT, level: :debug), base: base2, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
401
+ assert_equal 'console.log("a"),console.log("b"),console.log("d");', env2.find('test/a.js').export.source
402
+
403
+ # Fails to find dependency change because cache is missing the dependency
404
+ env3 = Condenser.new(base3, logger: Logger.new(STDOUT, level: :debug), base: base3, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
405
+ assert_equal 'console.log("a"),console.log("b"),console.log("e");', env3.find('test/a.js').export.source
406
+ end
268
407
  end
@@ -17,7 +17,7 @@ class DependencyTest < ActiveSupport::TestCase
17
17
  JS
18
18
 
19
19
  asset = @env.find('name.js')
20
- assert_equal asset.instance_variable_get(:@process_dependencies), ["models/*.js","helpers/*.js"]
20
+ assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["models/*", ["application/javascript"]],["helpers/*", ["application/javascript"]]]
21
21
 
22
22
 
23
23
  assert_file 'name.js', 'application/javascript', <<~JS
@@ -54,7 +54,7 @@ class DependencyTest < ActiveSupport::TestCase
54
54
  JS
55
55
 
56
56
  asset = @env.find('name.js')
57
- assert_equal asset.instance_variable_get(:@process_dependencies), ["models/*.js","helpers/*.js"]
57
+ assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["models/*", ["application/javascript"]],["helpers/*", ["application/javascript"]]]
58
58
 
59
59
 
60
60
  assert_file 'name.js', 'application/javascript', <<~JS
@@ -74,4 +74,53 @@ class DependencyTest < ActiveSupport::TestCase
74
74
  JS
75
75
  end
76
76
 
77
+ test 'js depending on another file type with JSAnalzyer' do
78
+ @env.unregister_preprocessor 'application/javascript', Condenser::BabelProcessor
79
+ @env.register_preprocessor 'application/javascript', Condenser::JSAnalyzer
80
+ @env.unregister_minifier('application/javascript')
81
+
82
+ file 'a.js', ''
83
+ file 'b.rb', ''
84
+ file 'models/a.js', ''
85
+ file 'models/b.rb', ''
86
+
87
+ file 'name.js.erb', <<~JS
88
+ // depends_on **/*.rb
89
+
90
+ console.log([<%= Dir.children("#{@path}").sort.map(&:inspect).join(', ') %>]);
91
+ JS
92
+
93
+ asset = @env.find('name.js')
94
+ assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["**/*", ["application/ruby"]]]
95
+ assert_equal asset.process_dependencies.map(&:source_file), ["#{@path}/b.rb", "#{@path}/models/b.rb"]
96
+ end
97
+
98
+ test 'relative imports with JSAnalzyer' do
99
+ @env.unregister_preprocessor 'application/javascript', Condenser::BabelProcessor
100
+ @env.register_preprocessor 'application/javascript', Condenser::JSAnalyzer
101
+ @env.unregister_minifier('application/javascript')
102
+
103
+ file 'a/a.js', <<~JS
104
+ export decault function () { console.log("a/a"); }
105
+ JS
106
+ file 'b/a.js', <<~JS
107
+ export decault function () { console.log("a/a"); }
108
+ JS
109
+
110
+ file 'a/b.js', <<~JS
111
+ import fn from './a';
112
+ a();
113
+ console.log("a/b");
114
+ JS
115
+ file 'b/b.js', <<~JS
116
+ import fn from './a';
117
+ a();
118
+ console.log("b/b");
119
+ JS
120
+
121
+ asset = @env.find('a/b.js')
122
+ assert_equal asset.instance_variable_get(:@export_dependencies).to_a, [["#{@path}/a/a", ["application/javascript"]]]
123
+ assert_equal asset.export_dependencies.map(&:source_file), ["#{@path}/a/a.js"]
124
+ end
125
+
77
126
  end
@@ -66,6 +66,40 @@ class ManifestTest < ActiveSupport::TestCase
66
66
  assert_equal asset.path, data['application.js']['path']
67
67
  end
68
68
 
69
+ test "compile asset dependencies includes the dependencies" do
70
+ file 'foo.svg', <<-SVG
71
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
72
+ <path d="M6 18L18 6M6 6l12 12" />
73
+ </svg>
74
+ SVG
75
+
76
+ file 'test.scss', <<-SCSS
77
+ body {
78
+ background: asset-url("foo.svg");
79
+ }
80
+ SCSS
81
+
82
+ manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
83
+
84
+ main_digest_path = @env['test.css'].path
85
+ dep_digest_path = @env['foo.svg'].path
86
+
87
+ assert !File.exist?("#{@dir}/#{main_digest_path}")
88
+ assert !File.exist?("#{@dir}/#{dep_digest_path}")
89
+
90
+ manifest.compile('test.css')
91
+ assert File.directory?(manifest.dir)
92
+ assert File.file?(manifest.filename)
93
+
94
+ assert File.exist?("#{@dir}/manifest.json")
95
+ assert File.exist?("#{@dir}/#{main_digest_path}")
96
+ assert File.exist?("#{@dir}/#{dep_digest_path}")
97
+
98
+ data = JSON.parse(File.read(manifest.filename))
99
+ assert_equal main_digest_path, data['test.css']['path']
100
+ assert_equal dep_digest_path, data['foo.svg']['path']
101
+ end
102
+
69
103
  # TODO:
70
104
  # test "compile asset with aliased index links" do
71
105
  # manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
@@ -4,7 +4,6 @@ class TerserMinifierTest < ActiveSupport::TestCase
4
4
 
5
5
  def setup
6
6
  super
7
- @env.unregister_preprocessor('application/javascript', Condenser::BabelProcessor)
8
7
  @env.unregister_exporter('application/javascript', Condenser::RollupProcessor)
9
8
  @env.register_minifier('application/javascript', Condenser::TerserMinifier)
10
9
  end