uglifier 2.7.1 → 3.1.13
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/.gitmodules +3 -0
- data/.rubocop.yml +20 -3
- data/.travis.yml +10 -11
- data/.yardopts +4 -0
- data/CHANGELOG.md +102 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +1 -5
- data/README.md +35 -12
- data/Rakefile +6 -30
- data/lib/es5.js +1 -1
- data/lib/source-map.js +3055 -0
- data/lib/uglifier/version.rb +1 -1
- data/lib/uglifier.js +120 -0
- data/lib/uglifier.rb +161 -99
- data/lib/uglify.js +55 -1803
- data/uglifier.gemspec +8 -8
- metadata +20 -48
- data/gemfiles/alaska +0 -4
- data/gemfiles/rubyracer +0 -4
- data/gemfiles/rubyrhino +0 -4
- data/spec/source_map_spec.rb +0 -110
- data/spec/spec_helper.rb +0 -23
- data/spec/uglifier_spec.rb +0 -271
data/lib/uglifier/version.rb
CHANGED
data/lib/uglifier.js
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
// Set source-map.js sourceMap to uglify.js MOZ_SourceMap
|
2
|
+
MOZ_SourceMap = sourceMap;
|
3
|
+
|
4
|
+
function comments(option) {
|
5
|
+
if (Object.prototype.toString.call(option) === '[object Array]') {
|
6
|
+
return new RegExp(option[0], option[1]);
|
7
|
+
} else if (option == "jsdoc") {
|
8
|
+
return function(node, comment) {
|
9
|
+
if (comment.type == "comment2") {
|
10
|
+
return /@preserve|@license|@cc_on/i.test(comment.value);
|
11
|
+
} else {
|
12
|
+
return false;
|
13
|
+
}
|
14
|
+
};
|
15
|
+
} else {
|
16
|
+
return option;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
function readNameCache(key) {
|
21
|
+
return UglifyJS.readNameCache(null, key);
|
22
|
+
}
|
23
|
+
|
24
|
+
function writeNameCache(key, cache) {
|
25
|
+
return UglifyJS.writeNameCache(null, key, cache);
|
26
|
+
}
|
27
|
+
|
28
|
+
function regexOption(options) {
|
29
|
+
if (typeof options === 'object' && options.regex) {
|
30
|
+
return new RegExp(options.regex[0], options.regex[1]);
|
31
|
+
} else {
|
32
|
+
return null;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
function parse(source, options) {
|
37
|
+
UglifyJS.base54.reset();
|
38
|
+
var ast = UglifyJS.parse(source, options.parse_options);
|
39
|
+
|
40
|
+
if (options.compress) {
|
41
|
+
var compress = { warnings: false };
|
42
|
+
UglifyJS.merge(compress, options.compress);
|
43
|
+
ast.figure_out_scope(options.mangle);
|
44
|
+
var compressor = UglifyJS.Compressor(compress);
|
45
|
+
ast = compressor.compress(ast);
|
46
|
+
ast.figure_out_scope();
|
47
|
+
}
|
48
|
+
|
49
|
+
if (options.mangle) {
|
50
|
+
ast.figure_out_scope(options.mangle);
|
51
|
+
ast.compute_char_frequency();
|
52
|
+
ast.mangle_names(options.mangle);
|
53
|
+
}
|
54
|
+
|
55
|
+
if (options.mangle_properties) {
|
56
|
+
var regex = regexOption(options.mangle_properties);
|
57
|
+
UglifyJS.mangle_properties(ast, {
|
58
|
+
reserved: [],
|
59
|
+
only_cache: false,
|
60
|
+
regex: regex,
|
61
|
+
debug: options.mangle_properties.debug,
|
62
|
+
ignore_quoted: options.mangle_properties.ignore_quoted
|
63
|
+
});
|
64
|
+
}
|
65
|
+
|
66
|
+
if (options.enclose) {
|
67
|
+
ast = ast.wrap_enclose(options.enclose);
|
68
|
+
}
|
69
|
+
return ast;
|
70
|
+
}
|
71
|
+
|
72
|
+
function copySourcesContent(sourceMap, options) {
|
73
|
+
sourceMap.get().setSourceContent(options.parse_options.filename, options.source);
|
74
|
+
|
75
|
+
var original = options.source_map_options.orig;
|
76
|
+
|
77
|
+
if (original && original.sources && original.sourcesContent) {
|
78
|
+
for(var i = 0; i < original.sources.length; i++) {
|
79
|
+
sourceMap.get().setSourceContent(original.sources[i], original.sourcesContent[i]);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
function uglifier(options) {
|
85
|
+
var source = options.source;
|
86
|
+
var ast = parse(source, options);
|
87
|
+
var source_map;
|
88
|
+
|
89
|
+
var gen_code_options = options.output;
|
90
|
+
gen_code_options.comments = comments(options.output.comments);
|
91
|
+
|
92
|
+
if (options.generate_map) {
|
93
|
+
source_map = UglifyJS.SourceMap(options.source_map_options);
|
94
|
+
gen_code_options.source_map = source_map;
|
95
|
+
|
96
|
+
if (options.source_map_options.sources_content) {
|
97
|
+
copySourcesContent(source_map, options);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
var stream = UglifyJS.OutputStream(gen_code_options);
|
102
|
+
ast.print(stream);
|
103
|
+
|
104
|
+
if (options.source_map_options.map_url) {
|
105
|
+
stream += "\n//# sourceMappingURL=" + options.source_map_options.map_url;
|
106
|
+
}
|
107
|
+
|
108
|
+
if (options.source_map_options.url) {
|
109
|
+
stream += "\n//# sourceURL=" + options.source_map_options.url;
|
110
|
+
}
|
111
|
+
|
112
|
+
if (options.generate_map) {
|
113
|
+
if (options.source_map_options.sources_content) {
|
114
|
+
source_map.get().setSourceContent(options.parse_options.filename, options.source);
|
115
|
+
}
|
116
|
+
return [stream.toString(), source_map.toString()];
|
117
|
+
} else {
|
118
|
+
return stream.toString();
|
119
|
+
}
|
120
|
+
}
|
data/lib/uglifier.rb
CHANGED
@@ -1,85 +1,25 @@
|
|
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__)
|
15
|
+
# Source Map path
|
16
|
+
SourceMapPath = File.expand_path("../source-map.js", __FILE__)
|
79
17
|
# ES5 shims source path
|
80
18
|
ES5FallbackPath = File.expand_path("../es5.js", __FILE__)
|
81
19
|
# String.split shim source path
|
82
20
|
SplitFallbackPath = File.expand_path("../split.js", __FILE__)
|
21
|
+
# UglifyJS wrapper path
|
22
|
+
UglifyJSWrapperPath = File.expand_path("../uglifier.js", __FILE__)
|
83
23
|
|
84
24
|
# Default options for compilation
|
85
25
|
DEFAULTS = {
|
@@ -98,48 +38,75 @@ class Uglifier
|
|
98
38
|
:indent_start => 0, # Starting indent level
|
99
39
|
:space_colon => false, # Insert space before colons (only with beautifier)
|
100
40
|
:width => 80, # Specify line width when beautifier is used (only with beautifier)
|
101
|
-
:preamble => nil # Preamble for the generated JS file. Can be used to insert any code or comment.
|
41
|
+
:preamble => nil, # Preamble for the generated JS file. Can be used to insert any code or comment.
|
42
|
+
:wrap_iife => false # Wrap IIFEs in parenthesis. Note: this disables the negate_iife compression option.
|
102
43
|
},
|
103
44
|
:mangle => {
|
104
45
|
:eval => false, # Mangle names when eval of when is used in scope
|
105
46
|
:except => ["$super"], # Argument names to be excluded from mangling
|
106
47
|
: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
|
48
|
+
:toplevel => false, # Mangle names declared in the toplevel scope
|
49
|
+
:properties => false, # Mangle property names
|
50
|
+
:keep_fnames => false # Do not modify function names
|
108
51
|
}, # Mangle variable and function names, set to false to skip mangling
|
52
|
+
:mangle_properties => false, # Mangle property names
|
109
53
|
:compress => {
|
110
54
|
:sequences => true, # Allow statements to be joined by commas
|
111
55
|
:properties => true, # Rewrite property access using the dot notation
|
112
56
|
:dead_code => true, # Remove unreachable code
|
113
57
|
:drop_debugger => true, # Remove debugger; statements
|
114
58
|
:unsafe => false, # Apply "unsafe" transformations
|
59
|
+
:unsafe_comps => false, # Reverse < and <= to > and >= to allow improved compression. This might be unsafe when an at least one of two operands is an object with computed values due the use of methods like get, or valueOf. This could cause change in execution order after operands in the comparison are switching. Compression only works if both comparisons and unsafe_comps are both set to true.
|
60
|
+
:unsafe_proto => false, # Optimize expressions like Array.prototype.slice.call(a) into [].slice.call(a)
|
115
61
|
:conditionals => true, # Optimize for if-s and conditional expressions
|
116
62
|
:comparisons => true, # Apply binary node optimizations for comparisons
|
117
63
|
:evaluate => true, # Attempt to evaluate constant expressions
|
118
64
|
:booleans => true, # Various optimizations to boolean contexts
|
119
65
|
:loops => true, # Optimize loops when condition can be statically determined
|
120
|
-
:unused => true, # Drop unreferenced functions and variables
|
66
|
+
:unused => true, # Drop unreferenced functions and variables (simple direct variable assignments do not count as references unless set to `"keep_assign"`)
|
67
|
+
:toplevel => false, # Drop unreferenced top-level functions and variables
|
68
|
+
:top_retain => [], # prevent specific toplevel functions and variables from `unused` removal
|
121
69
|
:hoist_funs => true, # Hoist function declarations
|
122
70
|
:hoist_vars => false, # Hoist var declarations
|
123
71
|
:if_return => true, # Optimizations for if/return and if/continue
|
124
72
|
:join_vars => true, # Join consecutive var statements
|
125
73
|
:cascade => true, # Cascade sequences
|
74
|
+
:collapse_vars => true, # Collapse single-use var and const definitions when possible.
|
75
|
+
:reduce_vars => false, # Collapse variables assigned with and used as constant values.
|
126
76
|
:negate_iife => true, # Negate immediately invoked function expressions to avoid extra parens
|
127
77
|
:pure_getters => false, # Assume that object property access does not have any side-effects
|
128
78
|
:pure_funcs => nil, # List of functions without side-effects. Can safely discard function calls when the result value is not used
|
129
79
|
:drop_console => false, # Drop calls to console.* functions
|
130
80
|
:angular => false, # Process @ngInject annotations
|
131
|
-
:keep_fargs => false # Preserve unused function arguments
|
81
|
+
:keep_fargs => false, # Preserve unused function arguments
|
82
|
+
:keep_fnames => false, # Do not drop names in function definitions
|
83
|
+
:passes => 1 # Number of times to run compress. Raising the number of passes will increase compress time, but can produce slightly smaller code.
|
132
84
|
}, # Apply transformations to code, set to false to skip
|
133
85
|
:define => {}, # Define values for symbol replacement
|
134
86
|
:enclose => false, # Enclose in output function wrapper, define replacements as key-value pairs
|
135
|
-
:
|
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
|
87
|
+
:keep_fnames => false, # Generate code safe for the poor souls relying on Function.prototype.name at run-time. Sets both compress and mangle keep_fanems to true.
|
139
88
|
:screw_ie8 => false, # Don't bother to generate safe code for IE8
|
140
|
-
:
|
141
|
-
|
89
|
+
:source_map => false # Generate source map
|
90
|
+
}
|
91
|
+
|
92
|
+
LEGACY_OPTIONS = [:comments, :squeeze, :copyright, :mangle]
|
93
|
+
|
94
|
+
MANGLE_PROPERTIES_DEFAULTS = {
|
95
|
+
:regex => nil, # A regular expression to filter property names to be mangled
|
96
|
+
:ignore_quoted => false, # Only mangle unquoted property names
|
97
|
+
:debug => false # Mangle names with the original name still present
|
142
98
|
}
|
99
|
+
|
100
|
+
SOURCE_MAP_DEFAULTS = {
|
101
|
+
:map_url => false, # Url for source mapping to be appended in minified source
|
102
|
+
:url => false, # Url for original source to be appended in minified source
|
103
|
+
:sources_content => false, # Include original source content in map
|
104
|
+
:filename => nil, # The filename of the input file
|
105
|
+
:root => nil, # The URL of the directory which contains :filename
|
106
|
+
:output_filename => nil, # The filename or URL where the minified output can be found
|
107
|
+
:input_source_map => nil # The contents of the source map describing the input
|
108
|
+
}
|
109
|
+
|
143
110
|
# rubocop:enable LineLength
|
144
111
|
|
145
112
|
# Minifies JavaScript code using implicit context.
|
@@ -164,7 +131,7 @@ class Uglifier
|
|
164
131
|
#
|
165
132
|
# @param options [Hash] optional overrides to +Uglifier::DEFAULTS+
|
166
133
|
def initialize(options = {})
|
167
|
-
(options.keys - DEFAULTS.keys -
|
134
|
+
(options.keys - DEFAULTS.keys - LEGACY_OPTIONS)[0..1].each do |missing|
|
168
135
|
raise ArgumentError, "Invalid option: #{missing}"
|
169
136
|
end
|
170
137
|
@options = options
|
@@ -176,7 +143,14 @@ class Uglifier
|
|
176
143
|
# @param source [IO, String] valid JS source code.
|
177
144
|
# @return [String] minified code.
|
178
145
|
def compile(source)
|
179
|
-
|
146
|
+
if @options[:source_map]
|
147
|
+
compiled, source_map = run_uglifyjs(source, true)
|
148
|
+
source_map_uri = Base64.strict_encode64(source_map)
|
149
|
+
source_map_mime = "application/json;charset=utf-8;base64"
|
150
|
+
compiled + "\n//# sourceMappingURL=data:#{source_map_mime},#{source_map_uri}"
|
151
|
+
else
|
152
|
+
run_uglifyjs(source, false)
|
153
|
+
end
|
180
154
|
end
|
181
155
|
alias_method :compress, :compile
|
182
156
|
|
@@ -191,25 +165,29 @@ class Uglifier
|
|
191
165
|
private
|
192
166
|
|
193
167
|
def uglifyjs_source
|
194
|
-
[ES5FallbackPath, SplitFallbackPath, SourcePath
|
195
|
-
|
168
|
+
[ES5FallbackPath, SplitFallbackPath, SourceMapPath, SourcePath,
|
169
|
+
UglifyJSWrapperPath].map do |file|
|
170
|
+
File.open(file, "r:UTF-8", &:read)
|
196
171
|
end.join("\n")
|
197
172
|
end
|
198
173
|
|
199
174
|
# Run UglifyJS for given source code
|
200
|
-
def run_uglifyjs(
|
175
|
+
def run_uglifyjs(input, generate_map)
|
176
|
+
source = read_source(input)
|
177
|
+
input_map = input_source_map(source, generate_map)
|
201
178
|
options = {
|
202
|
-
:source =>
|
179
|
+
:source => source,
|
203
180
|
:output => output_options,
|
204
181
|
:compress => compressor_options,
|
205
182
|
:mangle => mangle_options,
|
183
|
+
:mangle_properties => mangle_properties_options,
|
206
184
|
:parse_options => parse_options,
|
207
|
-
:source_map_options => source_map_options,
|
185
|
+
:source_map_options => source_map_options(input_map),
|
208
186
|
:generate_map => generate_map,
|
209
187
|
:enclose => enclose_options
|
210
188
|
}
|
211
189
|
|
212
|
-
@context.call(
|
190
|
+
@context.call("uglifier", options)
|
213
191
|
end
|
214
192
|
|
215
193
|
def read_source(source)
|
@@ -221,16 +199,49 @@ class Uglifier
|
|
221
199
|
end
|
222
200
|
|
223
201
|
def mangle_options
|
224
|
-
conditional_option(
|
202
|
+
defaults = conditional_option(
|
203
|
+
DEFAULTS[:mangle],
|
204
|
+
:keep_fnames => keep_fnames?(:mangle)
|
205
|
+
)
|
206
|
+
|
207
|
+
conditional_option(
|
208
|
+
@options.fetch(:mangle, DEFAULTS[:mangle]),
|
209
|
+
defaults,
|
210
|
+
:keep_fnames => keep_fnames?(:mangle)
|
211
|
+
)
|
212
|
+
end
|
213
|
+
|
214
|
+
def mangle_properties_options
|
215
|
+
mangle_options = @options.fetch(:mangle_properties, DEFAULTS[:mangle_properties])
|
216
|
+
options = conditional_option(mangle_options, MANGLE_PROPERTIES_DEFAULTS)
|
217
|
+
if options && options[:regex]
|
218
|
+
options.merge(:regex => encode_regexp(options[:regex]))
|
219
|
+
else
|
220
|
+
options
|
221
|
+
end
|
225
222
|
end
|
226
223
|
|
227
224
|
def compressor_options
|
228
225
|
defaults = conditional_option(
|
229
226
|
DEFAULTS[:compress],
|
230
227
|
:global_defs => @options[:define] || {},
|
231
|
-
:screw_ie8 =>
|
228
|
+
:screw_ie8 => screw_ie8?
|
229
|
+
)
|
230
|
+
|
231
|
+
conditional_option(
|
232
|
+
@options[:compress] || @options[:squeeze],
|
233
|
+
defaults,
|
234
|
+
{ :keep_fnames => keep_fnames?(:compress) }.merge(negate_iife_block)
|
232
235
|
)
|
233
|
-
|
236
|
+
end
|
237
|
+
|
238
|
+
# Prevent negate_iife when wrap_iife is true
|
239
|
+
def negate_iife_block
|
240
|
+
if output_options[:wrap_iife]
|
241
|
+
{ :negate_iife => false }
|
242
|
+
else
|
243
|
+
{}
|
244
|
+
end
|
234
245
|
end
|
235
246
|
|
236
247
|
def comment_options
|
@@ -269,24 +280,40 @@ class Uglifier
|
|
269
280
|
|
270
281
|
def screw_ie8?
|
271
282
|
if (@options[:output] || {}).has_key?(:ie_proof)
|
272
|
-
|
283
|
+
!@options[:output][:ie_proof]
|
273
284
|
else
|
274
|
-
@options
|
285
|
+
@options.fetch(:screw_ie8, DEFAULTS[:screw_ie8])
|
275
286
|
end
|
276
287
|
end
|
277
288
|
|
278
|
-
def
|
289
|
+
def keep_fnames?(type)
|
290
|
+
if @options[:keep_fnames] || DEFAULTS[:keep_fnames]
|
291
|
+
true
|
292
|
+
else
|
293
|
+
@options[type].respond_to?(:[]) && @options[type][:keep_fnames] ||
|
294
|
+
DEFAULTS[type].respond_to?(:[]) && DEFAULTS[type][:keep_fnames]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def source_map_options(input_map)
|
299
|
+
options = conditional_option(@options[:source_map], SOURCE_MAP_DEFAULTS) || SOURCE_MAP_DEFAULTS
|
300
|
+
|
279
301
|
{
|
280
|
-
:file =>
|
281
|
-
:root =>
|
282
|
-
:orig =>
|
283
|
-
:map_url =>
|
284
|
-
:url =>
|
302
|
+
:file => options[:output_filename],
|
303
|
+
:root => options.fetch(:root) { input_map ? input_map["sourceRoot"] : nil },
|
304
|
+
:orig => input_map,
|
305
|
+
:map_url => options[:map_url],
|
306
|
+
:url => options[:url],
|
307
|
+
:sources_content => options[:sources_content]
|
285
308
|
}
|
286
309
|
end
|
287
310
|
|
288
311
|
def parse_options
|
289
|
-
|
312
|
+
if @options[:source_map].respond_to?(:[])
|
313
|
+
{ :filename => @options[:source_map][:filename] }
|
314
|
+
else
|
315
|
+
{}
|
316
|
+
end
|
290
317
|
end
|
291
318
|
|
292
319
|
def enclose_options
|
@@ -309,13 +336,48 @@ class Uglifier
|
|
309
336
|
[regexp.source, modifiers]
|
310
337
|
end
|
311
338
|
|
312
|
-
def conditional_option(value, defaults)
|
339
|
+
def conditional_option(value, defaults, overrides = {})
|
313
340
|
if value == true || value.nil?
|
314
|
-
defaults
|
341
|
+
defaults.merge(overrides)
|
315
342
|
elsif value
|
316
|
-
defaults.merge(value)
|
343
|
+
defaults.merge(value).merge(overrides)
|
317
344
|
else
|
318
345
|
false
|
319
346
|
end
|
320
347
|
end
|
348
|
+
|
349
|
+
def sanitize_map_root(map)
|
350
|
+
if map.nil?
|
351
|
+
nil
|
352
|
+
elsif map.is_a? String
|
353
|
+
sanitize_map_root(JSON.parse(map))
|
354
|
+
elsif map["sourceRoot"] == ""
|
355
|
+
map.merge("sourceRoot" => nil)
|
356
|
+
else
|
357
|
+
map
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def extract_source_mapping_url(source)
|
362
|
+
comment_start = %r{(?://|/\*\s*)}
|
363
|
+
comment_end = %r{\s*(?:\r?\n?\*/|$)?}
|
364
|
+
source_mapping_regex = /#{comment_start}[@#]\ssourceMappingURL=\s*(\S*?)#{comment_end}/
|
365
|
+
rest = /\s#{comment_start}[@#]\s[a-zA-Z]+=\s*(?:\S*?)#{comment_end}/
|
366
|
+
regex = /#{source_mapping_regex}(?:#{rest})*\Z/m
|
367
|
+
match = regex.match(source)
|
368
|
+
match && match[1]
|
369
|
+
end
|
370
|
+
|
371
|
+
def input_source_map(source, generate_map)
|
372
|
+
return nil unless generate_map
|
373
|
+
source_map_options = @options[:source_map].is_a?(Hash) ? @options[:source_map] : {}
|
374
|
+
sanitize_map_root(source_map_options.fetch(:input_source_map) do
|
375
|
+
url = extract_source_mapping_url(source)
|
376
|
+
if url && url.start_with?("data:")
|
377
|
+
Base64.strict_decode64(url.split(",", 2)[-1])
|
378
|
+
end
|
379
|
+
end)
|
380
|
+
rescue ArgumentError, JSON::ParserError
|
381
|
+
nil
|
382
|
+
end
|
321
383
|
end
|