Commit 4632fd01 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Merge branch 'master' into doc-tags

parents 780894b6 9d4658f9
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -118,13 +118,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(/</)
@@ -136,7 +138,7 @@ module JsDuck
          end
        end

        out + tags.close_unfinished
        out
      end

      # Creates a link based on the link template.
+47 −31
Original line number Diff line number Diff line
@@ -6,17 +6,7 @@ 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>"
    #
    # See Format::Doc#replace for the use of this class.
    class HtmlStack

      # Initializes the stack with two optional parameters:
@@ -29,18 +19,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

@@ -49,22 +44,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)
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ require 'jsduck/util/html'
module JsDuck
  module Inline

    # Renders HTML link class or member.
    # Renders HTML link to class or member.
    class LinkRenderer
      # Access to relations object, used by Inline::Link and
      # Inline::AutoLink.
+13 −0
Original line number Diff line number Diff line
@@ -431,6 +431,19 @@ describe JsDuck::Format::Doc 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/