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

Merging of consecutive line-comments.

Though I was aftaid, that using String#slice might be slow when Ruby
treats the source code as UTF-8, there seems to be no performance loss.
parent accbe16c
Loading
Loading
Loading
Loading
+37 −7
Original line number Diff line number Diff line
@@ -18,20 +18,50 @@ module JsDuck

    # Input must be a String.
    def parse(input)
      @v8['js'] = input
      @v8['js'] = @input = input

      json = @v8.eval("JSON.stringify(esprima.parse(js, {comment: true, range: true}))")
      @ast = JSON.parse(json, :max_nesting => false)

      link_comments
      @ast["comments"] = merge_comments(@ast["comments"])
      locate_comments
    end

    # Establishes links between comments, so we can easily use
    # comment["next"] to get to the next comment.
    def link_comments
      @ast["comments"].each_with_index do |comment, i|
        comment["next"] = @ast["comments"][i+1]
    # Merges consecutive line-comments and Establishes links between
    # comments, so we can easily use comment["next"] to get to the
    # next comment.
    def merge_comments(original_comments)
      result = []

      comment = original_comments[0]
      i = 0

      while comment
        i += 1
        next_comment = original_comments[i]

        if next_comment && mergeable?(comment, next_comment)
          # Merge next comment to current one
          comment["value"] += "\n" + next_comment["value"]
          comment["range"][1] = next_comment["range"][1]
        else
          # Create a link and continue with next comment
          comment["next"] = next_comment
          result << comment
          comment = next_comment
        end
      end

      result
    end

    # Two comments can be merged if they are both line-comments and
    # they are separated only by whitespace
    def mergeable?(c1, c2)
      if c1["type"] == "Line" && c2["type"] == "Line"
        /\A\s*\Z/ =~ @input.slice((c1["range"][1]+1)..(c2["range"][0]-1))
      else
        false
      end
    end

+73 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ describe JsDuck::EsprimaParser do
    end
  end

  describe "parsing two comments before one function" do
  describe "parsing two block comments before one function" do
    before do
      @docs = parse(<<-EOS)
        /* Function A */
@@ -72,6 +72,78 @@ describe JsDuck::EsprimaParser do
    end
  end

  shared_examples_for "three comments merged" do
    it "finds one comment" do
      @docs.length.should == 1
    end

    it "merges all the line-comments together" do
      @docs[0][:comment].should == " Very\n Long\n Comment"
    end

    it "detects the whole comment as belonging to the function" do
      @docs[0][:code]["type"].should == "FunctionDeclaration"
    end
  end

  describe "parsing three line comments before one function" do
    before do
      @docs = parse(<<-EOS)
        // Very
        // Long
        // Comment
        function b() {
        }
      EOS
    end

    it_should_behave_like "three comments merged"
  end

  describe "parsing two separated line comments before one function" do
    before do
      @docs = parse(<<-EOS)
        // Very

        // Long


        // Comment
        function b() {
        }
      EOS
    end

    it_should_behave_like "three comments merged"
  end

  describe "parsing 2 x two line comments before one function" do
    before do
      @docs = parse(<<-EOS)
        // First
        // Comment for A
        function a() {
        }
        // Second
        // Comment for B
        function b() {
        }
      EOS
    end

    it "finds two comments" do
      @docs.length.should == 2
    end

    it "merges first two line-comments together" do
      @docs[0][:comment].should == " First\n Comment for A"
    end

    it "merges second two line-comments together" do
      @docs[1][:comment].should == " Second\n Comment for B"
    end
  end

  describe "parsing a comment before inner function" do
    before do
      @docs = parse(<<-EOS)