condenser 1.3 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52e335c087aab2b9bb3ef4540e54bfc5b8de0a888cab8f095c2f1dd778458bd4
4
- data.tar.gz: 566502264a1049f4ff5e33154caa56ef64ed74d14a8d72abd5e31628d59986c1
3
+ metadata.gz: 171baa1e5cd8016c4b2e7f142147d174410085ede075c101da43b743a4ad6fec
4
+ data.tar.gz: 9c97b58fb2bf540b335f6504997da99fac72891f61a0a0631639ae3fd9f28482
5
5
  SHA512:
6
- metadata.gz: 5c0fdf66cb6b17ff6a519af5205061f37e3af2f12896e45c2798154c46ba2db3dea57e219595b33e5433a82db17751bc8444453c5bc0371fb27013e97157352d
7
- data.tar.gz: 2486bd59e00c2d70ea683d2f69f1a71b0981b557144a08fd4965f9fe38a0c2da68d79e1c6fcba359718af3f9c26f4978619c3bb651f394cbb0db0172c450096f
6
+ metadata.gz: decc8b993d0e99c5212f3c0b1d4be88de43d49ab1386f32936a0dae482fc9b45de55cbbc51d99eafce58bcd68809a20fd27267ef0fe62d3aa3a244e33e68992e
7
+ data.tar.gz: e39a90c28c7beab789885e53e35ae0ad43340ff4009f81ad1586ac16eb0073dbaf999b69a94f78e796f5bfe5e93a16e0a45481e76b706d0e496dfbe5435b4966
@@ -65,33 +65,31 @@ class Condenser
65
65
  def process_dependencies
66
66
  deps = @environment.cache.fetch "direct-deps/#{cache_key}" do
67
67
  process
68
- @process_dependencies
68
+ @process_dependencies.map { |fn| [normalize_filename_base(fn[0]), fn[1]] }
69
69
  end
70
70
 
71
- d = []
72
- deps.each do |i|
73
- i = [i, @content_types] if i.is_a?(String)
71
+ deps.inject([]) do |memo, i|
72
+ i[0] = File.join(@environment.base, i[0].delete_prefix('!')) if i[0].start_with?('!') && @environment.base
74
73
  @environment.resolve(i[0], File.dirname(@source_file), accept: i[1]).each do |asset|
75
- d << asset
74
+ memo << asset
76
75
  end
76
+ memo
77
77
  end
78
- d
79
78
  end
80
79
 
81
80
  def export_dependencies
82
81
  deps = @environment.cache.fetch "export-deps/#{cache_key}" do
83
82
  process
84
- @export_dependencies + @process_dependencies
83
+ (@export_dependencies + @process_dependencies).map { |fn| [normalize_filename_base(fn[0]), fn[1]] }
85
84
  end
86
85
 
87
- d = []
88
- deps.each do |i|
89
- i = [i, @content_types] if i.is_a?(String)
86
+ deps.inject([]) do |memo, i|
87
+ i[0] = File.join(@environment.base, i[0].delete_prefix('!')) if i[0].start_with?('!') && @environment.base
90
88
  @environment.resolve(i[0], File.dirname(@source_file), accept: i[1]).each do |asset|
91
- d << asset
89
+ memo << asset
92
90
  end
91
+ memo
93
92
  end
94
- d
95
93
  end
96
94
 
97
95
  def has_default_export?
@@ -123,17 +121,27 @@ class Condenser
123
121
  end
124
122
  end
125
123
 
126
- def all_process_dependencies
127
- f = [@source_file]
128
- all_dependenies(process_dependencies, Set.new, :process_dependencies) do |dep|
124
+ def all_process_dependencies(visited = Set.new)
125
+ f = []
126
+ if !visited.include?(@source_file)
127
+ f << @source_file
128
+ visited << self.source_file
129
+ end
130
+
131
+ all_dependenies(process_dependencies, visited, :process_dependencies) do |dep|
129
132
  f << dep.source_file
130
133
  end
131
134
  f
132
135
  end
133
136
 
134
- def all_export_dependencies
135
- f = [@source_file]
136
- all_dependenies(export_dependencies, Set.new, :export_dependencies) do |dep|
137
+ def all_export_dependencies(visited = Set.new)
138
+ f = []
139
+ if !visited.include?(@source_file)
140
+ f << @source_file
141
+ visited << self.source_file
142
+ end
143
+
144
+ all_dependenies(export_dependencies, visited, :export_dependencies) do |dep|
137
145
  f << dep.source_file
138
146
  end
139
147
  f
@@ -143,19 +151,29 @@ class Condenser
143
151
  @cache_key ||= Digest::SHA1.base64digest(JSON.generate([
144
152
  Condenser::VERSION,
145
153
  @environment.pipline_digest,
146
- @environment.base ? @source_file.delete_prefix(@environment.base) : @source_file,
154
+ normalize_filename_base(@source_file),
147
155
  Digest::SHA256.file(@source_file).hexdigest,
148
156
  @content_types_digest
149
157
  ]))
