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

New multiline tags system.

Instead of setting @multiline = true, the multiline tags now return
a tag containing {:doc => :multiline} from their #parse method.

Inside Doc::Parser the free text will only get appended to these
:doc=>:multiline tags plus a special :tagname=>:doc tag which grabs
all the documentation since the beginning of doc-comment up to the first
multiline @tag.

The Doc::Ast will later combine docs for classes and members, mainly
looking at the :tagname=>:doc, but also at :cfg and :property which are
a special case because they can contain subproperties, and also
:constructor which can be used as a splitter between class documentation
and constructor documentation.
parent a34cb588
Loading
Loading
Loading
Loading
+16 −17
Original line number Diff line number Diff line
@@ -42,14 +42,14 @@ module JsDuck
      def create_class(docs, doc_map)
        return add_shared({
            :tagname => :class,
            :doc => detect_doc(docs),
            :doc => detect_doc(:class, doc_map),
          }, doc_map)
      end

      def create_method(docs, doc_map)
        return add_shared({
            :tagname => :method,
            :doc => detect_doc(docs),
            :doc => detect_doc(:method, doc_map),
            :params => detect_params(doc_map),
            :return => detect_return(doc_map),
          }, doc_map)
@@ -58,7 +58,7 @@ module JsDuck
      def create_event(docs, doc_map)
        return add_shared({
            :tagname => :event,
            :doc => detect_doc(docs),
            :doc => detect_doc(:event, doc_map),
            :params => detect_params(doc_map),
          }, doc_map)
      end
@@ -68,7 +68,7 @@ module JsDuck
            :tagname => :cfg,
            :name => detect_name(:cfg, doc_map),
            :type => detect_type(:cfg, doc_map),
            :doc => detect_doc(docs),
            :doc => detect_doc(:cfg, doc_map),
            :default => detect_default(:cfg, doc_map),
            :properties => detect_subproperties(:cfg, docs),
          }, doc_map)
@@ -79,7 +79,7 @@ module JsDuck
            :tagname => :property,
            :name => detect_name(:property, doc_map),
            :type => detect_type(:property, doc_map),
            :doc => detect_doc(docs),
            :doc => detect_doc(:property, doc_map),
            :default => detect_default(:property, doc_map),
            :properties => detect_subproperties(:property, docs),
          }, doc_map)
@@ -91,7 +91,7 @@ module JsDuck
            :name => detect_name(:css_var, doc_map),
            :type => detect_type(:css_var, doc_map),
            :default => detect_default(:css_var, doc_map),
            :doc => detect_doc(docs),
            :doc => detect_doc(:css_var, doc_map),
          }, doc_map)
      end

@@ -99,7 +99,7 @@ module JsDuck
        return add_shared({
            :tagname => :css_mixin,
            :name => detect_name(:css_mixin, doc_map),
            :doc => detect_doc(docs),
            :doc => detect_doc(:css_mixin, doc_map),
            :params => detect_params(doc_map),
          }, doc_map)
      end
@@ -168,16 +168,15 @@ module JsDuck
        }
      end

      # Combines :doc-s of most tags
      # Ignores tags that have doc comment themselves and subproperty tags
      def detect_doc(docs)
        ignore_tags = [:param, :return] + TagRegistry.multiliners.map {|t| t.key }
        doc_tags = docs.find_all { |tag| !ignore_tags.include?(tag[:tagname]) && !subproperty?(tag) }
        doc_tags.map { |tag| tag[:doc] }.compact.join(" ")
      # Returns documentation for class or member.
      def detect_doc(tagname, doc_map)
        doc = extract(doc_map, :doc, :doc) || ""
        if tagname == :cfg || tagname == :property
          doc += extract(doc_map, tagname, :doc) || ""
        elsif tagname == :method && doc_map[:constructor]
          doc += extract(doc_map, :constructor, :doc)
        end

      def subproperty?(tag)
        (tag[:tagname] == :cfg || tag[:tagname] == :property) && tag[:name] =~ /\./
        doc
      end

    end
+19 −19
Original line number Diff line number Diff line
@@ -35,31 +35,21 @@ module JsDuck

        parse_loop

        clean_empty_docs
        clean_empty_default_tag
        strip_docs
        @tags
      end

      # 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
      def strip_docs
        @tags.each do |tag|
          tag[:doc].strip!
          tag[:doc] = nil if tag[:doc] == ""
        end
      end

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

      # The main loop of the DocParser
      def parse_loop
        add_tag({:tagname => :default, :doc => ""})
        add_tag({:tagname => :doc, :doc => :multiline})

        while !@input.eos? do
          if look(/@/)
@@ -70,6 +60,16 @@ module JsDuck
        end
      end

      # Appends new @tag to parsed tags list
      def add_tag(tag)
        @tags << tag

        if tag[:doc] == :multiline
          tag[:doc] = ""
          @multiline_tag = tag
        end
      end

      # Processes anything beginning with @-sign.
      #
      # - When @ is not followed by any word chars, do nothing.
@@ -95,7 +95,7 @@ module JsDuck
          skip_white
        else
          Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
          @current_tag[:doc] += "@"
          @multiline_tag[:doc] += "@"
        end
      end

@@ -107,19 +107,19 @@ module JsDuck
      # 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(/[^@]+/)
        @multiline_tag[:doc] += match(/[^@]+/)

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

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

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

+0 −12
Original line number Diff line number Diff line
@@ -15,24 +15,12 @@ module JsDuck
        @ident_pattern = /[$\w-]+/
        @ident_chain_pattern = /[$\w-]+(\.[$\w-]+)*/

        @tags = []
        @input = nil # set to StringScanner in subclass
      end

      # Provides access to StringScanner
      attr_reader :input

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

        @current_tag[:doc] = "" unless @current_tag.has_key?(:doc)
      end

      # Parses standard pattern common in several builtin tags, which
      # goes like this:
      #
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ module JsDuck::Tag
    def parse(p)
      tag = p.standard_tag({:tagname => :cfg, :type => true, :name => true})
      tag[:optional] = false if parse_required(p)
      tag[:doc] = :multiline
      tag
    end

+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ module JsDuck::Tag

    # @constructor
    def parse(p)
      {:tagname => :constructor}
      {:tagname => :constructor, :doc => :multiline}
    end

    # The method name will become "constructor" unless a separate
Loading