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