150
158
  end
151
159
 
160
+ # Remove Enviroment base if it exists. This allows two of the same repos
161
+ # in a different location to use the same cache (like capistrano deploys)
162
+ def normalize_filename_base(source_filename)
163
+ if @environment.base && source_filename.start_with?(@environment.base)
164
+ '!'+source_filename.delete_prefix(@environment.base).delete_prefix(File::SEPARATOR)
165
+ else
166
+ source_filename
167
+ end
168
+ end
169
+
152
170
  def process_cache_version
153
171
  return @pcv if @pcv
154
172
 
155
173
  f = []
156
174
  all_dependenies(process_dependencies, Set.new, :process_dependencies) do |dep|
157
175
  f << [
158
- @environment.base ? dep.source_file.delete_prefix(@environment.base) : dep.source_file,
176
+ normalize_filename_base(dep.source_file),
159
177
  Digest::SHA256.file(dep.source_file).hexdigest
160
178
  ]
161
179
  end
@@ -169,7 +187,7 @@ class Condenser
169
187
  f = []
170
188
  all_dependenies(export_dependencies, Set.new, :export_dependencies) do |dep|
171
189
  f << [
172
- @environment.base ? dep.source_file.delete_prefix(@environment.base) : dep.source_file,
190
+ normalize_filename_base(dep.source_file),
173
191
  Digest::SHA256.file(dep.source_file).hexdigest
174
192
  ]
175
193
  end
@@ -276,6 +294,8 @@ class Condenser
276
294
 
277
295
  data[:digest] = @environment.digestor.digest(data[:source])
278
296
  data[:digest_name] = @environment.digestor.name.sub(/^.*::/, '').downcase
297
+ data[:process_dependencies] = normialize_dependency_names(data[:process_dependencies])
298
+ data[:export_dependencies] = normialize_dependency_names(data[:export_dependencies])
279
299
 
280
300
  # Do this here and at the end so cache_key can be calculated if we
281
301
  # run this block
@@ -314,6 +334,17 @@ class Condenser
314
334
  @processed = true
315
335
  end
316
336
 
337
+ def normialize_dependency_names(deps)
338
+ deps.map do |fn|
339
+ if fn.is_a?(String)
340
+ dirname, basename, extensions, mime_types = @environment.decompose_path(fn, source_file)
341
+ [dirname ? File.join(dirname, basename) : basename, mime_types.empty? ? @content_types : mime_types]
342
+ else
343
+ fn
344
+ end
345
+ end
346
+ end
347
+
317
348
  def export
318
349
  return @export if @export
319
350
 
@@ -22,6 +22,10 @@ class Condenser
22
22
  else
23
23
  @semaphore = Mutex.new
24
24
  @listener = Listen.to(*path) do |modified, added, removed|
25
+ modified = Set.new(modified)
26
+ added = Set.new(added)
27
+ removed = Set.new(removed)
28
+
25
29
  @semaphore.synchronize do
26
30
  @logger.debug { "build cache semaphore locked by #{Thread.current.object_id}" }
27
31
  @logger.debug do
@@ -122,16 +126,25 @@ class Condenser
122
126
 
123
127
  def []=(value, assets)
124
128
  @lookup_cache[value] = assets
129
+
130
+ if @fetching.nil?
131
+ begin
132
+ assets.each do |asset|
133
+ @fetching = Set.new
134
+ asset.all_process_dependencies(@fetching).each do |pd|
135
+ @process_dependencies[pd] ||= Set.new
136
+ @process_dependencies[pd] << asset
137
+ end
125
138
 
126
- assets.each do |asset|
127
- asset.all_process_dependencies.each do |pd|
128
- @process_dependencies[pd] ||= Set.new
129
- @process_dependencies[pd] << asset
130
- end
139
+ @fetching = Set.new
140
+ asset.all_export_dependencies(@fetching).each do |pd|
141
+ @export_dependencies[pd] ||= Set.new
131
142
 
132
- asset.all_export_dependencies.each do |pd|
133
- @export_dependencies[pd] ||= Set.new
134
- @export_dependencies[pd] << asset
143
+ @export_dependencies[pd] << asset
144
+ end
145
+ end
146
+ ensure
147
+ @fetching = nil
135
148
  end
136
149
  end
137
150
  end
@@ -55,4 +55,11 @@ module Condenser::ParseHelpers
55
55
  "#{lineno.to_s.rjust(4)}: " + @source[start..uptop] + "\n #{'-'* (@index-1-start)}#{'^'*(@matched.length)}"
56
56
  end
57
57
 
58
+ def gobble(r)
59
+ m = @source.match(r, @index)
60
+ if m&.begin(0) == @index
61
+ scan_until(r)
62
+ end
63
+ end
64
+
58
65
  end
