Loading lib/jsduck/doc_formatter.rb +5 −3 Original line number Diff line number Diff line Loading @@ -110,13 +110,15 @@ module JsDuck # There might still be "{" that doesn't begin {@link} or {@img} - ignore it out += s.scan(/[{]/) elsif substitute = @inline_example.replace(s) tags.push_tag("pre") tags.push_tag("code") out += substitute elsif s.check(/<\w/) # Open HTML tag out += s.scan(/</) + tags.open(s.scan(/\w+/)) + s.scan_until(/>|\Z/) out += tags.open(s) elsif s.check(/<\/\w+>/) # Close HTML tag out += s.scan(/<\//) + tags.close(s.scan(/\w+/)) + s.scan(/>/) out += tags.close(s) elsif s.check(/</) # Ignore plain '<' char. out += s.scan(/</) Loading @@ -128,7 +130,7 @@ module JsDuck end end out + tags.close_unfinished out end # Creates a link based on the link template. Loading lib/jsduck/html_stack.rb +46 −32 Original line number Diff line number Diff line Loading @@ -4,18 +4,6 @@ module JsDuck # Tracks opening and closing of HTML tags, with the purpose of # closing down the unfinished tags. # # Synopsis: # # tags = HtmlStack.new # # open and close a bunch of tags # tags.open("a") # tags.open("b") # tags.close("b") # # # ask which tags still need to be closed # tags.close_unfinished --> "</a>" # class HtmlStack # Initializes the stack with two optional parameters: Loading @@ -28,18 +16,23 @@ module JsDuck @open_tags = [] end # Registers opening of a tag. Returns the tag. def open(tag) @open_tags.unshift(tag) unless void?(tag) tag # Scans an opening tag in HTML using the passed in StringScanner. def open(s) s.scan(/</) + push_tag(s.scan(/\w+/)) + s.scan_until(/>|\Z/) end # Registers closing of a tag. Returns the tag. def close(tag) if @open_tags.include?(tag) # delete the most recent unclosed tag in our tags stack @open_tags.delete_at(@open_tags.index(tag)) # Scans a closing tag in HTML using the passed in StringScanner. def close(s) s.scan(/<\//) tag = s.scan(/\w+/) s.scan(/>/) pop_tags(tag).map {|t| "</#{t}>" }.join end # Registers opening of a tag. Returns the tag. def push_tag(tag) @open_tags.push(tag) unless void?(tag) tag end Loading @@ -48,22 +41,43 @@ module JsDuck @open_tags.include?(tag) end # Returns HTML for closing the still open tags. # Also prints warnings for all the unclosed tags. def close_unfinished return "" if @open_tags.length == 0 private warn_unfinished # Registers closing of a tag. Returns all the tags that need to # be closed at that point. def pop_tags(tag) if !@open_tags.include?(tag) if @ignore_html[tag] return [tag] else warn_unopened(tag) return [] end end @open_tags.map {|tag| "</#{tag}>" }.join popped = [] begin popped << t = @open_tags.pop if t != tag warn_unclosed(t) end end until t == tag private popped end def warn_unopened(*tags) warn("Unopened HTML tag", tags) end def warn_unclosed(*tags) warn("Unclosed HTML tag", tags) end def warn_unfinished def warn(msg, tags) ctx = @doc_context tag_list = @open_tags.map {|tag| "<#{tag}>" }.join(", ") Logger.warn(:html, "Unclosed HTML tag: #{tag_list}", ctx[:filename], ctx[:linenr]) tag_list = tags.map {|tag| "<#{tag}>" }.join(", ") Logger.warn(:html, "#{msg}: #{tag_list}", ctx[:filename], ctx[:linenr]) end def void?(tag) Loading spec/doc_formatter_spec.rb +13 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,19 @@ describe JsDuck::DocFormatter do @formatter.format("<img>").should_not =~ /<\/img>/ end it "closes unclosed <b> when closing of <a> is encountered." do @formatter.format("<a><b>blah</a>").should =~ Regexp.new("</b></a>") end it "throws away excessive close tags" do @formatter.format("blah</div>").should_not =~ Regexp.new("</div>") end it "allows for p-s nested inside divs" do @formatter.format("<div><small><p>Blah</p><p>Fah</p></small></div>").should =~ Regexp.new("<div><small><p>Blah</p><p>Fah</p></small></div>") end shared_examples_for "code blocks" do it "contains text before" do @html.should =~ /Some code/ Loading Loading
lib/jsduck/doc_formatter.rb +5 −3 Original line number Diff line number Diff line Loading @@ -110,13 +110,15 @@ module JsDuck # There might still be "{" that doesn't begin {@link} or {@img} - ignore it out += s.scan(/[{]/) elsif substitute = @inline_example.replace(s) tags.push_tag("pre") tags.push_tag("code") out += substitute elsif s.check(/<\w/) # Open HTML tag out += s.scan(/</) + tags.open(s.scan(/\w+/)) + s.scan_until(/>|\Z/) out += tags.open(s) elsif s.check(/<\/\w+>/) # Close HTML tag out += s.scan(/<\//) + tags.close(s.scan(/\w+/)) + s.scan(/>/) out += tags.close(s) elsif s.check(/</) # Ignore plain '<' char. out += s.scan(/</) Loading @@ -128,7 +130,7 @@ module JsDuck end end out + tags.close_unfinished out end # Creates a link based on the link template. Loading
lib/jsduck/html_stack.rb +46 −32 Original line number Diff line number Diff line Loading @@ -4,18 +4,6 @@ module JsDuck # Tracks opening and closing of HTML tags, with the purpose of # closing down the unfinished tags. # # Synopsis: # # tags = HtmlStack.new # # open and close a bunch of tags # tags.open("a") # tags.open("b") # tags.close("b") # # # ask which tags still need to be closed # tags.close_unfinished --> "</a>" # class HtmlStack # Initializes the stack with two optional parameters: Loading @@ -28,18 +16,23 @@ module JsDuck @open_tags = [] end # Registers opening of a tag. Returns the tag. def open(tag) @open_tags.unshift(tag) unless void?(tag) tag # Scans an opening tag in HTML using the passed in StringScanner. def open(s) s.scan(/</) + push_tag(s.scan(/\w+/)) + s.scan_until(/>|\Z/) end # Registers closing of a tag. Returns the tag. def close(tag) if @open_tags.include?(tag) # delete the most recent unclosed tag in our tags stack @open_tags.delete_at(@open_tags.index(tag)) # Scans a closing tag in HTML using the passed in StringScanner. def close(s) s.scan(/<\//) tag = s.scan(/\w+/) s.scan(/>/) pop_tags(tag).map {|t| "</#{t}>" }.join end # Registers opening of a tag. Returns the tag. def push_tag(tag) @open_tags.push(tag) unless void?(tag) tag end Loading @@ -48,22 +41,43 @@ module JsDuck @open_tags.include?(tag) end # Returns HTML for closing the still open tags. # Also prints warnings for all the unclosed tags. def close_unfinished return "" if @open_tags.length == 0 private warn_unfinished # Registers closing of a tag. Returns all the tags that need to # be closed at that point. def pop_tags(tag) if !@open_tags.include?(tag) if @ignore_html[tag] return [tag] else warn_unopened(tag) return [] end end @open_tags.map {|tag| "</#{tag}>" }.join popped = [] begin popped << t = @open_tags.pop if t != tag warn_unclosed(t) end end until t == tag private popped end def warn_unopened(*tags) warn("Unopened HTML tag", tags) end def warn_unclosed(*tags) warn("Unclosed HTML tag", tags) end def warn_unfinished def warn(msg, tags) ctx = @doc_context tag_list = @open_tags.map {|tag| "<#{tag}>" }.join(", ") Logger.warn(:html, "Unclosed HTML tag: #{tag_list}", ctx[:filename], ctx[:linenr]) tag_list = tags.map {|tag| "<#{tag}>" }.join(", ") Logger.warn(:html, "#{msg}: #{tag_list}", ctx[:filename], ctx[:linenr]) end def void?(tag) Loading
spec/doc_formatter_spec.rb +13 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,19 @@ describe JsDuck::DocFormatter do @formatter.format("<img>").should_not =~ /<\/img>/ end it "closes unclosed <b> when closing of <a> is encountered." do @formatter.format("<a><b>blah</a>").should =~ Regexp.new("</b></a>") end it "throws away excessive close tags" do @formatter.format("blah</div>").should_not =~ Regexp.new("</div>") end it "allows for p-s nested inside divs" do @formatter.format("<div><small><p>Blah</p><p>Fah</p></small></div>").should =~ Regexp.new("<div><small><p>Blah</p><p>Fah</p></small></div>") end shared_examples_for "code blocks" do it "contains text before" do @html.should =~ /Some code/ Loading