uglifier 2.7.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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