condenser 1.3 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/condenser/asset.rb +52 -21
- data/lib/condenser/build_cache.rb +21 -8
- data/lib/condenser/helpers/parse_helpers.rb +7 -0
- data/lib/condenser/processors/babel_processor.rb +8 -14
- data/lib/condenser/processors/js_analyzer.rb +41 -6
- data/lib/condenser/processors/node_processor.rb +1 -0
- data/lib/condenser/processors/rollup_processor.rb +1 -1
- data/lib/condenser/resolve.rb +26 -3
- data/lib/condenser/version.rb +1 -1
- data/test/cache_test.rb +111 -16
- data/test/dependency_test.rb +51 -2
- data/test/preprocessor/babel_test.rb +65 -54
- data/test/preprocessor/js_analyzer_test.rb +35 -0
- data/test/resolve_test.rb +10 -0
- data/test/server_test.rb +9 -9
- data/test/test_helper.rb +6 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 171baa1e5cd8016c4b2e7f142147d174410085ede075c101da43b743a4ad6fec
|
4
|
+
data.tar.gz: 9c97b58fb2bf540b335f6504997da99fac72891f61a0a0631639ae3fd9f28482
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: decc8b993d0e99c5212f3c0b1d4be88de43d49ab1386f32936a0dae482fc9b45de55cbbc51d99eafce58bcd68809a20fd27267ef0fe62d3aa3a244e33e68992e
|
7
|
+
data.tar.gz: e39a90c28c7beab789885e53e35ae0ad43340ff4009f81ad1586ac16eb0073dbaf999b69a94f78e796f5bfe5e93a16e0a45481e76b706d0e496dfbe5435b4966
|
data/lib/condenser/asset.rb
CHANGED
@@ -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
|
-
|
72
|
-
|
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
|
-
|
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
|
-
|
88
|
-
|
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
|
-
|
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 = [
|
128
|
-
|
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 = [
|
136
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
98
|
+
|
99
|
+
ExportDeclaration(path, state) {
|
99
100
|
hasExports = true;
|
100
|
-
|
101
|
+
if (path.node.source) {
|
102
|
+
imports.push(path.node.source.value);
|
103
|
+
}
|
101
104
|
},
|
102
|
-
|
103
|
-
|
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 :
|
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
|
-
|
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
|
-
|
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
|
@@ -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 ?
|
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
|
data/lib/condenser/resolve.rb
CHANGED
@@ -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.
|
153
|
-
|
154
|
-
|
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 == '.*'
|
data/lib/condenser/version.rb
CHANGED
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(){
|
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(){
|
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(){
|
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
|
-
|
139
|
+
console.log(5);
|
127
140
|
JS
|
128
141
|
assert_exported_file 'b.js', 'application/javascript', <<~JS
|
129
|
-
|
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
|
-
|
150
|
+
console.log(10);
|
138
151
|
JS
|
139
152
|
assert_exported_file 'b.js', 'application/javascript', <<~JS
|
140
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/dependency_test.rb
CHANGED
@@ -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
|
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
|
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$
|
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
|
-
|
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
|
-
|
174
|
-
|
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 =
|
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$
|
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$
|
286
|
-
: path$2[namespace] && path$2[namespace][method] || global$
|
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$
|
302
|
+
var global$6 = global$8;
|
296
303
|
var userAgent = engineUserAgent;
|
297
304
|
|
298
|
-
var process = global$
|
299
|
-
var Deno = global$
|
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$
|
333
|
+
var global$5 = global$8;
|
327
334
|
|
328
|
-
var $String$2 = global$
|
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
|
417
|
+
var sharedStore = {exports: {}};
|
411
418
|
|
412
|
-
var global$
|
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$
|
426
|
+
defineProperty$1(global$4, key, { value: value, configurable: true, writable: true });
|
420
427
|
} catch (error) {
|
421
|
-
global$
|
428
|
+
global$4[key] = value;
|
422
429
|
} return value;
|
423
430
|
};
|
424
431
|
|
425
|
-
var
|
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 =
|
436
|
+
var store$1 = sharedStore.exports = globalThis$1[SHARED] || defineGlobalProperty(SHARED, {});
|
430
437
|
|
431
|
-
|
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-
|
441
|
-
license: 'https://github.com/zloirock/core-js/blob/v3.
|
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
|
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$
|
480
|
-
var shared =
|
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$
|
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$
|
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] :
|
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 (
|
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
|
-
|
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 "
|
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
|
-
|
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(){
|
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 = '
|
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 '"
|
111
|
-
assert_equal '
|
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 '"
|
171
|
-
assert_equal '
|
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
|
-
|
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
|
-
|
58
|
-
|
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.
|
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:
|
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
|
401
|
+
rubygems_version: 3.5.4
|
402
402
|
signing_key:
|
403
403
|
specification_version: 4
|
404
404
|
summary: A Rack-based asset packaging system
|