sprockets 4.0.0.beta4 → 4.0.0.beta5

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,56 @@ module Sprockets
6
6
  module SourceMapUtils
7
7
  extend self
8
8
 
9
+ # Public: Transpose source maps into a standard format
10
+ #
11
+ # NOTE: Does not support index maps
12
+ #
13
+ # version => 3
14
+ # file => logical path
15
+ # sources => relative from filename
16
+ #
17
+ # Unnecessary attributes are removed
18
+ #
19
+ # Example
20
+ #
21
+ # map
22
+ # #=> {
23
+ # # "version" => 3,
24
+ # # "file" => "stdin",
25
+ # # "sourceRoot" => "",
26
+ # # "sourceContents" => "blah blah blah",
27
+ # # "sources" => [/root/logical/path.js],
28
+ # # "names" => [..],
29
+ # #}
30
+ # format_source_map(map, input)
31
+ # #=> {
32
+ # # "version" => 3,
33
+ # # "file" => "logical/path.js",
34
+ # # "sources" => ["path.js"],
35
+ # # "names" => [..],
36
+ # #}
37
+ def format_source_map(map, input)
38
+ filename = input[:filename]
39
+ load_path = input[:load_path]
40
+ load_paths = input[:environment].config[:paths]
41
+ mime_exts = input[:environment].config[:mime_exts]
42
+ pipeline_exts = input[:environment].config[:pipeline_exts]
43
+ file = PathUtils.split_subpath(load_path, filename)
44
+ {
45
+ "version" => 3,
46
+ "file" => file,
47
+ "mappings" => map["mappings"],
48
+ "sources" => map["sources"].map do |source|
49
+ source = URIUtils.split_file_uri(source)[2] if source.start_with? "file://"
50
+ source = PathUtils.join(File.dirname(filename), source) unless PathUtils.absolute_path?(source)
51
+ _, source = PathUtils.paths_split(load_paths, source)
52
+ source = PathUtils.relative_path_from(file, source)
53
+ PathUtils.set_pipeline(source, mime_exts, pipeline_exts, :source)
54
+ end,
55
+ "names" => map["names"]
56
+ }
57
+ end
58
+
9
59
  # Public: Concatenate two source maps.
10
60
  #
11
61
  # For an example, if two js scripts are concatenated, the individual source
@@ -16,25 +66,75 @@ module Sprockets
16
66
  # script3 = "#{script1}#{script2}"
17
67
  # map3 = concat_source_maps(map1, map2)
18
68
  #
19
- # a - Array of source mapping Hashes
20
- # b - Array of source mapping Hashes
69
+ # a - Source map hash
70
+ # b - Source map hash
21
71
  #
22
- # Returns a new Array of source mapping Hashes.
72
+ # Returns a new source map hash.
23
73
  def concat_source_maps(a, b)
24
- a ||= []
25
- b ||= []
26
- mappings = a.dup
74
+ return a || b unless a && b
75
+ a, b = make_index_map(a), make_index_map(b)
27
76
 
28
- if a.any?
29
- offset = a.last[:generated][0]
30
- else
77
+ if a["sections"].count == 0 || a["sections"].last["map"]["mappings"].empty?
31
78
  offset = 0
79
+ else
80
+ offset = a["sections"].last["map"]["mappings"].count(';') +
81
+ a["sections"].last["offset"]["line"] + 1
32
82
  end
33
83
 
34
- b.each do |m|
35
- mappings << m.merge(generated: [m[:generated][0] + offset, m[:generated][1]])
84
+ a["sections"] += b["sections"].map do |section|
85
+ {
86
+ "offset" => section["offset"].merge({ "line" => section["offset"]["line"] + offset }),
87
+ "map" => section["map"].merge({
88
+ "sources" => section["map"]["sources"].map do |source|
89
+ PathUtils.relative_path_from(a["file"], PathUtils.join(File.dirname(b["file"]), source))
90
+ end
91
+ })
92
+ }
36
93
  end
37
- mappings
94
+ a
95
+ end
96
+
97
+ # Public: Converts source map to index map
98
+ #
99
+ # Example:
100
+ #
101
+ # map
102
+ # # => {
103
+ # "version" => 3,
104
+ # "file" => "..",
105
+ # "mappings" => "AAAA;AACA;..;AACA",
106
+ # "sources" => [..],
107
+ # "names" => [..]
108
+ # }
109
+ # make_index_map(map)
110
+ # # => {
111
+ # "version" => 3,
112
+ # "file" => "..",
113
+ # "sections" => [
114
+ # {
115
+ # "offset" => { "line" => 0, "column" => 0 },
116
+ # "map" => {
117
+ # "version" => 3,
118
+ # "file" => "..",
119
+ # "mappings" => "AAAA;AACA;..;AACA",
120
+ # "sources" => [..],
121
+ # "names" => [..]
122
+ # }
123
+ # }
124
+ # ]
125
+ # }
126
+ def make_index_map(map)
127
+ return map if map.key? "sections"
128
+ {
129
+ "version" => map["version"],
130
+ "file" => map["file"],
131
+ "sections" => [
132
+ {
133
+ "offset" => { "line" => 0, "column" => 0 },
134
+ "map" => map
135
+ }
136
+ ]
137
+ }
38
138
  end
