Loading lib/jsduck/esprima_parser.rb +37 −7 Original line number Diff line number Diff line Loading @@ -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 Loading spec/esprima_parser_spec.rb +73 −1 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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) Loading Loading
lib/jsduck/esprima_parser.rb +37 −7 Original line number Diff line number Diff line Loading @@ -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 Loading
spec/esprima_parser_spec.rb +73 −1 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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) Loading