Repository: eslint/doctrine (js)

Issue:
Expected `OptionalType` param with default value but found `number` and `null`.
```js
/**
 * foo
 *
 * @param {number} [foo = 1] desc
 */

var jsdoc = doctrine.parse(
'/**\n'
+ ' * foo\n'
+ ' *\n'
+ ' * @param {number} [foo = 1] desc\n'
+ ' */'
    ,
    {
        strict: true,
        unwrap: true,
        sloppy: true,
        lineNumbers: true,
        recoverable: true
    }
);
```

JSDoc Object：

```json
{
    "description": "foo",
    "tags": [{
            "title": "param",
            "description": "= 1] desc",
            "lineNumber": 3,
            "type": null,
            "name": "number"
        }]
}
```

Expect:

```json
{
    "description": "foo",
    "tags": [{
            "title": "param",
            "description": "desc",
            "lineNumber": 3,
            "type": {
                "type": "OptionalType",
                "expression": {
                    "type": "NameExpression",
                    "name": "number"
                }
            },
            "name": "foo",
            "default": "1"
        }]
}
```

I'd  fixed it up in our fork：
https://github.com/ecomfe/doctrine2/commit/17faaa817609d186020852db47b756e42706b554

Pull request:
Fix: Allow whitespace in optional param with default value (fixes #141)

Patch:
diff --git a/lib/doctrine.js b/lib/doctrine.js
index 029a63f..de03a64 100644
--- a/lib/doctrine.js
+++ b/lib/doctrine.js
@@ -340,25 +340,37 @@
             }
 
             if (useBrackets) {
-
-
+                skipWhiteSpace(last);
                 // do we have a default value for this?
                 if (source.charCodeAt(index) === 0x3D  /* '=' */) {
                     // consume the '='' symbol
                     name += advance();
+                    skipWhiteSpace(last);
+
+                    var ch;
                     var bracketDepth = 1;
                     // scan in the default value
                     while (index < last) {
-                        if (source.charCodeAt(index) === 0x5B /* '[' */) {
+                        ch = source.charCodeAt(index);
+
+                        if (esutils.code.isWhiteSpace(ch)) {
+                            skipWhiteSpace(last);
+                            ch = source.charCodeAt(index);
+                        }
+
+                        if (ch === 0x5B /* '[' */) {
                             bracketDepth++;
-                        } else if (source.charCodeAt(index) === 0x5D  /* ']' */ &&
+                        } else if (ch === 0x5D  /* ']' */ &&
                             --bracketDepth === 0) {
                             break;
                         }
+
                         name += advance();
                     }
                 }
 
+                skipWhiteSpace(last);
+
                 if (index >= last  || source.charCodeAt(index) !== 0x5D  /* ']' */) {
                     // we never found a closing ']'
                     return null;


Test patch:
diff --git a/test/parse.js b/test/parse.js
index 8b51a46..c34b678 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -1947,6 +1947,28 @@ describe('optional params', function() {
         });
     });
 
+    it('success 4', function() {
+        doctrine.parse(
+            ["/**", " * @param {String=} [val = abc] some description", " */"].join('\n'),
+            { unwrap: true, sloppy: true}
+        ).should.eql({
+            "description": "",
+            "tags": [{
+                "title": "param",
+                "description": "some description",
+                "type": {
+                    "type": "OptionalType",
+                    "expression": {
+                        "type": "NameExpression",
+                        "name": "String"
+                    }
+                },
+                "name": "val",
+                "default": "abc"
+            }]
+        });
+    });
+
     it('default array', function() {
         doctrine.parse(
             ["/**", " * @param {String} [val=['foo']] some description", " */"].join('\n'),
@@ -1969,6 +1991,29 @@ describe('optional params', function() {
         });
     });
 
+
+    it('default array within white spaces', function() {
+        doctrine.parse(
+            ["/**", " * @param {String} [val = [ 'foo' ]] some description", " */"].join('\n'),
+            { unwrap: true, sloppy: true}
+        ).should.eql({
+            "description": "",
+            "tags": [{
+                "title": "param",
+                "description": "some description",
+                "type": {
+                    "type": "OptionalType",
+                    "expression": {
+                        "type": "NameExpression",
+                        "name": "String"
+                    }
+                },
+                "name": "val",
+                "default": "['foo']"
+            }]
+        });
+    });
+
     it('line numbers', function() {
         var res = doctrine.parse(
             [