class Closure::Compiler::Util
Closure
Script
extends compiler.jar by transforming the arguments in novel ways. The most obvious augmentation is to support –ns for compiling namespaces. We can also expand paths to a new base, work with modules, and much more. These all will directly modify args. @private This is a high value target for refactoring in minor version updates.
Public Class Methods
Extracts the values for a options in the arguments. Use Array#last to emulate compiler.jar for single options. Will collect from an array of options. @param [Array<String>] args @param [String|Array<String>] options One or more options. @return [Array<String>]
# File lib/closure/compiler.rb, line 248 def self.arg_values(args, options) options = [options].flatten unless options.kind_of? Array values = [] args_index = 0 while args_index < args.length if options.include? args[args_index] values << args[args_index+1] end args_index = args_index + 2 end values end
Main function to convert –ns arguments into –js arguments. Returns module info when modules are processed. @param [Array<String>] args @return [Array<Hash>] mods
# File lib/closure/compiler.rb, line 231 def self.augment(args, sources, env={}) mods = extract_modules args if mods module_augment args, sources, mods, env else namespace_augment args, sources, [], env end mods end
Expands all filesystem argument values to a specified folder. @param [Array<String>] args @return [Array<String>] args
# File lib/closure/compiler.rb, line 169 def self.expand_paths(args, base) file_options = INPUT_OPTIONS + OUTPUT_OPTIONS args_index = 0 while args_index < args.length option, value = args[args_index, 2] value = File.expand_path value, base if file_options.include? option args[args_index+1] = value end args_index = args_index + 2 end args end
The javascript snippet for module info @param [Array<Hash>] mods
# File lib/closure/compiler.rb, line 193 def self.module_info(mods, var = 'MODULE_INFO') js = "var #{var} = {" js += mods.map do |mod| reqs = mod[:requires].map{ |r| r.dump } "#{mod[:name].dump}: [#{reqs.join ', '}]" end.join ', ' js += "};\n" end
The javascript snippet for module info @param [Array<Hash>] mods
# File lib/closure/compiler.rb, line 186 def self.module_path(path, var = 'MODULE_PATH') js = "var #{var} = #{path.dump};\n" end
The javascript snippet for compiled module file locations @param [Array<Hash>] mods
# File lib/closure/compiler.rb, line 217 def self.module_uris_compiled(mods, sources, prefix, var = 'MODULE_URIS') js = "var #{var} = {\n" js += mods.map do |mod| file = sources.src_for prefix + mod[:name] + '.js' "#{mod[:name].dump}: [#{file.dump}]" end.join ",\n" js += "\n};\n" end
The javascript snippet for raw module file locations @param [Array<Hash>] mods
# File lib/closure/compiler.rb, line 205 def self.module_uris_raw(mods, sources, var = 'MODULE_URIS') js = "var #{var} = {\n" js += mods.map do |mod| files = mod[:files].map{ |r| (sources.src_for r).dump } "#{mod[:name].dump}: [\n#{files.join ",\n"}]" end.join ",\n" js += "\n};\n" end
Private Class Methods
@param [Array<String>] args @return [Array<Hash>] mods
# File lib/closure/compiler.rb, line 354 def self.extract_modules(args) found_starred = false found_numeric = false mod_args = [] mods = [] args_index = args.length while args_index > 0 args_index = args_index - 2 option, value = args[args_index, 2] if %w{--js --ns}.include? option mod_args.unshift args.delete_at args_index + 1 mod_args.unshift args.delete_at args_index elsif option == '--module' if mod_args.empty? raise "No --js or --ns files for --module #{value}" end mod = value.split ':' if mod[1] == '*' found_starred = true else found_numeric = true end mods.unshift({ :name => mod[0], :requires => (mod[2]||'').split(','), :args => mod_args }) mod_args = [] 2.times {args.delete_at args_index} end end unless mod_args.empty? or mods.empty? raise 'Automatic --module must appear before first --js or --ns option.' end if found_starred and found_numeric raise 'Static and automatic --module options can not be mixed.' end if mods.empty? args.insert(-1, *mod_args) nil else mods end end
Converts –ns arguments into –js arguments @param [Array<String>] args
# File lib/closure/compiler.rb, line 267 def self.module_augment(args, sources, mods, env) walk_modules sources, mods, env files = [] mods.each do |mod| mod_args = mod[:args] mod_files = (mod[:files] ||= []) # We are adding the bubbled namespaces to the end. # This allows moduleManager.setLoaded to fire earlier # since the bubbled files are needed only for the children. (mod[:bubble]||[]).each do |mod_bubble| namespaces = sources.namespaces_for mod_bubble, env namespaces.each do |ns| mod_args << '--ns' << ns end end namespace_augment(mod_args, sources, files, env) args << '--module' args << "#{mod[:name]}:#{mod_args.size / 2}:#{mod[:requires].join(',')}" mod_args.each_slice(2) do |a,b| args << a << b mod_files << b end end end
Converts –ns arguments into –js arguments @param [Array<String>] args
# File lib/closure/compiler.rb, line 295 def self.namespace_augment(args, sources, files, env) files_index = files.length args_index = 0 while args_index < args.length option, value = args[args_index, 2] if option == '--ns' sources.files_for(value, files, env) replacement = [] while files_index < files.length replacement.push '--js' replacement.push files[files_index] files_index = files_index + 1 end args[args_index, 2] = replacement else args_index = args_index + 2 end end end
Insanity-inducing recursive explorer to find common files in child modules. Try every branch in the tree and bubble up common files as we see them.
# File lib/closure/compiler.rb, line 318 def self.walk_modules(sources, mods, env, seek=nil, mods_seen=[], files_seen=[]) files = [] mods_seen << seek mods.each do |mod| if (!seek and mod[:requires].empty?) or mod[:requires].include? seek next if mods_seen.include? mod[:name] # Find the needed files for this module's --ns args files_seen_dup = files_seen.dup mod[:args].each_slice(2) do |option, value| if option == '--ns' sources.files_for value, files_seen_dup, env end end mod_files = files_seen_dup[files_seen.size..-1] # Get the needed files for each of the modules requiring this mod files_sets = walk_modules sources, mods, env, mod[:name], mods_seen, files_seen_dup # Find the common files that will bubble up common_files = [] child_files = files_sets.reduce([]){|memo, v|common_files |= memo&v; memo|v} mod[:bubble] = common_files # Clear bubbling files from children mods.each do |child_mod| if child_mod[:requires].include? mod[:name] child_mod[:bubble] -= common_files end end # Add to result array files << (mod_files + child_files).uniq end end files end