Commit 4f1f6a6b authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Parsing of different types of default values.

Supporting all JavaScript literals:

- Number
- String
- RegExp
- Boolean
- Array
- Object
parent c5d1c205
Loading
Loading
Loading
Loading
+90 −5
Original line number Diff line number Diff line
@@ -345,7 +345,7 @@ module JsDuck
      end
    end

    # matches: <ident-chain> | "[" <ident-chain> [ "=" <default-value> ] "]"
    # matches: <ident-chain> | "[" <ident-chain> [ "=" <literal> ] "]"
    def maybe_name_with_default
      skip_horiz_white
      if look(/\[/)
@@ -354,11 +354,11 @@ module JsDuck
        skip_horiz_white
        if look(/=/)
          match(/=/)
          @current_tag[:default] = match(/[^\]]*/).strip
          skip_horiz_white
          @current_tag[:default] = literal
        end
        if look(/\]/)
        skip_horiz_white
        match(/\]/)
        end
        @current_tag[:optional] = true
      else
        maybe_ident_chain(:name)
@@ -390,6 +390,91 @@ module JsDuck
      end
    end

    def literal
      skip_horiz_white
      if look(/[0-9]/)
        number_literal
      elsif look(/["']/)
        string_literal
      elsif look(/\//)
        regex_literal
      elsif look(/\[/)
        array_literal
      elsif look(/\{/)
        object_literal
      elsif look(/true|false/)
        boolean_literal
      end
    end

    def string_literal
      if look(/"/)
        match(/"([^"\\]|\\.)*"/)
      elsif look(/'/)
        match(/'([^'\\]|\\.)*'/)
      end
    end

    def regex_literal
      match(/\/([^\/\\]|\\.)*\/[gim]*/)
    end

    def number_literal
      match(/[0-9]+(\.[0-9]*)?/)
    end

    def boolean_literal
      match(/true|false/)
    end

    def array_literal
      match(/\[/)
      r = []
      lit = literal
      while lit
        r << lit
        skip_horiz_white
        match(/,/)
        lit = literal
      end
      match(/\]/)
      "[" + r.join(", ") + "]"
    end

    def object_literal
      match(/\{/)
      r = []
      lit = object_literal_pair
      while lit
        r << lit
        skip_horiz_white
        match(/,/)
        lit = object_literal_pair
      end
      match(/\}/)
      "{" + r.join(", ") + "}"
    end

    def object_literal_pair
      skip_horiz_white
      if look(/\w/)
        key = ident
      elsif look(/['"]/)
        key = string_literal
      else
        return
      end

      skip_horiz_white
      match(/:/)

      skip_horiz_white
      value = literal
      return if !value

      key + ": " + value
    end

    # matches {...} and returns text inside brackets
    def typedef
      match(/\{/)
+100 −9
Original line number Diff line number Diff line
@@ -102,44 +102,135 @@ describe JsDuck::Aggregator do
    end
  end

  describe "parameter with explicit long default value" do
  describe "parameter with explicit string default value" do
    before do
      @param = parse(<<-EOS)[0][:params][0]
        /**
         * @param {Number} [foo="Hello, my dear!"] Something
         * @param {Number} [foo="Hello, my [dear]!"] Something
         */
        function foo() {
      EOS
    end
    it_should_behave_like "optional parameter"
    it "has default value" do
      @param[:default].should == '"Hello, my dear!"'
      @param[:default].should == '"Hello, my [dear]!"'
    end
  end

  describe "cfg with explicit default value" do
  describe "cfg with explicit regex default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=128.6] Something
         * @cfg {Number} [foo=/[0-9]+/] Something
         */
      EOS
    end
    it "has default value" do
      @doc[:default].should == "128.6"
      @doc[:default].should == "/[0-9]+/"
    end
  end

  describe "cfg with explicit long default value" do
  describe "cfg with explicit boolean default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=/hmm.../] Something
         * @cfg {Number} [foo=true] Something
         */
      EOS
    end
    it "has default value" do
      @doc[:default].should == "/hmm.../"
      @doc[:default].should == "true"
    end
  end

  describe "cfg with explicit array default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=["foo", 5, /[a-z]/]] Something
         */
      EOS
    end
    it "has default value" do
      @doc[:default].should == '["foo", 5, /[a-z]/]'
    end
  end

  describe "cfg with explicit object default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo={"foo": 5, bar: [1, 2, 3]}] Something
         */
      EOS
    end
    it "has default value" do
      @doc[:default].should == '{"foo": 5, bar: [1, 2, 3]}'
    end
  end

  describe "cfg with rubbish as default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=!haa] Something
         */
      EOS
    end
    it "has no default value" do
      @doc[:default].should == nil
    end
  end

  describe "cfg with rubbish after default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=7 and me too] Something
         */
      EOS
    end
    it "has a correct default value" do
      @doc[:default].should == '7'
    end
  end

  describe "cfg with bogus array literal as default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo=[ho, ho]] Something
         */
      EOS
    end
    it "has as much of the array as possible for default value" do
      @doc[:default].should == '[]'
    end
  end

  describe "cfg with bogus object literal as default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo={ho:5, ho}] Something
         */
      EOS
    end
    it "has as much of the object as possible for default value" do
      @doc[:default].should == '{ho: 5}'
    end
  end

  describe "cfg with unfinished object literal as default value" do
    before do
      @doc = parse(<<-EOS)[0]
        /**
         * @cfg {Number} [foo={ho:5] Something
         */
      EOS
    end
    it "has as much of the object as possible for default value" do
      @doc[:default].should == '{ho: 5}'
    end
  end