condenser 1.2 → 1.4

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.
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