39
139
 
40
140
  # Public: Combine two seperate source map transformations into a single
@@ -49,25 +149,95 @@ module Sprockets
49
149
  # map can be combined with the Uglifier map so the source lines of the
50
150
  # minified output can be traced back to the original CoffeeScript file.
51
151
  #
52
- # original_map = [{ :source => "index.coffee", :generated => [2, 0], :original => [1, 0] }]
53
- # second_map = [{ :source => "index.js", :generated => [1, 1], :original => [2, 0] }]
54
- # combine_source_maps(original_map, second_map)
55
- # # => [{:source=>"index.coffee", :generated => [1, 1], :original => [1, 0]}]
56
- #
57
- # Returns a new Array of source mapping Hashes.
58
- def combine_source_maps(original_map, second_map)
59
- original_map ||= []
60
- return second_map.dup if original_map.empty?
152
+ # Returns a source map hash.
153
+ def combine_source_maps(first, second)
154
+ return second unless first
155
+
156
+ _first = decode_source_map(first)
157
+ _second = decode_source_map(second)
61
158
 
62
- new_map = []
159
+ new_mappings = []
63
160
 
64
- second_map.each do |m|
65
- original_line = bsearch_mappings(original_map, m[:original])
66
- next unless original_line
67
- new_map << original_line.merge(generated: m[:generated])
161
+ _second[:mappings].each do |m|
162
+ first_line = bsearch_mappings(_first[:mappings], m[:original])
163
+ new_mappings << first_line.merge(generated: m[:generated]) if first_line
68
164
  end
69
165
 
70
- new_map
166
+ _first[:mappings] = new_mappings
167
+
168
+ encode_source_map(_first)
169
+ end
170
+
171
+ # Public: Decompress source map
172
+ #
173
+ # Example:
174
+ #
175
+ # decode_source_map(map)
176
+ # # => {
177
+ # version: 3,
178
+ # file: "..",
179
+ # mappings: [
180
+ # { source: "..", generated: [0, 0], original: [0, 0], name: ".."}, ..
181
+ # ],
182
+ # sources: [..],
183
+ # names: [..]
184
+ # }
185
+ #
186
+ # map - Source map hash (v3 spec)
187
+ #
188
+ # Returns an uncompressed source map hash
189
+ def decode_source_map(map)
190
+ return nil unless map
191
+
192
+ mappings, sources, names = [], [], []
193
+ if map["sections"]
194
+ map["sections"].each do |s|
195
+ mappings += decode_source_map(s["map"])[:mappings].each do |m|
196
+ m[:generated][0] += s["offset"]["line"]
197
+ m[:generated][1] += s["offset"]["column"]
198
+ end
199
+ sources |= s["map"]["sources"]
200
+ names |= s["map"]["names"]
201
+ end
202
+ else
203
+ mappings = decode_vlq_mappings(map["mappings"], sources: map["sources"], names: map["names"])
204
+ sources = map["sources"]
205
+ names = map["names"]
206
+ end
207
+ {
208
+ version: 3,
209
+ file: map["file"],
210
+ mappings: mappings,
211
+ sources: sources,
212
+ names: names
213
+ }
214
+ end
215
+
216
+ # Public: Compress source map
217
+ #
218
+ # Example:
219
+ #
220
+ # encode_source_map(map)
221
+ # # => {
222
+ # "version" => 3,
223
+ # "file" => "..",
224
+ # "mappings" => "AAAA;AACA;..;AACA",
225
+ # "sources" => [..],
226
+ # "names" => [..]
227
+ # }
228
+ #
229
+ # map - Source map hash (uncompressed)
230
+ #
231
+ # Returns a compressed source map hash according to source map spec v3
232
+ def encode_source_map(map)
233
+ return nil unless map
234
+ {
235
+ "version" => map[:version],
236
+ "file" => map[:file],
237
+ "mappings" => encode_vlq_mappings(map[:mappings], sources: map[:sources], names: map[:names]),
238
+ "sources" => map[:sources],
239
+ "names" => map[:names]
240
+ }
71
241
  end
72
242
 
73
243
  # Public: Compare two source map offsets.
@@ -114,49 +284,6 @@ module Sprockets
114
284
  end
115
285
  end
116
286
 
117
- # Public: Decode Source Map JSON into Ruby objects.
118
- #
119
- # json - String source map JSON
120
- #
121
- # Returns Hash.
122
- def decode_json_source_map(json)
123
- map = JSON.parse(json)
124
- map['mappings'] = decode_vlq_mappings(map['mappings'], sources: map['sources'], names: map['names'])
125
- map
126
- end
127
-
128
- # Public: Encode mappings to Source Map JSON.
129
- #
130
- # mappings - Array of Hash or String VLQ encoded mappings
131
- # sources - Array of String sources
132
- # names - Array of String names
133
- # filename - String filename
134
- #
135
- # Returns JSON String.
136
- def encode_json_source_map(mappings, sources: nil, names: nil, filename: nil)
137
- case mappings
138
- when String
139
- when Array
140
- mappings.each do |m|
141
- m[:source] = PathUtils.relative_path_from(filename, m[:source])
142
- end if filename
143
- sources = sources.map { |s| PathUtils.relative_path_from(filename, s) } if filename && sources
144
- sources = (Array(sources) + mappings.map { |m| m[:source] }).uniq.compact
145
- names ||= mappings.map { |m| m[:name] }.uniq.compact
146
- mappings = encode_vlq_mappings(mappings, sources: sources, names: names)
147
- else
148
- raise TypeError, "could not encode mappings: #{mappings}"
149
- end
150
-
151
- JSON.generate({
152
- "version" => 3,
153
- "file" => filename,
154
- "mappings" => mappings,
155
- "sources" => sources,
156
- "names" => names
157
- })
158
- end
159
-
160
287
  # Public: Decode VLQ mappings and match up sources and symbol names.
161
288
  #
162
289
  # str - VLQ string from 'mappings' attribute
@@ -44,16 +44,22 @@ module Sprockets
44
44
  end
45
45
 
46
46
  def call(input)
47
- if Autoload::Uglifier::VERSION.to_i < 2
48
- raise "uglifier 1.x is no longer supported, please upgrade to 2.x"
47
+ case Autoload::Uglifier::VERSION.to_i
48
+ when 1
49
+ raise "uglifier 1.x is no longer supported, please upgrade to 2.x or newer"
50
+ when 2
51
+ input_options = { source_filename: input[:filename] }
52
+ else
53
+ input_options = { source_map: { filename: input[:filename] } }
49
54
  end
50
- @uglifier ||= Autoload::Uglifier.new(@options)
51
55
 
52
- js, map = @uglifier.compile_with_map(input[:data])
53
- map = SourceMapUtils.combine_source_maps(
54
- input[:metadata][:map],
55
- SourceMapUtils.decode_json_source_map(map)["mappings"]
56
- )
56
+ uglifier = Autoload::Uglifier.new(@options.merge(input_options))
57
+
58
+ js, map = uglifier.compile_with_map(input[:data])
59
+
60
+ map = SourceMapUtils.format_source_map(JSON.parse(map), input)
61
+ map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
62
+
57
63
  { data: js, map: map }
58
64
  end
59
65
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sprockets
3
- VERSION = "4.0.0.beta4"
3
+ VERSION = "4.0.0.beta5"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta4
4
+ version: 4.0.0.beta5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-10-17 00:00:00.000000000 Z
12
+ date: 2017-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -251,14 +251,14 @@ dependencies:
251
251
  name: uglifier
252
252
  requirement: !ruby/object:Gem::Requirement
253
253
  requirements:
254
- - - "~>"
254
+ - - ">="
255
255
  - !ruby/object:Gem::Version
256
256
  version: '2.3'
257
257
  type: :development
258
258
  prerelease: false
259
259
  version_requirements: !ruby/object:Gem::Requirement
260
260
  requirements:
261
- - - "~>"
261
+ - - ">="
262
262
  - !ruby/object:Gem::Version
263
263
  version: '2.3'
264
264
  - !ruby/object:Gem::Dependency
@@ -353,6 +353,7 @@ files:
353
353
  - lib/sprockets/manifest.rb
354
354
  - lib/sprockets/manifest_utils.rb
355
355
  - lib/sprockets/mime.rb
356
+ - lib/sprockets/npm.rb
356
357
  - lib/sprockets/path_dependency_utils.rb
357
358
  - lib/sprockets/path_digest_utils.rb
358
359
  - lib/sprockets/path_utils.rb
@@ -393,7 +394,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
393
394
  requirements:
394
395
  - - ">="
395
396
  - !ruby/object:Gem::Version
396
- version: 2.0.0
397
+ version: 2.2.0
397
398
  required_rubygems_version: !ruby/object:Gem::Requirement
398
399
  requirements:
399
400
  - - ">"
@@ -401,7 +402,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
401
402
  version: 1.3.1
402
403
  requirements: []
403
404
  rubyforge_project: sprockets
404
- rubygems_version: 2.5.1
405
+ rubygems_version: 2.6.13
405
406
  signing_key:
406
407
  specification_version: 4
407
408
  summary: Rack-based asset packaging system