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

Reorganize and document DocFormatter.

parent 0cb8c89c
Loading
Loading
Loading
Loading
+65 −41
Original line number Diff line number Diff line
@@ -20,7 +20,8 @@ module JsDuck
  # Unrecognized @tags are left as is into documentation as if they
  # were normal text.
  #
  # @see and {@link} are parsed separately in JsDuck::DocFormatter.
  # @example, {@img}, {@link} and {@video} are parsed separately in
  # JsDuck::DocFormatter.
  #
  class DocParser
    def initialize
@@ -75,17 +76,11 @@ module JsDuck
      @linenr = linenr
      @tags = []
      @input = StringScanner.new(purify(input))

      parse_loop
      # The parsing process can leave whitespace at the ends of
      # doc-strings, here we get rid of it.  Additionally null all empty docs
      @tags.each do |tag|
        tag[:doc].strip!
        tag[:doc] = nil if tag[:doc] == ""
      end
      # Get rid of empty default tag
      if @tags.first && @tags.first[:tagname] == :default && !@tags.first[:doc]
        @tags.shift
      end

      clean_empty_docs
      clean_empty_default_tag
      @tags
    end

@@ -117,17 +112,27 @@ module JsDuck
      return result.join("\n")
    end

    def add_tag(tag)
      @tags << @current_tag = {:tagname => tag, :doc => ""}
    # The parsing process can leave whitespace at the ends of
    # doc-strings, here we get rid of it.
    # Additionally null all empty docs.
    def clean_empty_docs
      @tags.each do |tag|
        tag[:doc].strip!
        tag[:doc] = nil if tag[:doc] == ""
      end
    end

    def remove_last_tag
      @tags.pop
      @current_tag = @tags.last
    # Gets rid of empty default tag
    def clean_empty_default_tag
      if @tags.first && @tags.first[:tagname] == :default && !@tags.first[:doc]
        @tags.shift
      end
    end

    # The main loop of the DocParser
    def parse_loop
      add_tag(:default)

      while !@input.eos? do
        if look(/@/)
          parse_at_tag
@@ -137,29 +142,6 @@ module JsDuck
      end
    end

    # Skips until the beginning of next @tag.
    #
    # There must be space before the next @tag - this ensures that we
    # don't detect tags inside "foo@example.com" or "{@link}".
    #
    # Also check that the @tag is not part of an indented code block -
    # in which case we also ignore the tag.
    def skip_to_next_at_tag
      @current_tag[:doc] += match(/[^@]+/)

      while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
        @current_tag[:doc] += match(/@+[^@]+/)
      end
    end

    def prev_char_is_whitespace?
      @current_tag[:doc][-1,1] =~ /\s/
    end

    def indented_as_code?
      @current_tag[:doc] =~ /^ {4,}[^\n]*\Z/
    end

    # Processes anything beginning with @-sign.
    #
    # - When @ is not followed by any word chards, do nothing.
@@ -178,7 +160,7 @@ module JsDuck
        send(*tagdef)
      elsif tagdef = @meta_tags[name]
        match(/\w+/)
        meta_at_tag(tagdef)
        parse_meta_tag(tagdef)
      else
        Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
        @current_tag[:doc] += "@"
@@ -186,7 +168,7 @@ module JsDuck
    end

    # Matches the given meta-tag
    def meta_at_tag(tag)
    def parse_meta_tag(tag)
      prev_tag = @current_tag

      add_tag(:meta)
@@ -210,6 +192,33 @@ module JsDuck
      end
    end

    # Skips until the beginning of next @tag.
    #
    # There must be space before the next @tag - this ensures that we
    # don't detect tags inside "foo@example.com" or "{@link}".
    #
    # Also check that the @tag is not part of an indented code block -
    # in which case we also ignore the tag.
    def skip_to_next_at_tag
      @current_tag[:doc] += match(/[^@]+/)

      while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
        @current_tag[:doc] += match(/@+[^@]+/)
      end
    end

    def prev_char_is_whitespace?
      @current_tag[:doc][-1,1] =~ /\s/
    end

    def indented_as_code?
      @current_tag[:doc] =~ /^ {4,}[^\n]*\Z/
    end

    #
    # Routines for parsing of concrete tags...
    #

    # matches @<tagname> [ classname ]
    # Used for @class, @extends, @member
    def class_at_tag(tagname, property_name)
@@ -395,6 +404,21 @@ module JsDuck
      skip_white
    end

    #
    # Parsing helpers ...
    #

    # Appends new @tag to parsed tags list
    def add_tag(tag)
      @tags << @current_tag = {:tagname => tag, :doc => ""}
    end

    # Forgets the previously parsed tag
    def remove_last_tag
      @tags.pop
      @current_tag = @tags.last
    end

    # matches {type} if possible and sets it on @current_tag
    # Also checks for {optionality=} in type definition.
    def maybe_type