@@ -95,23 +95,17 @@ class Condenser::BabelProcessor < Condenser::NodeProcessor
95
95
  ImportDeclaration(path, state) {
96
96
  imports.push(path.node.source.value);
97
97
  },
98
- ExportDefaultDeclaration(path, state) {
98
+
99
+ ExportDeclaration(path, state) {
99
100
  hasExports = true;
100
- defaultExport = true;
101
+ if (path.node.source) {
102
+ imports.push(path.node.source.value);
103
+ }
101
104
  },
102
- ExportDefaultSpecifier(path, state) {
103
- hasExports = true;
105
+
106
+ ExportDefaultDeclaration(path, state) {
104
107
  defaultExport = true;
105
- },
106
- ExportAllDeclaration(path, state) {
107
- hasExports = true;
108
- },
109
- ExportNamedDeclaration(path, state) {
110
- hasExports = true;
111
- },
112
- ExportSpecifier(path, state) {
113
- hasExports = true;
114
- },
108
+ }
115
109
  }
116
110
  };
117
111
  });
@@ -15,7 +15,7 @@ class Condenser::JSAnalyzer
15
15
  @source = input[:source]
16
16
  @stack = [:main]
17
17
 
18
- input[:export_dependencies] ||= []
18
+ input[:export_dependencies] ||= Set.new
19
19
 
20
20
  scan_until(/\A(\/\/[^\n]*(\n|\z))*/)
21
21
  if matched
@@ -28,6 +28,7 @@ class Condenser::JSAnalyzer
28
28
  end
29
29
 
30
30
  last_postion = nil
31
+ last_stack = nil
31
32
  while !eos?
32
33
  case @stack.last
33
34
 
@@ -53,6 +54,32 @@ class Condenser::JSAnalyzer
53
54
  scan_until(/(;|\n)/)
54
55
  @stack.pop
55
56
 
