lib/opal/fragment.rb
# frozen_string_literal: true module Opal # A fragment holds a string of generated javascript that will be written # to the destination. It also keeps hold of the original sexp from which # it was generated. Using this sexp, when writing fragments in order, a # mapping can be created of the original location => target location, # aka, source-maps! # # These are generated by nodes, so will not have to create directly. class Fragment # String of javascript this fragment holds # @return [String] attr_reader :code # Create fragment with javascript code and optional original [Opal::Sexp]. # # @param code [String] javascript code # @param sexp [Opal::Sexp] sexp used for creating fragment def initialize(code, scope, sexp = nil) @code = code.to_s @sexp = sexp @scope = scope end # Inspect the contents of this fragment, f("fooo") def inspect "f(#{@code.inspect})" end def source_map_name_for(sexp) case sexp.type when :top case sexp.meta[:kind] when :require '<top (required)>' when :eval '(eval)' when :main '<main>' end when :begin, :newline, :js_return source_map_name_for(@scope.sexp) if @scope when :iter scope = @scope iters = 1 while scope if scope.class == Nodes::IterNode iters += 1 scope = scope.parent else break end end level = " (#{iters} levels)" if iters > 1 "block#{level} in #{source_map_name_for(scope.sexp)}" when :self 'self' when :module const, = *sexp "<module:#{source_map_name_for(const)}>" when :class const, = *sexp "<class:#{source_map_name_for(const)}>" when :const scope, name = *sexp if !scope || scope.type == :cbase name.to_s else "#{source_map_name_for(scope)}::#{name}" end when :int sexp.children.first when :def sexp.children.first when :defs sexp.children[1] when :send sexp.children[1] when :lvar, :lvasgn, :lvdeclare, :ivar, :ivasgn, :gvar, :cvar, :cvasgn, :gvars, :gvasgn, :arg sexp.children.first when :str, :xstr # Inside xstr - JS calls source_map_name_for(@scope.sexp) else # nil end end def source_map_name return nil unless @sexp source_map_name_for(@sexp) end def location case when !@sexp nil when @sexp.type == :send loc = @sexp.loc if loc.respond_to? :dot # a>.b || a>+b / >a / a>[b] loc.dot || loc.selector elsif loc.respond_to? :operator # a >|= b loc.operator else @sexp end when @sexp.type == :iter if loc.respond_to? :begin @sexp.loc.begin # [1,2].each >{ } else @sexp end else @sexp end end # Original line this fragment was created from # @return [Integer, nil] def line location&.line end # Original column this fragment was created from # @return [Integer, nil] def column location&.column end def skip_source_map? @sexp == false end end end