Commit faf8db38 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Merge better dependencies info branch to master.

parents 905372b5 ded1ba47
Loading
Loading
Loading
Loading
+52 −9
Original line number Diff line number Diff line
@@ -8,8 +8,16 @@ module JsDuck
  class Class
    attr_accessor :relations

    def initialize(doc)
    # Creates JSDuck class.
    #
    # Pass true as second parameter to create a placeholder class.
    def initialize(doc, class_exists=true)
      @doc = doc

      # Wrap classname into custom string class that allows
      # differenciating between existing and missing classes.
      @doc[:name] = ClassNameString.new(@doc[:name], class_exists)

      @doc[:members] = Class.default_members_hash if !@doc[:members]
      @doc[:statics] = Class.default_members_hash if !@doc[:statics]
      @relations = nil
@@ -44,15 +52,25 @@ module JsDuck
      p ? p.superclasses + [p]  : []
    end

    # Returns array of mixin class instances.
    # Returns empty array if no mixins
    # Returns all direct mixins of this class. Same as #deps(:mixins).
    def mixins
      @doc[:mixins] ? @doc[:mixins].collect {|classname| lookup(classname) }.compact : []
      deps(:mixins)
    end

    # Returns an array of class instances this class directly depends on.
    # Possible types are:
    #
    # - :mixins
    # - :requires
    # - :uses
    #
    def deps(type)
      @doc[type] ? @doc[type].collect {|classname| lookup(classname) } : []
    end

    # Returns all mixins this class and its parent classes
    def all_mixins
      mixins + (parent ? parent.all_mixins : [])
    # Same ase #deps, but pulls out the dependencies from all parent classes.
    def parent_deps(type)
      parent ? parent.deps(type) + parent.parent_deps(type) : []
    end

    # Looks up class object by name
@@ -60,10 +78,18 @@ module JsDuck
    def lookup(classname)
      if @relations[classname]
        @relations[classname]
      elsif !@relations.ignore?(classname)
      elsif @relations.ignore?(classname) || classname =~ /\*/
        # Ignore explicitly ignored classes and classnames with
        # wildcards in them.  We could expand the wildcard, but that
        # can result in a very long list of classes, like when
        # somebody requires 'Ext.form.*', so for now we do the
        # simplest thing and ignore it.
        Class.new({:name => classname}, false)
      else
        context = @doc[:files][0]
        Logger.instance.warn(:extend, "Class #{classname} not found", context[:filename], context[:linenr])
        nil
        # Create placeholder class
        Class.new({:name => classname}, false)
      end
    end

@@ -276,4 +302,21 @@ module JsDuck
    end
  end

  # String class for classnames that has extra method #exists? which
  # returns false when class with such name doesn't exist.
  #
  # This ability is used by JsDuck::Renderer, which only receives
  # names of various classes but needs to only render existing classes
  # as links.
  class ClassNameString < String
    def initialize(str, exists=true)
      super(str)
      @exists = exists
    end

    def exists?
      @exists
    end
  end

end
+6 −1
Original line number Diff line number Diff line
@@ -20,7 +20,12 @@ module JsDuck
      h[:superclasses] = cls.superclasses.collect {|c| c.full_name }
      h[:subclasses] = @relations.subclasses(cls).collect {|c| c.full_name }
      h[:mixedInto] = @relations.mixed_into(cls).collect {|c| c.full_name }
      h[:allMixins] = cls.all_mixins.collect {|c| c.full_name }

      h[:mixins] = cls.deps(:mixins).collect {|c| c.full_name }
      h[:parentMixins] = cls.parent_deps(:mixins).collect {|c| c.full_name }
      h[:requires] = cls.deps(:requires).collect {|c| c.full_name }
      h[:uses] = cls.deps(:uses).collect {|c| c.full_name }

      h
    end

+1 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ module JsDuck
      @warning_docs = [
        [:global, "Member doesn't belong to any class"],
        [:inheritdoc, "@inheritdoc referring to unknown class or member"],
        [:extend, "@extend or @mixin referring to unknown class"],
        [:extend, "@extend/mixin/requires/uses referring to unknown class"],
        [:link, "{@link} to unknown class or member"],
        [:link_ambiguous, "{@link} is ambiguous"],
        [:link_auto, "Auto-detected link to unknown class or member"],
+13 −14
Original line number Diff line number Diff line
@@ -43,7 +43,8 @@ module JsDuck
      items = [
        render_alternate_class_names,
        render_tree,
        render_dependencies(:allMixins, "Mixins"),
        render_dependencies(:mixins, "Mixins"),
        render_dependencies(:parentMixins, "Inherited mixins"),
        render_dependencies(:requires, "Requires"),
        render_dependencies(:subclasses, "Subclasses"),
        render_dependencies(:mixedInto, "Mixed into"),
@@ -69,7 +70,7 @@ module JsDuck
      return if !@cls[type] || @cls[type].length == 0
      return [
        "<h4>#{title}</h4>",
        @cls[type].sort.map {|name| "<div class='dependency'>#{render_link(name)}</div>" },
        @cls[type].sort.map {|name| "<div class='dependency'>#{name.exists? ? render_link(name) : name}</div>" },
      ]
    end

@@ -90,23 +91,21 @@ module JsDuck
    # We still create the tree, but without links in it.
    def render_tree
      return if !@cls[:extends] || @cls[:extends] == "Object"
      tree = ["<h4>Hierarchy</h4>"]

      if @cls[:superclasses].length > 0
        tree + render_class_tree(@cls[:superclasses].concat([@cls[:name]]), {:first => true, :links => true})
      else
        tree + render_class_tree([@cls[:extends], @cls[:name]], {:first => true})
      end
      return [
        "<h4>Hierarchy</h4>",
        render_class_tree(@cls[:superclasses] + [@cls[:name]])
      ]
    end

    def render_class_tree(superclasses, o)
      return "" if superclasses.length == 0
    def render_class_tree(classes, i=0)
      return "" if classes.length <= i

      name = superclasses[0]
      name = classes[i]
      return [
        "<div class='subclass #{o[:first] ? 'first-child' : ''}'>",
          superclasses.length > 1 ? (o[:links] ? render_link(name) : name) : "<strong>#{name}</strong>",
          render_class_tree(superclasses.slice(1, superclasses.length-1), {:links => o[:links]}),
        "<div class='subclass #{i == 0 ? 'first-child' : ''}'>",
          classes.length-1 == i ? "<strong>#{name}</strong>" : (name.exists? ? render_link(name) : name),
          render_class_tree(classes, i+1),
        "</div>",
      ]
    end