Commit 3ec1fc1d authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Initial support for parameters with properties.

parent 1b05fee9
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -23,7 +23,8 @@ module JsDuck
  class DocParser
    # Pass in :css to be able to parse CSS doc-comments
    def initialize(mode = :js)
      @ident_pattern = (mode == :css) ? /\$[a-zA-Z0-9_-]*/ : /\w+/
      @ident_pattern = (mode == :css) ? /\$[\w-]*/ : /\w+/
      @ident_chain_pattern = (mode == :css) ? /\$[\w.-]*/ : /[\w.]+/
    end

    def parse(input)
@@ -183,12 +184,13 @@ module JsDuck
      skip_white
    end

    # matches @param {type} variable ...
    # matches @param {type} name ...
    def at_param
      match(/@param/)
      add_tag(:param)
      maybe_type
      maybe_name
      #maybe_name
      maybe_ident_chain(:name)
      skip_white
    end

@@ -278,7 +280,7 @@ module JsDuck
      match(/@alias/)
      add_tag(:alias)
      skip_horiz_white
      if look(/\w/)
      if look(@ident_chain_pattern)
        @current_tag[:cls] = ident_chain
        if look(/#\w/)
          @input.scan(/#/)
@@ -347,7 +349,7 @@ module JsDuck
    # matches ident.chain if possible and sets it on @current_tag
    def maybe_ident_chain(propname)
      skip_horiz_white
      if look(/\w/)
      if look(@ident_chain_pattern)
        @current_tag[propname] = ident_chain
      end
    end
@@ -364,7 +366,7 @@ module JsDuck
    def class_list
      skip_horiz_white
      classes = []
      while look(/\w/)
      while look(@ident_chain_pattern)
        classes << ident_chain
        skip_horiz_white
      end
@@ -373,7 +375,7 @@ module JsDuck

    # matches chained.identifier.name and returns it
    def ident_chain
      @input.scan(/[\w.]+/)
      @input.scan(@ident_chain_pattern)
    end

    # matches identifier and returns its name
+18 −1
Original line number Diff line number Diff line
@@ -318,6 +318,7 @@ module JsDuck
          :doc => doc,
          # convert to boolean for JavaScript export, otherwise it's 0 or nil
          :optional => !!(doc =~ /\(optional\)/i),
          :properties => ex[:properties] || [],
        }
      end
      params
@@ -334,7 +335,23 @@ module JsDuck
    end

    def detect_explicit_params(docs)
      docs.find_all {|tag| tag[:tagname] == :param}
      combine_properties(docs.find_all {|tag| tag[:tagname] == :param})
    end

    def combine_properties(raw_items)
      items = []
      previous = {}
      raw_items.each do |it|
        if it[:name] =~ /\.(.*)$/
          it[:name] = $1
          previous[:properties] = [] unless previous[:properties]
          previous[:properties] << it
        else
          items << it
          previous = it
        end
      end
      items
    end

    def detect_return(doc_map, default_type="undefined")
+76 −0
Original line number Diff line number Diff line
@@ -267,6 +267,82 @@ describe JsDuck::Aggregator do
    end
  end

  describe "method parameter with properties" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * Some function
         * @param {Object} coord Geographical coordinates
         * @param {Number} coord.lat Latitude
         * @param {Number} coord.lng Longitude
         */
        function foo(x, y) {}
      EOS
    end

    it "interprets as single parameter" do
      @doc[:params].length.should == 1
    end

    describe "single param" do
      before do
        @param = @doc[:params][0]
      end

      it "has name" do
        @param[:name].should == "coord"
      end

      it "has type" do
        @param[:type].should == "Object"
      end

      it "has doc" do
        @param[:doc].should == "Geographical coordinates"
      end

      it "contains 2 properties" do
        @param[:properties].length.should == 2
      end

      describe "first property" do
        before do
          @prop = @param[:properties][0]
        end

        it "has name without namespace" do
          @prop[:name].should == "lat"
        end

        it "has type" do
          @prop[:type].should == "Number"
        end

        it "has doc" do
          @prop[:doc].should == "Latitude"
        end
      end

      describe "second property" do
        before do
          @prop = @param[:properties][1]
        end

        it "has name without namespace" do
          @prop[:name].should == "lng"
        end

        it "has type" do
          @prop[:type].should == "Number"
        end

        it "has doc" do
          @prop[:doc].should == "Longitude"
        end
      end
    end
  end

  describe "@return documenting return value" do
    before do
      @doc = parse(<<-EOS)[0]
+12 −3
Original line number Diff line number Diff line
@@ -406,8 +406,7 @@ Ext.define('Docs.view.cls.Overview', {

        if (member.params && member.params.length > 0) {
            doc += '<h3 class="pa">Parameters</h3>';
            var ps = Ext.Array.map(member.params, this.renderLongParam, this).join("");
            doc += "<ul>" + ps + "</ul>";
            doc += this.renderParams(member.params);
        }

        if (member["return"]) {
@@ -417,14 +416,24 @@ Ext.define('Docs.view.cls.Overview', {
        return doc;
    },

    renderParams: function(params) {
        return "<ul>" + Ext.Array.map(params, this.renderLongParam, this).join("") + "</ul>";
    },

    renderLongParam: function(param) {
        this.paramTpl = this.paramTpl || new Ext.XTemplate(
            '<li>',
                '<span class="pre">{name}</span> : {type}',
                '<div class="sub-desc">',
                    '{doc}',
                    '<tpl if="properties && properties.length">',
                        '{[this.renderParams(values.properties)]}',
                    '</tpl>',
                '</div>',
            '</li>'
            '</li>',
            {
                renderParams: Ext.Function.bind(this.renderParams, this)
            }
        );

        return this.paramTpl.apply(param);