Skip to content

Commit d7426e5

Browse files
ikokostyanzakas
authored andcommitted
Update: add ability to parse optional properties in typedefs (refs eslint#5) (eslint#174)
* Update: add ability to parse optional properties in typedefs (refs eslint#5) * Simplify condition
1 parent b4b2870 commit d7426e5

File tree

2 files changed

+253
-4
lines changed

2 files changed

+253
-4
lines changed

lib/doctrine.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
return isProperty(title) || isParamTitle(title);
7373
}
7474

75+
function isAllowedOptional(title) {
76+
return isProperty(title) || isParamTitle(title);
77+
}
78+
7579
function isTypeParameterRequired(title) {
7680
return isParamTitle(title) || isReturnTitle(title) ||
7781
title === 'define' || title === 'enum' ||
@@ -255,9 +259,10 @@
255259
return utility.throwError('Braces are not balanced');
256260
}
257261

258-
if (isParamTitle(title)) {
262+
if (isAllowedOptional(title)) {
259263
return typed.parseParamType(type);
260264
}
265+
261266
return typed.parseType(type);
262267
}
263268

@@ -284,6 +289,7 @@
284289
useBrackets,
285290
insideString;
286291

292+
287293
skipWhiteSpace(last);
288294

289295
if (index >= last) {
@@ -469,7 +475,7 @@
469475

470476
TagParser.prototype._parseNamePath = function (optional) {
471477
var name;
472-
name = parseName(this._last, sloppy && isParamTitle(this._title), true);
478+
name = parseName(this._last, sloppy && isAllowedOptional(this._title), true);
473479
if (!name) {
474480
if (!optional) {
475481
if (!this.addError('Missing or invalid tag name')) {
@@ -495,7 +501,7 @@
495501

496502
// param, property requires name
497503
if (isAllowedName(this._title)) {
498-
this._tag.name = parseName(this._last, sloppy && isParamTitle(this._title), isAllowedNested(this._title));
504+
this._tag.name = parseName(this._last, sloppy && isAllowedOptional(this._title), isAllowedNested(this._title));
499505
if (!this._tag.name) {
500506
if (!isNameParameterRequired(this._title)) {
501507
return true;
@@ -535,6 +541,7 @@
535541
}
536542
}
537543

544+
538545
return true;
539546
};
540547

@@ -647,7 +654,7 @@
647654

648655
description = this._tag.description;
649656
// un-fix potentially sloppy declaration
650-
if (isParamTitle(this._title) && !this._tag.type && description && description.charAt(0) === '[') {
657+
if (isAllowedOptional(this._title) && !this._tag.type && description && description.charAt(0) === '[') {
651658
this._tag.type = this._extra.name;
652659
if (!this._tag.name) {
653660
this._tag.name = undefined;
@@ -739,6 +746,7 @@
739746
TagParser.prototype.parse = function parse() {
740747
var i, iz, sequences, method;
741748

749+
742750
// empty title
743751
if (!this._title) {
744752
if (!this.addError('Missing or invalid title')) {
@@ -785,6 +793,7 @@
785793
while (index < parser._last) {
786794
advance();
787795
}
796+
788797
return tag;
789798
}
790799

test/parse.js

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,24 @@ describe('parse', function () {
866866
res.tags.should.have.length(0);
867867
});
868868

869+
870+
it('property with optional type', function() {
871+
var res = doctrine.parse(
872+
["/**",
873+
"* testtypedef",
874+
"* @typedef {object} abc",
875+
"* @property {String} [val] value description",
876+
"*/"].join('\n'), {
877+
unwrap: true,
878+
sloppy: true
879+
});
880+
881+
res.tags[1].should.have.property('title', 'property');
882+
res.tags[1].should.have.property('type');
883+
res.tags[1]['type'].should.have.property('type', "OptionalType");
884+
});
885+
886+
869887
it('property with nested name', function () {
870888
var res = doctrine.parse(
871889
[
@@ -2227,6 +2245,228 @@ describe('optional params', function() {
22272245
});
22282246
});
22292247

2248+
describe('optional properties', function() {
2249+
2250+
// should fail since sloppy option not set
2251+
it('failure 0', function() {
2252+
doctrine.parse(
2253+
[ "/**",
2254+
" * @property {String} [val] some description",
2255+
" */"].join('\n'), {
2256+
unwrap: true
2257+
}).should.eql({
2258+
"description": "",
2259+
"tags": []
2260+
});
2261+
});
2262+
2263+
it('failure 1', function() {
2264+
doctrine.parse(
2265+
["/**", " * @property [val", " */"].join('\n'), {
2266+
unwrap: true, sloppy: true
2267+
}).should.eql({
2268+
"description": "",
2269+
"tags": []
2270+
});
2271+
});
2272+
2273+
it('success 1', function() {
2274+
doctrine.parse(
2275+
["/**", " * @property {String} [val]", " */"].join('\n'), {
2276+
unwrap: true, sloppy: true
2277+
}).should.eql({
2278+
"description": "",
2279+
"tags": [{
2280+
"title": "property",
2281+
"description": null,
2282+
"type": {
2283+
"type": "OptionalType",
2284+
"expression": {
2285+
"type": "NameExpression",
2286+
"name": "String"
2287+
}
2288+
},
2289+
"name": "val"
2290+
}]
2291+
});
2292+
});
2293+
2294+
it('success 2', function() {
2295+
doctrine.parse(
2296+
["/**", " * @property {String=} val", " */"].join('\n'), {
2297+
unwrap: true, sloppy: true
2298+
}).should.eql({
2299+
"description": "",
2300+
"tags": [{
2301+
"title": "property",
2302+
"description": null,
2303+
"type": {
2304+
"type": "OptionalType",
2305+
"expression": {
2306+
"type": "NameExpression",
2307+
"name": "String"
2308+
}
2309+
},
2310+
"name": "val"
2311+
}]
2312+
});
2313+
});
2314+
2315+
it('success 3', function() {
2316+
doctrine.parse(
2317+
["/**", " * @property {String=} [val=abc] some description", " */"].join('\n'),
2318+
{ unwrap: true, sloppy: true}
2319+
).should.eql({
2320+
"description": "",
2321+
"tags": [{
2322+
"title": "property",
2323+
"description": "some description",
2324+
"type": {
2325+
"type": "OptionalType",
2326+
"expression": {
2327+
"type": "NameExpression",
2328+
"name": "String"
2329+
}
2330+
},
2331+
"name": "val",
2332+
"default": "abc"
2333+
}]
2334+
});
2335+
});
2336+
2337+
it('success 4', function() {
2338+
doctrine.parse(
2339+
["/**", " * @property {String=} [val = abc] some description", " */"].join('\n'),
2340+
{ unwrap: true, sloppy: true}
2341+
).should.eql({
2342+
"description": "",
2343+
"tags": [{
2344+
"title": "property",
2345+
"description": "some description",
2346+
"type": {
2347+
"type": "OptionalType",
2348+
"expression": {
2349+
"type": "NameExpression",
2350+
"name": "String"
2351+
}
2352+
},
2353+
"name": "val",
2354+
"default": "abc"
2355+
}]
2356+
});
2357+
});
2358+
2359+
it('default string', function() {
2360+
doctrine.parse(
2361+
["/**", " * @property {String} [val=\"foo\"] some description", " */"].join('\n'),
2362+
{ unwrap: true, sloppy: true}
2363+
).should.eql({
2364+
"description": "",
2365+
"tags": [{
2366+
"title": "property",
2367+
"description": "some description",
2368+
"type": {
2369+
"type": "OptionalType",
2370+
"expression": {
2371+
"type": "NameExpression",
2372+
"name": "String"
2373+
}
2374+
},
2375+
"name": "val",
2376+
"default": "\"foo\""
2377+
}]
2378+
});
2379+
});
2380+
2381+
it('default string surrounded by whitespace', function() {
2382+
doctrine.parse(
2383+
["/**", " * @property {String} [val= 'foo' ] some description", " */"].join('\n'),
2384+
{ unwrap: true, sloppy: true}
2385+
).should.eql({
2386+
"description": "",
2387+
"tags": [{
2388+
"title": "property",
2389+
"description": "some description",
2390+
"type": {
2391+
"type": "OptionalType",
2392+
"expression": {
2393+
"type": "NameExpression",
2394+
"name": "String"
2395+
}
2396+
},
2397+
"name": "val",
2398+
"default": "'foo'"
2399+
}]
2400+
});
2401+
});
2402+
2403+
it('should preserve whitespace in default string', function() {
2404+
doctrine.parse(
2405+
["/**", " * @property {String} [val= \" foo\" ] some description", " */"].join('\n'),
2406+
{ unwrap: true, sloppy: true}
2407+
).should.eql({
2408+
"description": "",
2409+
"tags": [{
2410+
"title": "property",
2411+
"description": "some description",
2412+
"type": {
2413+
"type": "OptionalType",
2414+
"expression": {
2415+
"type": "NameExpression",
2416+
"name": "String"
2417+
}
2418+
},
2419+
"name": "val",
2420+
"default": "\" foo\""
2421+
}]
2422+
});
2423+
});
2424+
2425+
it('default array', function() {
2426+
doctrine.parse(
2427+
["/**", " * @property {String} [val=['foo']] some description", " */"].join('\n'),
2428+
{ unwrap: true, sloppy: true}
2429+
).should.eql({
2430+
"description": "",
2431+
"tags": [{
2432+
"title": "property",
2433+
"description": "some description",
2434+
"type": {
2435+
"type": "OptionalType",
2436+
"expression": {
2437+
"type": "NameExpression",
2438+
"name": "String"
2439+
}
2440+
},
2441+
"name": "val",
2442+
"default": "['foo']"
2443+
}]
2444+
});
2445+
});
2446+
2447+
it('default array within white spaces', function() {
2448+
doctrine.parse(
2449+
["/**", " * @property {String} [val = [ 'foo' ]] some description", " */"].join('\n'),
2450+
{ unwrap: true, sloppy: true}
2451+
).should.eql({
2452+
"description": "",
2453+
"tags": [{
2454+
"title": "property",
2455+
"description": "some description",
2456+
"type": {
2457+
"type": "OptionalType",
2458+
"expression": {
2459+
"type": "NameExpression",
2460+
"name": "String"
2461+
}
2462+
},
2463+
"name": "val",
2464+
"default": "['foo']"
2465+
}]
2466+
});
2467+
});
2468+
});
2469+
22302470
describe('recovery tests', function() {
22312471
it ('params 2', function () {
22322472
var res = doctrine.parse(

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy