uglifier 2.7.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 93cb2441ef4a95a1bb409fa2d9c47acf7e18117a
4
- data.tar.gz: 6e6265967cb909387d5e621262a84246f49b44a2
3
+ metadata.gz: 965824e428764606cd1617e6e72b9ab0ad912b7b
4
+ data.tar.gz: 996b18eac0ad32e9c9ad8b31e7a8ab90c0208039
5
5
  SHA512:
6
- metadata.gz: c2524b95360adb6557e70e2a6354b6d969ed04a8981374187b27a4930c5d04885d112d4e70891baf5d7c6279652aac890772dac6c8972290ffb3a62cf8838631
7
- data.tar.gz: ada6b5d1036f83ef1a236a62056b49947c9c583deb5c81fc66ac38b656eac367f25abc2f964ed05b492313d235603b4b789d21c761f97504fcefe3f9e613a5f4
6
+ metadata.gz: d41ff9576c911132ce28f20b530d1c3b925e6caa5416884608e69cbbbe25b1fda4a4a27fb267b320633b6d9bb34c632c9e1c60c5be6b7663309aecb0a17b93df
7
+ data.tar.gz: 748763a30cd991eec4c52648c0af2a40ae199646cb92b0dc481ff504b1ef388dbfd385817011ca5489dd4ad5f37d0dff0c6d0e52a39fc41b61be6d859946677a
@@ -25,3 +25,9 @@ Style/SignalException:
25
25
 
26
26
  Style/StringLiterals:
27
27
  Enabled: false
28
+
29
+ Style/Alias:
30
+ Enabled: false
31
+
32
+ Style/MutableConstant:
33
+ Enabled: false
@@ -2,12 +2,13 @@ sudo: false
2
2
  language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
- - 1.8.7
6
5
  - 1.9.3
7
6
  - 2.0.0
8
- - 2.1.5
9
- - 2.2.0
10
- - jruby
7
+ - 2.1.7
8
+ - 2.2.3
9
+ - 2.3.0
10
+ - jruby-19mode
11
+ - jruby-9.0.4.0
11
12
  - rbx-2
12
13
  git:
13
14
  submodules: false
@@ -15,16 +16,16 @@ gemfile:
15
16
  - Gemfile
16
17
  matrix:
17
18
  include:
18
- - rvm: 2.2.0
19
+ - rvm: 2.3.0
19
20
  gemfile: gemfiles/rubyracer
20
- - rvm: 2.1.5
21
+ - rvm: 2.1.7
21
22
  gemfile: gemfiles/rubyracer
22
23
  - rvm: jruby-19mode
23
24
  gemfile: gemfiles/rubyrhino
24
- - rvm: 2.2.0
25
+ - rvm: 2.3.0
25
26
  gemfile: gemfiles/alaska
26
27
  env: ALASKA=1
27
28
  allow_failures:
28
- - rvm: 2.2.0
29
+ - rvm: 2.3.0
29
30
  gemfile: gemfiles/alaska
30
31
  env: ALASKA=1
@@ -0,0 +1,4 @@
1
+ --title "Uglifier"
2
+ -
3
+ CHANGELOG.md
4
+ LICENSE.txt
@@ -1,3 +1,15 @@
1
+ ## 3.0.0 (22 March 2016)
2
+
3
+ - drop support for Ruby 1.8
4
+ - remove json as dependency
5
+ - discard unused function arguments only in unsafe mode
6
+ - add `keep_fnames` option to preserve function names in compressed code
7
+ - add `collapse_vars` option to collapse single-use variables
8
+ - backwards incompatible changes to source map options
9
+ - support for inline base64 encoded source maps
10
+ - mangle property names option (disabled by default)
11
+ - update UglifyJS to 2.6.2
12
+
1
13
  ## 2.7.2 (26 August 2015)
2
14
 
3
15
  - update UglifyJS to 2.4.24
data/Gemfile CHANGED
@@ -2,8 +2,4 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- if RUBY_VERSION >= '1.9'
6
- gem 'rubocop', '~> 0.28.0', :group => [:development]
7
- else
8
- gem 'execjs', '~> 2.0.2'
9
- end
5
+ gem 'rubocop', '~> 0.37.2', :group => [:development]
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # Uglifier [![Build Status](https://travis-ci.org/lautis/uglifier.svg?branch=master)](https://travis-ci.org/lautis/uglifier) [![Dependency Status](https://gemnasium.com/lautis/uglifier.svg)](https://gemnasium.com/lautis/uglifier)
1
+ # Uglifier
2
2
 
3
3
  Ruby wrapper for [UglifyJS](https://github.com/mishoo/UglifyJS2) JavaScript compressor.
4
4
 
5
+ [![Build Status](https://travis-ci.org/lautis/uglifier.svg?branch=master)](https://travis-ci.org/lautis/uglifier)
6
+
5
7
  ## Installation
6
8
 
7
9
  Uglifier is available as a ruby gem.
@@ -65,6 +67,9 @@ Available options and their defaults are
65
67
  :sort => false, # Assign shorter names to most frequently used variables. Often results in bigger output after gzip.
66
68
  :toplevel => false # Mangle names declared in the toplevel scope
67
69
  }, # Mangle variable and function names, set to false to skip mangling
70
+ :mangle_properties => {
71
+ :regex => nil # A regular expression to filter property names to be mangled
72
+ } # Mangle property names, disabled by default
68
73
  :compress => {
69
74
  :sequences => true, # Allow statements to be joined by commas
70
75
  :properties => true, # Rewrite property access using the dot notation
@@ -82,22 +87,26 @@ Available options and their defaults are
82
87
  :if_return => true, # Optimizations for if/return and if/continue
83
88
  :join_vars => true, # Join consecutive var statements
84
89
  :cascade => true, # Cascade sequences
90
+ :collapse_vars => false, # Collapse single-use var and const definitions when possible.
85
91
  :negate_iife => true, # Negate immediately invoked function expressions to avoid extra parens
86
92
  :pure_getters => false, # Assume that object property access does not have any side-effects
87
93
  :pure_funcs => nil, # List of functions without side-effects. Can safely discard function calls when the result value is not used
88
94
  :drop_console => false, # Drop calls to console.* functions
89
- :angular => false # Process @ngInject annotations
90
- :keep_fargs => false # Preserve unused function arguments
95
+ :angular => false, # Process @ngInject annotations
96
+ :keep_fargs => false, # Preserve unused function arguments
97
+ :keep_fnames => false # Preserve function names
91
98
  }, # Apply transformations to code, set to false to skip
92
99
  :define => {}, # Define values for symbol replacement
93
100
  :enclose => false, # Enclose in output function wrapper, define replacements as key-value pairs
94
- :source_filename => nil, # The filename of the input file
95
- :source_root => nil, # The URL of the directory which contains :source_filename
96
- :output_filename => nil, # The filename or URL where the minified output can be found
97
- :input_source_map => nil, # The contents of the source map describing the input
98
- :screw_ie8 => false, # Don't bother to generate safe code for IE8
99
- :source_map_url => false, # Url for source mapping to be appended in minified source
100
- :source_url => false # Url to original source to be appended in minified source
101
+ :source_map => {
102
+ :map_url => false, # Url for source mapping to be appended in minified source
103
+ :url => false, # Url for original source to be appended in minified source
104
+ :sources_content => false, # Include original source content in map
105
+ :filename => nil, # The filename of the input file
106
+ :root => nil, # The URL of the directory which contains :filename
107
+ :output_filename => nil, # The filename or URL where the minified output can be found
108
+ :input_source_map => nil # The contents of the source map describing the input
109
+ }
101
110
  }
102
111
  ```
103
112
 
data/Rakefile CHANGED
@@ -1,40 +1,15 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'rubygems'
4
- require 'bundler'
5
3
  require 'bundler/gem_tasks'
6
-
7
- begin
8
- Bundler.setup(:default, :development)
9
- rescue Bundler::BundlerError => e
10
- $stderr.puts e.message
11
- $stderr.puts "Run `bundle install` to install missing gems"
12
- exit e.status_code
13
- end
14
-
15
- require 'rake'
16
-
17
- require 'rspec/core'
18
4
  require 'rspec/core/rake_task'
19
5
  RSpec::Core::RakeTask.new(:spec) do |spec|
20
6
  spec.pattern = FileList['spec/**/*_spec.rb']
21
7
  end
22
8
 
23
- require 'rdoc/task'
24
- Rake::RDocTask.new do |rdoc|
25
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
26
-
27
- rdoc.rdoc_dir = 'rdoc'
28
- rdoc.title = "uglifier #{version}"
29
- rdoc.rdoc_files.include('README*')
30
- rdoc.rdoc_files.include('lib/**/*.rb')
31
- end
32
-
33
9
  desc "Rebuild lib/uglify.js"
34
10
  task :js do
35
11
  cd 'vendor/source-map/' do
36
12
  `npm install`
37
- `node Makefile.dryice.js`
38
13
  end
39
14
 
40
15
  cd 'vendor/uglifyjs/' do
@@ -54,7 +29,7 @@ end
54
29
  begin
55
30
  require 'rubocop/rake_task'
56
31
  RuboCop::RakeTask.new(:rubocop)
57
- task :default => [:spec]
32
+ task :default => [:rubocop, :spec]
58
33
  rescue LoadError
59
34
  task :default => [:spec]
60
35
  end
@@ -0,0 +1,111 @@
1
+ function comments(option) {
2
+ if (Object.prototype.toString.call(option) === '[object Array]') {
3
+ return new RegExp(option[0], option[1]);
4
+ } else if (option == "jsdoc") {
5
+ return function(node, comment) {
6
+ if (comment.type == "comment2") {
7
+ return /@preserve|@license|@cc_on/i.test(comment.value);
8
+ } else {
9
+ return false;
10
+ }
11
+ };
12
+ } else {
13
+ return option;
14
+ }
15
+ }
16
+
17
+ function readNameCache(key) {
18
+ return UglifyJS.readNameCache(null, key);
19
+ }
20
+
21
+ function writeNameCache(key, cache) {
22
+ return UglifyJS.writeNameCache(null, key, cache);
23
+ }
24
+
25
+ function regexOption(options) {
26
+ if (typeof options === 'object' && options.regex) {
27
+ return new RegExp(options.regex[0], options.regex[1]);
28
+ } else {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ function parse(source, options) {
34
+ var ast = UglifyJS.parse(source, options.parse_options);
35
+ ast.figure_out_scope();
36
+
37
+ if (options.compress) {
38
+ var compressor = UglifyJS.Compressor(options.compress);
39
+ ast = ast.transform(compressor);
40
+ ast.figure_out_scope();
41
+ }
42
+
43
+ if (options.mangle) {
44
+ ast.compute_char_frequency();
45
+ ast.mangle_names(options.mangle);
46
+ }
47
+
48
+ if (options.mangle_properties) {
49
+ var regex = regexOption(options.mangle_properties);
50
+ UglifyJS.mangle_properties(ast, {
51
+ reserved: [],
52
+ only_cache: false,
53
+ regex: regex
54
+ });
55
+ }
56
+
57
+ if (options.enclose) {
58
+ ast = ast.wrap_enclose(options.enclose);
59
+ }
60
+ return ast;
61
+ }
62
+
63
+ function copySourcesContent(sourceMap, options) {
64
+ sourceMap.get().setSourceContent(options.parse_options.filename, options.source);
65
+
66
+ var original = options.source_map_options.orig;
67
+
68
+ if (original && original.sources && original.sourcesContent) {
69
+ for(var i = 0; i < original.sources.length; i++) {
70
+ sourceMap.get().setSourceContent(original.sources[i], original.sourcesContent[i]);
71
+ }
72
+ }
73
+ }
74
+
75
+ function uglifier(options) {
76
+ var source = options.source;
77
+ var ast = parse(source, options);
78
+ var source_map;
79
+
80
+ var gen_code_options = options.output;
81
+ gen_code_options.comments = comments(options.output.comments);
82
+
83
+ if (options.generate_map) {
84
+ source_map = UglifyJS.SourceMap(options.source_map_options);
85
+ gen_code_options.source_map = source_map;
86
+
87
+ if (options.source_map_options.sources_content) {
88
+ copySourcesContent(source_map, options);
89
+ }
90
+ }
91
+
92
+ var stream = UglifyJS.OutputStream(gen_code_options);
93
+ ast.print(stream);
94
+
95
+ if (options.source_map_options.map_url) {
96
+ stream += "\n//# sourceMappingURL=" + options.source_map_options.map_url;
97
+ }
98
+
99
+ if (options.source_map_options.url) {
100
+ stream += "\n//# sourceURL=" + options.source_map_options.url;
101
+ }
102
+
103
+ if (options.generate_map) {
104
+ if (options.source_map_options.sources_content) {
105
+ source_map.get().setSourceContent(options.parse_options.filename, options.source);
106
+ }
107
+ return [stream.toString(), source_map.toString()];
108
+ } else {
109
+ return stream.toString();
110
+ }
111
+ }
@@ -1,78 +1,14 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require "execjs"
4
3
  require "json"
4
+ require "base64"
5
+ require "execjs"
5
6
  require "uglifier/version"
6
7
 
7
8
  # A wrapper around the UglifyJS interface
8
9
  class Uglifier
9
10
  # Error class for compilation errors.
10
11
  Error = ExecJS::Error
11
- # JavaScript code to call UglifyJS
12
- JS = <<-JS
13
- (function(options) {
14
- function comments(option) {
15
- if (Object.prototype.toString.call(option) === '[object Array]') {
16
- return new RegExp(option[0], option[1]);
17
- } else if (option == "jsdoc") {
18
- return function(node, comment) {
19
- if (comment.type == "comment2") {
20
- return /@preserve|@license|@cc_on/i.test(comment.value);
21
- } else {
22
- return false;
23
- }
24
- }
25
- } else {
26
- return option;
27
- }
28
- }
29
-
30
- var source = options.source;
31
- var ast = UglifyJS.parse(source, options.parse_options);
32
- ast.figure_out_scope();
33
-
34
- if (options.compress) {
35
- var compressor = UglifyJS.Compressor(options.compress);
36
- ast = ast.transform(compressor);
37
- ast.figure_out_scope();
38
- }
39
-
40
- if (options.mangle) {
41
- ast.compute_char_frequency();
42
- ast.mangle_names(options.mangle);
43
- }
44
-
45
- if (options.enclose) {
46
- ast = ast.wrap_enclose(options.enclose);
47
- }
48
-
49
- var gen_code_options = options.output;
50
- gen_code_options.comments = comments(options.output.comments);
51
-
52
- if (options.generate_map) {
53
- var source_map = UglifyJS.SourceMap(options.source_map_options);
54
- gen_code_options.source_map = source_map;
55
- }
56
-
57
- var stream = UglifyJS.OutputStream(gen_code_options);
58
-
59
- ast.print(stream);
60
-
61
- if (options.source_map_options.map_url) {
62
- stream += "\\n//# sourceMappingURL=" + options.source_map_options.map_url;
63
- }
64
-
65
- if (options.source_map_options.url) {
66
- stream += "\\n//# sourceURL=" + options.source_map_options.url;
67
- }
68
-
69
- if (options.generate_map) {
70
- return [stream.toString(), source_map.toString()];
71
- } else {
72
- return stream.toString();
73
- }
74
- })
75
- JS
76
12
 
77
13
  # UglifyJS source path
78
14
  SourcePath = File.expand_path("../uglify.js", __FILE__)
@@ -80,6 +16,8 @@ class Uglifier
80
16
  ES5FallbackPath = File.expand_path("../es5.js", __FILE__)
81
17
  # String.split shim source path
82
18
  SplitFallbackPath = File.expand_path("../split.js", __FILE__)
19
+ # UglifyJS wrapper path
20
+ UglifyJSWrapperPath = File.expand_path("../uglifier.js", __FILE__)
83
21
 
84
22
  # Default options for compilation
85
23
  DEFAULTS = {
@@ -104,8 +42,10 @@ class Uglifier
104
42
  :eval => false, # Mangle names when eval of when is used in scope
105
43
  :except => ["$super"], # Argument names to be excluded from mangling
106
44
  :sort => false, # Assign shorter names to most frequently used variables. Often results in bigger output after gzip.
107
- :toplevel => false # Mangle names declared in the toplevel scope
45
+ :toplevel => false, # Mangle names declared in the toplevel scope
46
+ :properties => false # Mangle property names
108
47
  }, # Mangle variable and function names, set to false to skip mangling
48
+ :mangle_properties => false, # Mangle property names
109
49
  :compress => {
110
50
  :sequences => true, # Allow statements to be joined by commas
111
51
  :properties => true, # Rewrite property access using the dot notation
@@ -123,23 +63,37 @@ class Uglifier
123
63
  :if_return => true, # Optimizations for if/return and if/continue
124
64
  :join_vars => true, # Join consecutive var statements
125
65
  :cascade => true, # Cascade sequences
66
+ :collapse_vars => false, # Collapse single-use var and const definitions when possible.
126
67
  :negate_iife => true, # Negate immediately invoked function expressions to avoid extra parens
127
68
  :pure_getters => false, # Assume that object property access does not have any side-effects
128
69
  :pure_funcs => nil, # List of functions without side-effects. Can safely discard function calls when the result value is not used
129
70
  :drop_console => false, # Drop calls to console.* functions
130
71
  :angular => false, # Process @ngInject annotations
131
- :keep_fargs => false # Preserve unused function arguments
72
+ :keep_fargs => false, # Preserve unused function arguments
73
+ :keep_fnames => false # Preserve function names
132
74
  }, # Apply transformations to code, set to false to skip
133
75
  :define => {}, # Define values for symbol replacement
134
76
  :enclose => false, # Enclose in output function wrapper, define replacements as key-value pairs
135
- :source_filename => nil, # The filename of the input file
136
- :source_root => nil, # The URL of the directory which contains :source_filename
137
- :output_filename => nil, # The filename or URL where the minified output can be found
138
- :input_source_map => nil, # The contents of the source map describing the input
139
77
  :screw_ie8 => false, # Don't bother to generate safe code for IE8
140
- :source_map_url => false, # Url for source mapping to be appended in minified source
141
- :source_url => false # Url for original source to be appended in minified source
78
+ :source_map => false # Generate source map
79
+ }
80
+
81
+ LEGACY_OPTIONS = [:comments, :squeeze, :copyright, :mangle]
82
+
83
+ MANGLE_PROPERTIES_DEFAULTS = {
84
+ :regex => nil # A regular expression to filter property names to be mangled
142
85
  }
86
+
87
+ SOURCE_MAP_DEFAULTS = {
88
+ :map_url => false, # Url for source mapping to be appended in minified source
89
+ :url => false, # Url for original source to be appended in minified source
90
+ :sources_content => false, # Include original source content in map
91
+ :filename => nil, # The filename of the input file
92
+ :root => nil, # The URL of the directory which contains :filename
93
+ :output_filename => nil, # The filename or URL where the minified output can be found
94
+ :input_source_map => nil # The contents of the source map describing the input
95
+ }
96
+
143
97
  # rubocop:enable LineLength
144
98
 
145
99
  # Minifies JavaScript code using implicit context.
@@ -164,7 +118,7 @@ class Uglifier
164
118
  #
165
119
  # @param options [Hash] optional overrides to +Uglifier::DEFAULTS+
166
120
  def initialize(options = {})
167
- (options.keys - DEFAULTS.keys - [:comments, :squeeze, :copyright])[0..1].each do |missing|
121
+ (options.keys - DEFAULTS.keys - LEGACY_OPTIONS)[0..1].each do |missing|
168
122
  raise ArgumentError, "Invalid option: #{missing}"
169
123
  end
170
124
  @options = options
@@ -176,7 +130,14 @@ class Uglifier
176
130
  # @param source [IO, String] valid JS source code.
177
131
  # @return [String] minified code.
178
132
  def compile(source)
179
- run_uglifyjs(source, false)
133
+ if @options[:source_map]
134
+ compiled, source_map = run_uglifyjs(source, true)
135
+ source_map_uri = Base64.strict_encode64(source_map)
136
+ source_map_mime = "application/json;charset=utf-8;base64"
137
+ compiled + "\n//# sourceMappingURL=data:#{source_map_mime},#{source_map_uri}"
138
+ else
139
+ run_uglifyjs(source, false)
140
+ end
180
141
  end
181
142
  alias_method :compress, :compile
182
143
 
@@ -191,25 +152,28 @@ class Uglifier
191
152
  private
192
153
 
193
154
  def uglifyjs_source
194
- [ES5FallbackPath, SplitFallbackPath, SourcePath].map do |file|
195
- File.open(file, "r:UTF-8") { |f| f.read }
155
+ [ES5FallbackPath, SplitFallbackPath, SourcePath, UglifyJSWrapperPath].map do |file|
156
+ File.open(file, "r:UTF-8", &:read)
196
157
  end.join("\n")
197
158
  end
198
159
 
199
160
  # Run UglifyJS for given source code
200
- def run_uglifyjs(source, generate_map)
161
+ def run_uglifyjs(input, generate_map)
162
+ source = read_source(input)
163
+ input_map = input_source_map(source, generate_map)
201
164
  options = {
202
- :source => read_source(source),
165
+ :source => source,
203
166
  :output => output_options,
204
167
  :compress => compressor_options,
205
168
  :mangle => mangle_options,
169
+ :mangle_properties => mangle_properties_options,
206
170
  :parse_options => parse_options,
207
- :source_map_options => source_map_options,
171
+ :source_map_options => source_map_options(input_map),
208
172
  :generate_map => generate_map,
209
173
  :enclose => enclose_options
210
174
  }
211
175
 
212
- @context.call(Uglifier::JS, options)
176
+ @context.call("uglifier", options)
213
177
  end
214
178
 
215
179
  def read_source(source)
@@ -221,14 +185,25 @@ class Uglifier
221
185
  end
222
186
 
223
187
  def mangle_options
224
- conditional_option(@options[:mangle], DEFAULTS[:mangle])
188
+ mangle_options = @options.fetch(:mangle, @options[:mangle])
189
+ conditional_option(mangle_options, DEFAULTS[:mangle])
190
+ end
191
+
192
+ def mangle_properties_options
193
+ mangle_options = @options.fetch(:mangle_properties, DEFAULTS[:mangle_properties])
194
+ options = conditional_option(mangle_options, MANGLE_PROPERTIES_DEFAULTS)
195
+ if options && options[:regex]
196
+ options.merge(:regex => encode_regexp(options[:regex]))
197
+ else
198
+ options
199
+ end
225
200
  end
226
201
 
227
202
  def compressor_options
228
203
  defaults = conditional_option(
229
204
  DEFAULTS[:compress],
230
205
  :global_defs => @options[:define] || {},
231
- :screw_ie8 => @options[:screw_ie8] || DEFAULTS[:screw_ie8]
206
+ :screw_ie8 => screw_ie8?
232
207
  )
233
208
  conditional_option(@options[:compress] || @options[:squeeze], defaults)
234
209
  end
@@ -269,24 +244,31 @@ class Uglifier
269
244
 
270
245
  def screw_ie8?
271
246
  if (@options[:output] || {}).has_key?(:ie_proof)
272
- false
247
+ !@options[:output][:ie_proof]
273
248
  else
274
- @options[:screw_ie8] || DEFAULTS[:screw_ie8]
249
+ @options.fetch(:screw_ie8, DEFAULTS[:screw_ie8])
275
250
  end
276
251
  end
277
252
 
278
- def source_map_options
253
+ def source_map_options(input_map)
254
+ options = conditional_option(@options[:source_map], SOURCE_MAP_DEFAULTS)
255
+
279
256
  {
280
- :file => @options[:output_filename],
281
- :root => @options[:source_root],
282
- :orig => @options[:input_source_map],
283
- :map_url => @options[:source_map_url],
284
- :url => @options[:source_url]
257
+ :file => options[:output_filename],
258
+ :root => options.fetch(:root) { input_map ? input_map["sourceRoot"] : nil },
259
+ :orig => input_map,
260
+ :map_url => options[:map_url],
261
+ :url => options[:url],
262
+ :sources_content => options[:sources_content]
285
263
  }
286
264
  end
287
265
 
288
266
  def parse_options
289
- { :filename => @options[:source_filename] }
267
+ if @options[:source_map].respond_to?(:[])
268
+ { :filename => @options[:source_map][:filename] }
269
+ else
270
+ {}
271
+ end
290
272
  end
291
273
 
292
274
  def enclose_options
@@ -318,4 +300,38 @@ class Uglifier
318
300
  false
319
301
  end
320
302
  end
303
+
304
+ def sanitize_map_root(map)
305
+ if map.nil?
306
+ nil
307
+ elsif map.is_a? String
308
+ sanitize_map_root(JSON.load(map))
309
+ elsif map["sourceRoot"] == ""
310
+ map.merge("sourceRoot" => nil)
311
+ else
312
+ map
313
+ end
314
+ end
315
+
316
+ def extract_source_mapping_url(source)
317
+ comment_start = %r{(?://|/\*\s*)}
318
+ comment_end = %r{\s*(?:\r?\n?\*/|$)?}
319
+ source_mapping_regex = /#{comment_start}[@#]\ssourceMappingURL=\s*(\S*?)#{comment_end}/
320
+ rest = /\s#{comment_start}[@#]\s[a-zA-Z]+=\s*(?:\S*?)#{comment_end}/
321
+ regex = /#{source_mapping_regex}(?:#{rest})*\Z/m
322
+ match = regex.match(source)
323
+ match && match[1]
324
+ end
325
+
326
+ def input_source_map(source, generate_map)
327
+ return nil unless generate_map
328
+ sanitize_map_root(@options.fetch(:source_map, {}).fetch(:input_source_map) do
329
+ url = extract_source_mapping_url(source)
330
+ if url && url.start_with?("data:")
331
+ Base64.strict_decode64(url.split(",", 2)[-1])
332
+ end
333
+ end)
334
+ rescue ArgumentError, JSON::ParserError
335
+ nil
336
+ end
321
337
  end