57
+ when :export
58
+ input[:exports] = true;
59
+ input[:default_export] = true if gobble(/\s+default/)
60
+ gobble(/\s+/)
61
+
62
+ if gobble(/\{/)
63
+ @stack << :brackets
64
+ elsif gobble(/\*/)
65
+ @stack << :export_from
66
+ else
67
+ @stack.pop
68
+ end
69
+
70
+ when :export_from
71
+ if gobble(/\s+from\s+/)
72
+ scan_until(/\"|\'/)
73
+ input[:export_dependencies] << case matched
74
+ when '"'
75
+ double_quoted_value
76
+ when "'"
77
+ single_quoted_value
78
+ end
79
+ end
80
+ @stack.pop
81
+ @stack.pop
82
+
56
83
  else
57
84
  scan_until(/(\/\/|\/\*|\/|\(|\)|\{|\}|\"|\'|\`|export|import|\z)/)
58
85
 
@@ -85,15 +112,17 @@ class Condenser::JSAnalyzer
85
112
  @stack.push :brackets
86
113
  when '}'
87
114
  case @stack.last
88
- when :brackets, :tick_statment
115
+ when :tick_statment
116
+ @stack.pop
117
+ when :brackets
89
118
  @stack.pop
119
+ @stack << :export_from if @stack.last == :export
90
120
  else
91
121
  raise unexptected_token("}")
92
122
  end
93
123
  when 'export'
94
124
  if @stack.last == :main
95
- input[:exports] = true;
96
- input[:default_export] = true if next_word == 'default'
125
+ @stack << :export
97
126
  end
98
127
  when 'import'
99
128
  if @stack.last == :main
@@ -104,10 +133,13 @@ class Condenser::JSAnalyzer
104
133
  end
105
134
  end
106
135
 
107
- if last_postion == @index
136
+ if last_postion == @index && last_stack == @stack.last
137
+ syntax_error = Condenser::SyntaxError.new("Error parsing JS file with JSAnalyzer")
138
+ syntax_error.instance_variable_set(:@path, @sourcefile)
108
139
  raise Condenser::SyntaxError, "Error parsing JS file with JSAnalyzer"
109
140
  else
110
141
  last_postion = @index
142
+ last_stack = @stack.last
111
143
  end
112
144
  end
113
145
  end
@@ -121,7 +153,10 @@ class Condenser::JSAnalyzer
121
153
  message << "\n#{lineno.to_s.rjust(4)}: " << @source[start..uptop]
122
154
  message << "\n #{'-'* (@index-1-start)}#{'^'*(@matched.length)}"
123
155
  message << "\n"
124
- Condenser::SyntaxError.new(message)
156
+
157
+ syntax_error = Condenser::SyntaxError.new(message)
158
+ syntax_error.instance_variable_set(:@path, @sourcefile)
159
+ syntax_error
125
160
  end
126
161
 
127
162
  def double_quoted_value
@@ -60,6 +60,7 @@ class Condenser
60
60
  lineno = lines[0][/\((\d+):\d+\)$/, 1] if lines[0]
61
61
  lineno ||= 1
62
62
  error.set_backtrace(["#{source_file}:#{lineno}"] + caller)
63
+ error.instance_variable_set(:@path, source_file)
63
64
  error
64
65
  end
65
66
 
@@ -214,7 +214,7 @@ class Condenser::RollupProcessor < Condenser::NodeProcessor
214
214
  elsif importee.end_with?('*')
215
215
  File.join(File.dirname(importee), '*')
216
216
  else
217
- @environment.find(importee, importer ? File.dirname(@entry == importer ? @input[:source_file] : importer) : nil, accept: @input[:content_types].last)&.source_file
217
+ @environment.find(importee, importer ? (@entry == importer ? @input[:source_file] : importer) : nil, accept: @input[:content_types].last)&.source_file
218
218
  end
219
219
  when 'load'
220
220
  importee = message['args'].first
@@ -148,11 +148,34 @@ class Condenser
148
148
  end
149
149
  end
150
150
 
151
+ def has_dir?(path)
152
+ path.count('/') > (path.start_with?('/') ? 1 : 0)
153
+ end
154
+
155
+ def expand_path(path)
156
+ dir = if path.start_with?('/')
157
+ File.expand_path(path)
158
+ else
159
+ File.expand_path("/#{path}").delete_prefix('/')
160
+ end
161
+ dir.empty? ? nil : dir
162
+ end
163
+
151
164
  def decompose_path(path, base=nil)
152
- dirname = path.index('/') ? File.dirname(path) : nil
153
- if base && path&.start_with?('.')
154
- dirname = File.expand_path(dirname, base)
165
+ dirname = if base && path.start_with?('.')
166
+ if has_dir?(base)
167
+ if has_dir?(path)
168
+ expand_path(File.join(File.dirname(base), File.dirname(path)))
169
+ else
170
+ expand_path(File.dirname(base))
171
+ end
172
+ else
173
+ expand_path(File.dirname(path))
174
+ end
175
+ else
176
+ path.index('/') ? File.dirname(path) : nil
155
177
  end
178
+
156
179
 
157
180
  _, star, basename, extensions = path.match(/(([^\.\/]+)(\.[^\/]+)|\*|[^\/]+)$/).to_a
158
181
  if extensions == '.*'
@@ -1,3 +1,3 @@
1
1
  class Condenser
2
- VERSION = '1.3'
2
+ VERSION = '1.4'
3
3
  end
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,12 +147,11 @@ 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
157
  test 'a dependency is superceeded by a new file' do
@@ -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
 
@@ -259,7 +271,7 @@ class CacheTest < ActiveSupport::TestCase
259
271
  JS
260
272
 
261
273
  assert_exported_file 'a.js', 'application/javascript', <<~JS
262
- !function(){"use strict";console.log("a")}();
274
+ console.log("a");
263
275
  JS
264
276
 
265
277
  file 'a.js', <<~JS
@@ -269,7 +281,7 @@ class CacheTest < ActiveSupport::TestCase
269
281
  JS
270
282
 
271
283
  assert_exported_file 'a.js', 'application/javascript', <<~JS
272
- !function(){"use strict";console.log("a"),console.log("b")}();
284
+ console.log("a"),console.log("b");
273
285
  JS
274
286
 
275
287
  file 'b.js', <<~JS
@@ -277,7 +289,7 @@ class CacheTest < ActiveSupport::TestCase
277
289
  JS
278
290
 
279
291
  assert_exported_file 'a.js', 'application/javascript', <<~JS
280
- !function(){"use strict";console.log("a"),console.log("c")}();
292
+ console.log("a"),console.log("c");
281
293
  JS
282
294
  end
283
295
 
@@ -308,5 +320,88 @@ class CacheTest < ActiveSupport::TestCase
308
320
  body{background:green}body{background:aqua}
309
321
  JS
310
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
311
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
312
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).to_a, ["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).to_a, ["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
@@ -28,6 +28,28 @@ class CondenserBabelTest < ActiveSupport::TestCase
28
28
  JS
29
29
  end
30
30
 
31
+ test "dependency tracking for a export from" do
32
+ file 'c.js', <<~JS
33
+ function c() { return 'ok'; }
34
+
35
+ export {c}
36
+ JS
37
+
38
+ file 'b.js', <<~JS
39
+ export {c} from 'c';
40
+
41
+ JS
42
+
43
+ file 'a.js', <<~JS
44
+ import {c} from 'b'
45
+
46
+ console.log(c());
47
+ JS
48
+
49
+ asset = assert_file 'a.js', 'application/javascript'
50
+ assert_equal ['/a.js', '/b.js', '/c.js'], asset.all_export_dependencies.map { |path| path.delete_prefix(@path) }
51
+ end
52
+
31
53
  test "error" do
32
54
  file 'error.js', <<~JS
33
55
  console.log('this file has an error');
@@ -47,6 +69,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
47
69
  | ^
48
70
  4 |
49
71
  ERROR
72
+ assert_equal '/assets/error.js', e.path
50
73
  end
51
74
 
52
75
  test 'not duplicating polyfills' do
@@ -83,7 +106,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
83
106
  };
84
107
 
85
108
  // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
86
- var global$9 =
109
+ var global$8 =
87
110
  // eslint-disable-next-line es/no-global-this -- safe
88
111
  check(typeof globalThis == 'object' && globalThis) ||
89
112
  check(typeof window == 'object' && window) ||
@@ -153,25 +176,14 @@ class CondenserBabelTest < ActiveSupport::TestCase
153
176
  if (classofRaw(fn) === 'Function') return uncurryThis$8(fn);
154
177
  };
155
178
 
156
- var documentAll$2 = typeof document == 'object' && document.all;
157
-
158
179
  // https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot
159
- // eslint-disable-next-line unicorn/no-typeof-undefined -- required for testing
160
- var IS_HTMLDDA = typeof documentAll$2 == 'undefined' && documentAll$2 !== undefined;
161
-
162
- var documentAll_1 = {
163
- all: documentAll$2,
164
- IS_HTMLDDA: IS_HTMLDDA
165
- };
166
-
167
- var $documentAll$1 = documentAll_1;
168
-
169
- var documentAll$1 = $documentAll$1.all;
180
+ var documentAll = typeof document == 'object' && document.all;
170
181
 
171
182
  // `IsCallable` abstract operation
172
183
  // https://tc39.es/ecma262/#sec-iscallable
173
- var isCallable$7 = $documentAll$1.IS_HTMLDDA ? function (argument) {
174
- return typeof argument == 'function' || argument === documentAll$1;
184
+ // eslint-disable-next-line unicorn/no-typeof-undefined -- required for testing
185
+ var isCallable$7 = typeof documentAll == 'undefined' && documentAll !== undefined ? function (argument) {
186
+ return typeof argument == 'function' || argument === documentAll;
175
187
  } : function (argument) {
176
188
  return typeof argument == 'function';
177
189
  };
@@ -261,20 +273,15 @@ class CondenserBabelTest < ActiveSupport::TestCase
261
273
  };
262
274
 
263
275
  var isCallable$6 = isCallable$7;
264
- var $documentAll = documentAll_1;
265
-
266
- var documentAll = $documentAll.all;
267
276
 
268
- var isObject$4 = $documentAll.IS_HTMLDDA ? function (it) {
269
- return typeof it == 'object' ? it !== null : isCallable$6(it) || it === documentAll;
270
- } : function (it) {
277
+ var isObject$4 = function (it) {
271
278
  return typeof it == 'object' ? it !== null : isCallable$6(it);
272
279
  };
273
280
 
274
281
  var path$3 = {};
275
282
 
276
283
  var path$2 = path$3;
277
- var global$8 = global$9;
284
+ var global$7 = global$8;
278
285
  var isCallable$5 = isCallable$7;
279
286
 
280
287
  var aFunction = function (variable) {
@@ -282,8 +289,8 @@ class CondenserBabelTest < ActiveSupport::TestCase
282
289
  };
283
290
 
284
291
  var getBuiltIn$1 = function (namespace, method) {
285
- return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(global$8[namespace])
286
- : path$2[namespace] && path$2[namespace][method] || global$8[namespace] && global$8[namespace][method];
292
+ return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(global$7[namespace])
293
+ : path$2[namespace] && path$2[namespace][method] || global$7[namespace] && global$7[namespace][method];
287
294
  };
288
295
 
289
296
  var uncurryThis$6 = functionUncurryThis;
@@ -292,11 +299,11 @@ class CondenserBabelTest < ActiveSupport::TestCase
292
299
 
293
300
  var engineUserAgent = typeof navigator != 'undefined' && String(navigator.userAgent) || '';
294
301
 
295
- var global$7 = global$9;
302
+ var global$6 = global$8;
296
303
  var userAgent = engineUserAgent;
297
304
 
298
- var process = global$7.process;
299
- var Deno = global$7.Deno;
305
+ var process = global$6.process;
306
+ var Deno = global$6.Deno;
300
307
  var versions = process && process.versions || Deno && Deno.version;
301
308
  var v8 = versions && versions.v8;
302
309
  var match, version;
@@ -323,9 +330,9 @@ class CondenserBabelTest < ActiveSupport::TestCase
323
330
  /* eslint-disable es/no-symbol -- required for testing */
324
331
  var V8_VERSION = engineV8Version;
325
332
  var fails$4 = fails$8;
326
- var global$6 = global$9;
333
+ var global$5 = global$8;
327
334
 
328
- var $String$2 = global$6.String;
335
+ var $String$2 = global$5.String;
329
336
 
330
337
  // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
331
338
  var symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$4(function () {
@@ -407,42 +414,42 @@ class CondenserBabelTest < ActiveSupport::TestCase
407
414
  throw new $TypeError$3("Can't convert object to primitive value");
408
415
  };
409
416
 
410
- var shared$1 = {exports: {}};
417
+ var sharedStore = {exports: {}};
411
418
 
412
- var global$5 = global$9;
419
+ var global$4 = global$8;
413
420
 
414
421
  // eslint-disable-next-line es/no-object-defineproperty -- safe
415
422
  var defineProperty$1 = Object.defineProperty;
416
423
 
417
424
  var defineGlobalProperty$1 = function (key, value) {
418
425
  try {
419
- defineProperty$1(global$5, key, { value: value, configurable: true, writable: true });
426
+ defineProperty$1(global$4, key, { value: value, configurable: true, writable: true });
420
427
  } catch (error) {
421
- global$5[key] = value;
428
+ global$4[key] = value;
422
429
  } return value;
423
430
  };
424
431
 
425
- var global$4 = global$9;
432
+ var globalThis$1 = global$8;
426
433
  var defineGlobalProperty = defineGlobalProperty$1;
427
434
 
428
435
  var SHARED = '__core-js_shared__';
429
- var store$1 = global$4[SHARED] || defineGlobalProperty(SHARED, {});
436
+ var store$1 = sharedStore.exports = globalThis$1[SHARED] || defineGlobalProperty(SHARED, {});
430
437
 
431
- var sharedStore = store$1;
432
-
433
- var store = sharedStore;
434
-
435
- (shared$1.exports = function (key, value) {
436
- return store[key] || (store[key] = value !== undefined ? value : {});
437
- })('versions', []).push({
438
- version: '3.34.0',
438
+ (store$1.versions || (store$1.versions = [])).push({
439
+ version: '3.37.1',
439
440
  mode: 'pure' ,
440
- copyright: '© 2014-2023 Denis Pushkarev (zloirock.ru)',
441
- license: 'https://github.com/zloirock/core-js/blob/v3.34.0/LICENSE',
441
+ copyright: '© 2014-2024 Denis Pushkarev (zloirock.ru)',
442
+ license: 'https://github.com/zloirock/core-js/blob/v3.37.1/LICENSE',
442
443
  source: 'https://github.com/zloirock/core-js'
443
444
  });
444
445
 
445
- var sharedExports = shared$1.exports;
446
+ var sharedStoreExports = sharedStore.exports;
447
+
448
+ var store = sharedStoreExports;
449
+
450
+ var shared$1 = function (key, value) {
451
+ return store[key] || (store[key] = value || {});
452
+ };
446
453
 
447
454
  var requireObjectCoercible = requireObjectCoercible$2;
448
455
 
@@ -476,8 +483,8 @@ class CondenserBabelTest < ActiveSupport::TestCase
476
483
  return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);
477
484
  };
478
485
 
479
- var global$3 = global$9;
480
- var shared = sharedExports;
486
+ var global$3 = global$8;
487
+ var shared = shared$1;
481
488
  var hasOwn$3 = hasOwnProperty_1;
482
489
  var uid = uid$1;
483
490
  var NATIVE_SYMBOL = symbolConstructorDetection;
@@ -531,7 +538,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
531
538
  return isSymbol(key) ? key : key + '';
532
539
  };
533
540
 
534
- var global$2 = global$9;
541
+ var global$2 = global$8;
535
542
  var isObject$1 = isObject$4;
536
543
 
537
544
  var document$1 = global$2.document;
@@ -695,7 +702,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
695
702
  return object;
696
703
  };
697
704
 
698
- var global$1 = global$9;
705
+ var global$1 = global$8;
699
706
  var apply = functionApply;
700
707
  var uncurryThis$2 = functionUncurryThisClause;
701
708
  var isCallable = isCallable$7;
@@ -705,6 +712,8 @@ class CondenserBabelTest < ActiveSupport::TestCase
705
712
  var bind = functionBindContext;
706
713
  var createNonEnumerableProperty = createNonEnumerableProperty$1;
707
714
  var hasOwn$1 = hasOwnProperty_1;
715
+ // add debugging info
716
+
708
717
 
709
718
  var wrapConstructor = function (NativeConstructor) {
710
719
  var Wrapper = function (a, b, c) {
@@ -741,7 +750,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
741
750
  var STATIC = options.stat;
742
751
  var PROTO = options.proto;
743
752
 
744
- var nativeSource = GLOBAL ? global$1 : STATIC ? global$1[TARGET] : (global$1[TARGET] || {}).prototype;
753
+ var nativeSource = GLOBAL ? global$1 : STATIC ? global$1[TARGET] : global$1[TARGET] && global$1[TARGET].prototype;
745
754
 
746
755
  var target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET];
747
756
  var targetPrototype = target.prototype;
@@ -764,7 +773,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
764
773
  // export native or implementation
765
774
  sourceProperty = (USE_NATIVE && nativeProperty) ? nativeProperty : source[key];
766
775
 
767
- if (USE_NATIVE && typeof targetProperty == typeof sourceProperty) continue;
776
+ if (!FORCED && !PROTO && typeof targetProperty == typeof sourceProperty) continue;
768
777
 
769
778
  // bind methods to global for calling from export context
770
779
  if (options.bind && USE_NATIVE) resultProperty = bind(sourceProperty, global$1);
@@ -838,7 +847,8 @@ class CondenserBabelTest < ActiveSupport::TestCase
838
847
  // `ToLength` abstract operation
839
848
  // https://tc39.es/ecma262/#sec-tolength
840
849
  var toLength$1 = function (argument) {
841
- return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
850
+ var len = toIntegerOrInfinity(argument);
851
+ return len > 0 ? min(len, 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
842
852
  };
843
853
 
844
854
  var toLength = toLength$1;
@@ -858,6 +868,7 @@ class CondenserBabelTest < ActiveSupport::TestCase
858
868
  return function ($this, el, fromIndex) {
859
869
  var O = toIndexedObject$1($this);
860
870
  var length = lengthOfArrayLike(O);
871
+ if (length === 0) return !IS_INCLUDES && -1;
861
872
  var index = toAbsoluteIndex(fromIndex, length);
862
873
  var value;
863
874
  // Array#includes uses SameValueZero equality algorithm
@@ -248,4 +248,39 @@ class JSAnalyzerTest < ActiveSupport::TestCase
248
248
  assert_equal ['a.js', 'b.js'], asset.export_dependencies.map(&:filename)
249
249
  end
250
250
 
251
+ test "dependency tracking for a export from" do
252
+ file 'c.js', <<~JS
253
+ function c() { return 'ok'; }
254
+
255
+ export {c}
256
+ JS
257
+
258
+ file 'b.js', <<~JS
259
+ export {c} from 'c';
260
+
261
+ JS
262
+
263
+ file 'a.js', <<~JS
264
+ import {c} from 'b'
265
+
266
+ console.log(c());
267
+ JS
268
+
269
+ asset = assert_file 'a.js', 'application/javascript'
270
+ assert_equal ['/a.js', '/b.js', '/c.js'], asset.all_export_dependencies.map { |path| path.delete_prefix(@path) }
271
+ end
272
+
273
+ test 'exporting a nested object' do
274
+ file 't.js', <<~JS
275
+ export default {
276
+ registry: {
277
+ boolean: true,
278
+ integer: 1
279
+ }
280
+ };
281
+ JS
282
+
283
+ asset = assert_file 't.js', 'application/javascript'
284
+ end
285
+
251
286
  end
data/test/resolve_test.rb CHANGED
@@ -35,6 +35,16 @@ class ResolveTest < ActiveSupport::TestCase
35
35
  assert_equal ['test', '*', ['.js'], ['application/javascript']], @env.decompose_path('test/*.js')
36
36
  assert_equal ['test/*', '*', ['.js'], ['application/javascript']], @env.decompose_path('test/*/*.js')
37
37
  assert_equal ['test/**', '*', ['.js'], ['application/javascript']], @env.decompose_path('test/**/*.js')
38
+
39
+ assert_equal ['a', 'test', ['.js'], ['application/javascript']], @env.decompose_path('./test.js', 'a/b.js')
40
+ assert_equal [nil, 'test', ['.js'], ['application/javascript']], @env.decompose_path('./test.js', 'b.js')
41
+ assert_equal ['a/folder', 'test', ['.js'], ['application/javascript']], @env.decompose_path('./folder/test.js', 'a/b.js')
42
+ assert_equal ['folder', 'test', ['.js'], ['application/javascript']], @env.decompose_path('./folder/test.js', 'b.js')
43
+
44
+ assert_equal [nil, 'test', ['.js'], ['application/javascript']], @env.decompose_path('../test.js', 'a/b.js')
45
+ assert_equal ["/", 'test', ['.js'], ['application/javascript']], @env.decompose_path('../test.js', '/a/b.js')
46
+ assert_equal ["folder", 'test', ['.js'], ['application/javascript']], @env.decompose_path('../folder/test.js', 'a/b.js')
47
+ assert_equal ["/folder", 'test', ['.js'], ['application/javascript']], @env.decompose_path('../folder/test.js', '/a/b.js')
38
48
  end
39
49
 
40
50
  test 'resolve' do
data/test/server_test.rb CHANGED
@@ -27,10 +27,10 @@ class ServerTest < ActiveSupport::TestCase
27
27
  test "serve single source file" do
28
28
  get "/assets/foo.js"
29
29
  assert_equal 200, last_response.status
30
- assert_equal "43", last_response.headers['Content-Length']
30
+ assert_equal "15", last_response.headers['Content-Length']
31
31
  assert_equal "Accept-Encoding", last_response.headers['Vary']
32
32
  assert_equal <<~JS.strip, last_response.body
33
- !function(){"use strict";console.log(1)}();
33
+ console.log(1);
34
34
  JS
35
35
  end
36
36
 
@@ -54,7 +54,7 @@ class ServerTest < ActiveSupport::TestCase
54
54
 
55
55
  get "/assets/main.js"
56
56
  assert_equal <<~JS.strip, last_response.body
57
- !function(){"use strict";var o;console.log((o=5)*o*o)}();
57
+ !function(){var o;console.log((o=5)*o*o)}();
58
58
  JS
59
59
  end
60
60
 
@@ -73,7 +73,7 @@ class ServerTest < ActiveSupport::TestCase
73
73
  test "serve source with etag headers" do
74
74
  get "/assets/foo.js"
75
75
 
76
- digest = '9001f422e9c91516f6e130be56dd77aa313c52bb7dd18e4bb085067162c9fa70'
76
+ digest = '35c146f76e129477c64061bc84511e1090f3d4d8059713e6663dd4b35b1f7642'
77
77
  assert_equal "\"#{digest}\"", last_response.headers['ETag']
78
78
  end
79
79
 
@@ -107,8 +107,8 @@ class ServerTest < ActiveSupport::TestCase
107
107
  'HTTP_IF_NONE_MATCH' => "nope"
108
108
 
109
109
  assert_equal 200, last_response.status
110
- assert_equal '"9001f422e9c91516f6e130be56dd77aa313c52bb7dd18e4bb085067162c9fa70"', last_response.headers['ETag']
111
- assert_equal '43', last_response.headers['Content-Length']
110
+ assert_equal '"35c146f76e129477c64061bc84511e1090f3d4d8059713e6663dd4b35b1f7642"', last_response.headers['ETag']
111
+ assert_equal '15', last_response.headers['Content-Length']
112
112
  end
113
113
 
114
114
  test "not modified partial response with fingerprint and if-none-match etags match" do
@@ -167,8 +167,8 @@ class ServerTest < ActiveSupport::TestCase
167
167
  'HTTP_IF_MATCH' => etag
168
168
 
169
169
  assert_equal 200, last_response.status
170
- assert_equal '"9001f422e9c91516f6e130be56dd77aa313c52bb7dd18e4bb085067162c9fa70"', last_response.headers['ETag']
171
- assert_equal '43', last_response.headers['Content-Length']
170
+ assert_equal '"35c146f76e129477c64061bc84511e1090f3d4d8059713e6663dd4b35b1f7642"', last_response.headers['ETag']
171
+ assert_equal '15', last_response.headers['Content-Length']
172
172
  end
173
173
 
174
174
  test "precondition failed with if-match is a mismatch" do
@@ -253,7 +253,7 @@ class ServerTest < ActiveSupport::TestCase
253
253
  JS
254
254
  get "/assets/%E6%97%A5%E6%9C%AC%E8%AA%9E.js"
255
255
  assert_equal <<~JS.strip, last_response.body
256
- !function(){"use strict";console.log("日本語")}();
256
+ console.log("日本語");
257
257
  JS
258
258
  end
259
259
 
data/test/test_helper.rb CHANGED
@@ -53,9 +53,10 @@ class ActiveSupport::TestCase
53
53
  assert_equal json, jbuild(&block)
54
54
  end
55
55
 
56
- def file(name, source)
57
- dir = name.include?('/') ? File.join(@path, File.dirname(name)) : @path
58
- path = File.join(@path, name)
56
+ def file(name, source, base: nil)
57
+ base ||= @path
58
+ dir = name.include?('/') ? File.join(base, File.dirname(name)) : base
59
+ path = File.join(base, name)
59
60
 
60
61
  FileUtils.mkdir_p(dir)
61
62
  if File.exist?(path)
@@ -78,6 +79,7 @@ class ActiveSupport::TestCase
78
79
  assert_equal path.delete_prefix('/'), asset.filename
79
80
  assert_equal Array(mime_types), asset.content_types
80
81
  assert_equal(source.rstrip, asset.source.rstrip) if !source.nil?
82
+ asset
81
83
  end
82
84
 
83
85
  def assert_exported_file(path, mime_types, source=nil)
@@ -88,6 +90,7 @@ class ActiveSupport::TestCase
88
90
  assert_equal path, asset.filename
89
91
  assert_equal Array(mime_types), asset.content_types
90
92
  assert_equal(source.rstrip, asset.source.rstrip) if !source.nil?
93
+ asset
91
94
  end
92
95
 
93
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: condenser
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.3'
4
+ version: '1.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-06 00:00:00.000000000 Z
11
+ date: 2024-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erubi
@@ -398,7 +398,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
398
398
  - !ruby/object:Gem::Version
399
399
  version: '0'
400
400
  requirements: []
401
- rubygems_version: 3.4.13
401
+ rubygems_version: 3.5.4
402
402
  signing_key:
403
403
  specification_version: 4
404
404
  summary: A Rack-based asset packaging system