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 +4 -4
- data/.rubocop.yml +6 -0
- data/.travis.yml +9 -8
- data/.yardopts +4 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -5
- data/README.md +19 -10
- data/Rakefile +1 -26
- data/lib/uglifier.js +111 -0
- data/lib/uglifier.rb +109 -93
- data/lib/uglifier/version.rb +1 -1
- data/lib/uglify.js +3015 -2102
- data/spec/source_map_spec.rb +152 -36
- data/spec/spec_helper.rb +11 -2
- data/spec/uglifier_spec.rb +95 -18
- data/uglifier.gemspec +3 -5
- metadata +16 -36
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 965824e428764606cd1617e6e72b9ab0ad912b7b
         | 
| 4 | 
            +
              data.tar.gz: 996b18eac0ad32e9c9ad8b31e7a8ab90c0208039
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d41ff9576c911132ce28f20b530d1c3b925e6caa5416884608e69cbbbe25b1fda4a4a27fb267b320633b6d9bb34c632c9e1c60c5be6b7663309aecb0a17b93df
         | 
| 7 | 
            +
              data.tar.gz: 748763a30cd991eec4c52648c0af2a40ae199646cb92b0dc481ff504b1ef388dbfd385817011ca5489dd4ad5f37d0dff0c6d0e52a39fc41b61be6d859946677a
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    | @@ -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. | 
| 9 | 
            -
              - 2.2. | 
| 10 | 
            -
              -  | 
| 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. | 
| 19 | 
            +
                - rvm: 2.3.0
         | 
| 19 20 | 
             
                  gemfile: gemfiles/rubyracer
         | 
| 20 | 
            -
                - rvm: 2.1. | 
| 21 | 
            +
                - rvm: 2.1.7
         | 
| 21 22 | 
             
                  gemfile: gemfiles/rubyracer
         | 
| 22 23 | 
             
                - rvm: jruby-19mode
         | 
| 23 24 | 
             
                  gemfile: gemfiles/rubyrhino
         | 
| 24 | 
            -
                - rvm: 2. | 
| 25 | 
            +
                - rvm: 2.3.0
         | 
| 25 26 | 
             
                  gemfile: gemfiles/alaska
         | 
| 26 27 | 
             
                  env: ALASKA=1
         | 
| 27 28 | 
             
              allow_failures:
         | 
| 28 | 
            -
                - rvm: 2. | 
| 29 | 
            +
                - rvm: 2.3.0
         | 
| 29 30 | 
             
                  gemfile: gemfiles/alaska
         | 
| 30 31 | 
             
                  env: ALASKA=1
         | 
    
        data/.yardopts
    ADDED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -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
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,7 +1,9 @@ | |
| 1 | 
            -
            # Uglifier | 
| 1 | 
            +
            # Uglifier
         | 
| 2 2 |  | 
| 3 3 | 
             
            Ruby wrapper for [UglifyJS](https://github.com/mishoo/UglifyJS2) JavaScript compressor.
         | 
| 4 4 |  | 
| 5 | 
            +
            [](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 | 
| 90 | 
            -
                :keep_fargs => false | 
| 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 | 
            -
              : | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 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
         | 
    
        data/lib/uglifier.js
    ADDED
    
    | @@ -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 | 
            +
            }
         | 
    
        data/lib/uglifier.rb
    CHANGED
    
    | @@ -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 | 
            -
                : | 
| 141 | 
            -
             | 
| 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 -  | 
| 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 | 
            -
                 | 
| 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" | 
| 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( | 
| 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 =>  | 
| 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( | 
| 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 | 
            -
                 | 
| 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 =>  | 
| 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 | 
            -
                   | 
| 247 | 
            +
                  !@options[:output][:ie_proof]
         | 
| 273 248 | 
             
                else
         | 
| 274 | 
            -
                  @options | 
| 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 =>  | 
| 281 | 
            -
                  :root =>  | 
| 282 | 
            -
                  :orig =>  | 
| 283 | 
            -
                  :map_url =>  | 
| 284 | 
            -
                  :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 | 
            -
                 | 
| 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
         |