Class: Opal::Optimizer

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/opal/optimizer.rb,
lib/opal/optimizer/step.rb,
lib/opal/optimizer/helpers.rb,
lib/opal/optimizer/version.rb,
lib/opal/optimizer/sprockets.rb,
lib/opal/optimizer/step/tree_shaking.rb,
lib/opal/optimizer/step/collapse_stubs.rb

Defined Under Namespace

Modules: Helpers, Sprockets Classes: NonOpalArgumentError, Step

Constant Summary collapse

VERSION =
"0.1.8"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#parse_js

Constructor Details

#initialize(code, exports: "", force_corelib: true) ⇒ Optimizer

Returns a new instance of Optimizer.

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/opal/optimizer.rb', line 17

def initialize(code, exports: "", force_corelib: true)
  if force_corelib
    unless code.include? "//   A few conventions for the documentation of this file:"
      raise NonOpalArgumentError, "A non-Opal code provided"
    end
  end

  @ast = parse_js(code)

  @corelib = @ast.value.find do |i|
    es = code[i.range.from.index..i.range.to.index]
    if es.start_with?("(function(undefined) {\n  // @note\n"\
                      "  //   A few conventions for the documentation of this file:") &&
       es.end_with?("TypeError.$$super = Error;\n}).call(this);")
      @opal_version = 1.0
    elsif es.start_with?("(function(global_object) {\n  \"use strict\";\n\n  // @note\n  "\
                         "//   A few conventions for the documentation of this file:")
      if es.end_with?("TypeError.$$super = Error;\n}).call(this);")
        if es.include? 'function $prop(object,'
          @opal_version = 1.4
        else
          @opal_version = 1.1
        end
      elsif es.end_with?("Opal.file_sources = {};\n}).call(this);")
        @opal_version = 1.6
      end
    end
  end

  raise ArgumentError, "Couldn't deduce Opal version based on this content" if force_corelib && !@corelib

  @corelib_source = @corelib.value.value.value.value.function_body.value if @corelib

  reload

  # Are exports js or do we need to compile them first?
  unless [nil, ""].include?(exports) || exports.start_with?("(function(")
    exports = Opal::Compiler.new(exports).compile
  end
  @exports = Opal::Optimizer.new(exports, exports: nil, force_corelib: false) unless exports == nil
end

Instance Attribute Details

#astObject

Returns the value of attribute ast.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def ast
  @ast
end

#corelibObject

Returns the value of attribute corelib.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def corelib
  @corelib
end

#corelib_callsObject

Returns the value of attribute corelib_calls.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def corelib_calls
  @corelib_calls
end

#corelib_sourceObject

Returns the value of attribute corelib_source.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def corelib_source
  @corelib_source
end

#exportsObject

Returns the value of attribute exports.



15
16
17
# File 'lib/opal/optimizer.rb', line 15

def exports
  @exports
end

#function_callsObject

Returns the value of attribute function_calls.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def function_calls
  @function_calls
end

#opal_versionObject

Returns the value of attribute opal_version.



12
13
14
# File 'lib/opal/optimizer.rb', line 12

def opal_version
  @opal_version
end

Instance Method Details

#optimizeObject



68
69
70
71
72
73
# File 'lib/opal/optimizer.rb', line 68

def optimize
  Step::TreeShaking.new(self).run
  Step::CollapseStubs.new(self).run

  @ast.to_ecma
end

#reloadObject



59
60
61
62
63
64
65
66
# File 'lib/opal/optimizer.rb', line 59

def reload
  @function_calls = ast.pointcut(FunctionCallNode).matches
  @corelib_calls = @function_calls.select do |i|
    i.value_path?(DotAccessorNode, ResolveNode, "Opal") ||
    i.value_path?(ResolveNode, /\A\$/)
  end.group_by { |i| (i.value.value.is_a?(String) ? i.value.value : i.value.accessor).gsub('$', '') }
  @corelib_calls = Hash.new { [] }.merge(@corelib_calls)
end