Commit 66730a44 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Implement inheriting docs from parent member.

Simple @inheritdoc tag without any parameters will inherit docs
from parent class member of the same name.
parent ec7f6167
Loading
Loading
Loading
Loading
+41 −20
Original line number Diff line number Diff line
@@ -2,11 +2,13 @@ require 'jsduck/logger'

module JsDuck

  # Deals with inheriting documentation
  class InheritDoc
    def initialize(relations)
      @relations = relations
    end

    # Performs all inheriting
    def resolve_all
      @relations.each do |cls|
        cls.each_member do |member|
@@ -17,38 +19,57 @@ module JsDuck
      end
    end

    # Copy over doc/params/return from original member to new one.
    # Copy over doc/params/return from parent member.
    def resolve(m)
      orig = find_original(m)
      m[:doc] = m[:doc] + "\n\n" + orig[:doc]
      m[:params] = orig[:params] if orig[:params]
      m[:return] = orig[:return] if orig[:return]
      parent = find_parent(m)
      m[:doc] = (m[:doc] + "\n\n" + parent[:doc]).strip
      m[:params] = parent[:params] if parent[:params]
      m[:return] = parent[:return] if parent[:return]
    end

    # Finds the member to which inheritdoc refers to.
    # If the original also happens to alos have @inheritdoc, continue recursively.
    def find_original(m)
    # Finds parent member of the given member.  When @inheritdoc names
    # a member to inherit from, finds that member instead.
    #
    # If the parent also has @inheritdoc, continues recursively.
    def find_parent(m)
      context = m[:files][0]
      inherit = m[:inheritdoc]

      orig = @relations[inherit[:cls]]
      unless orig
        Logger.instance.warn(:inheritdoc, "Class #{inherit[:cls]} not found", context[:filename], context[:linenr])
      if inherit[:cls]
        parent_cls = @relations[inherit[:cls]]
        unless parent_cls
          warn("@inheritdoc #{inherit[:cls]}##{inherit[:member]} - class not found", context)
          return m
        end
      orig = orig.get_member(inherit[:member], inherit[:type] || m[:tagname])
      unless orig
        Logger.instance.warn(:inheritdoc, "Member #{inherit[:cls]}##{inherit[:member]} not found", context[:filename], context[:linenr])
        parent = parent_cls.get_member(inherit[:member], inherit[:type] || m[:tagname])
        unless parent
          warn("@inheritdoc #{inherit[:cls]}##{inherit[:member]} - member not found", context)
          return m
        end
      else
        parent_cls = @relations[m[:owner]].parent
        unless parent_cls
          warn("@inheritdoc - parent class not found", context)
          return m
        end
        parent = parent_cls.get_member(m[:name], m[:tagname])
        unless parent
          warn("@inheritdoc - parent member not found", context)
          return m
        end
      end

      if orig[:inheritdoc]
        find_original(orig)
      if parent[:inheritdoc]
        find_parent(parent)
      else
        orig
        parent
      end
    end

    def warn(msg, context)
      Logger.instance.warn(:inheritdoc, msg, context[:filename], context[:linenr])
    end

  end

end
+78 −0
Original line number Diff line number Diff line
@@ -3,9 +3,14 @@ require "jsduck/source_file"
require "jsduck/class"
require "jsduck/relations"
require "jsduck/inherit_doc"
require "jsduck/logger"

describe JsDuck::Aggregator do

  before do
    JsDuck::Logger.instance.set_warning(:inheritdoc, false)
  end

  def parse(string)
    agr = JsDuck::Aggregator.new
    agr.aggregate(JsDuck::SourceFile.new(string))
@@ -288,5 +293,78 @@ describe JsDuck::Aggregator do
    end
  end

  describe "@inheritdoc without parameter" do
    before do
      @docs = parse(<<-EOF)
        /**
         * @class Parent
         */
          /**
           * @method foo
           * Original comment.
           * @param arg1
           * @param arg2
           * @return {String}
           */

        /**
         * @class Child
         * @extends Parent
         */
          /**
           * @method foo
           * @inheritdoc
           */
      EOF
      @method = @docs["Child"][:members][:method][0]
    end

    it "inherits docs from parent class method" do
      @method[:doc].should == "Original comment."
    end
  end

  describe "@inheritdoc without parent" do
    before do
      @docs = parse(<<-EOF)
        /**
         * @class Child
         */
          /**
           * @method foo
           * @inheritdoc
           */
      EOF
      @method = @docs["Child"][:members][:method][0]
    end

    it "inherits nothing" do
      @method[:doc].should == ""
    end
  end

  describe "@inheritdoc without method in parent" do
    before do
      @docs = parse(<<-EOF)
        /**
         * @class Parent
         */
        /**
         * @class Child
         * @extends Parent
         */
          /**
           * @method foo
           * @inheritdoc
           */
      EOF
      @method = @docs["Child"][:members][:method][0]
    end

    it "inherits nothing" do
      @method[:doc].should == ""
    end
  end

end