comment-parser 0.5.1 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +8 -4
- package/CHANGELOG.md +13 -0
- package/README.md +7 -7
- package/index.d.ts +29 -0
- package/index.js +1 -1
- package/package.json +11 -10
- package/parser.js +1 -1
- package/parsers.js +25 -16
- package/tests/parse.js +4 -4
- package/tests/parse.spec.js +192 -1
package/.travis.yml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# v0.5.5
|
|
2
|
+
- allow loose tag names, e.g. @.tag, @-tag
|
|
3
|
+
|
|
4
|
+
# v0.5.4
|
|
5
|
+
- allow quoted literal names, e.g. `@tag "My Var" description`
|
|
6
|
+
|
|
7
|
+
# v0.5.3
|
|
8
|
+
- corrected TypeScript definitions
|
|
9
|
+
|
|
10
|
+
# v0.5.2
|
|
11
|
+
- added TypeScript definitions
|
|
12
|
+
- removed `readable-stream` dependency
|
|
13
|
+
|
|
1
14
|
# v0.5.1
|
|
2
15
|
- Support for tab as separator between tag components.
|
|
3
16
|
- Docs: Indicate when `optional` is `true`; `default` property
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Module provides `parse(s:String[, opts:Object]):Object` function which takes `/*
|
|
|
9
9
|
|
|
10
10
|
It is not trying to detect relations between tags or somehow recognize their meaning. Any tag can be used, as long as it satisfies the format.
|
|
11
11
|
|
|
12
|
-
```
|
|
12
|
+
```javascript
|
|
13
13
|
/**
|
|
14
14
|
* Singleline or multiline description text. Line breaks are preserved.
|
|
15
15
|
*
|
|
@@ -24,7 +24,7 @@ It is not trying to detect relations between tags or somehow recognize their mea
|
|
|
24
24
|
|
|
25
25
|
this would be parsed into following
|
|
26
26
|
|
|
27
|
-
```
|
|
27
|
+
```json
|
|
28
28
|
[{
|
|
29
29
|
"tags": [{
|
|
30
30
|
"tag": "some-tag",
|
|
@@ -78,7 +78,7 @@ By default dotted names like `name.subname.subsubname` will be expanded into nes
|
|
|
78
78
|
|
|
79
79
|
Below are examples of acceptable comment formats
|
|
80
80
|
|
|
81
|
-
```
|
|
81
|
+
```javascript
|
|
82
82
|
/** online comment */
|
|
83
83
|
|
|
84
84
|
/** first line
|
|
@@ -111,7 +111,7 @@ Each parser function takes string left after previous parsers applied and data p
|
|
|
111
111
|
|
|
112
112
|
Tag node data is build by merging result bits from all parsers. Here is some example that is not doing actual parsing but is demonstrating the flow:
|
|
113
113
|
|
|
114
|
-
```
|
|
114
|
+
```javascript
|
|
115
115
|
/**
|
|
116
116
|
* Source to be parsed below
|
|
117
117
|
* @tag {type} name Description
|
|
@@ -140,12 +140,12 @@ parse(source, {parsers: [
|
|
|
140
140
|
|
|
141
141
|
This would produce following:
|
|
142
142
|
|
|
143
|
-
```
|
|
143
|
+
```json
|
|
144
144
|
[{
|
|
145
145
|
"tags": [{
|
|
146
146
|
"tag": "tag",
|
|
147
147
|
"errors": [
|
|
148
|
-
"check_tag: Unrecognized tag
|
|
148
|
+
"check_tag: Unrecognized tag \"tag\""
|
|
149
149
|
],
|
|
150
150
|
"name": "name2",
|
|
151
151
|
"optional": false,
|
|
@@ -168,4 +168,4 @@ This would produce following:
|
|
|
168
168
|
|
|
169
169
|
```
|
|
170
170
|
> npm info --registry https://registry.npmjs.org comment-parser contributors
|
|
171
|
-
```
|
|
171
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Type definitions for comment-parser
|
|
2
|
+
// Project: comment-parser
|
|
3
|
+
// Definitions by: Javier "Ciberman" Mora <https://github.com/jhm-ciberman/>
|
|
4
|
+
|
|
5
|
+
declare namespace CommentParser {
|
|
6
|
+
export interface Comment {
|
|
7
|
+
tags: Tag[];
|
|
8
|
+
line: number;
|
|
9
|
+
description: string;
|
|
10
|
+
source: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Tag {
|
|
13
|
+
tag: string;
|
|
14
|
+
name: string;
|
|
15
|
+
optional: boolean;
|
|
16
|
+
type: string;
|
|
17
|
+
description: string;
|
|
18
|
+
line: number;
|
|
19
|
+
source: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Options {
|
|
22
|
+
parsers?: [(str: string, data: any) => { source: string, data: any }];
|
|
23
|
+
dotted_names?: boolean;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare function parse(str: string, opts?: CommentParser.Options): [CommentParser.Comment];
|
|
28
|
+
|
|
29
|
+
export = parse;
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comment-parser",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "Generic JSDoc-like comment parser. ",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
6
7
|
"directories": {
|
|
7
8
|
"test": "tests"
|
|
8
9
|
},
|
|
9
|
-
"dependencies": {
|
|
10
|
-
"readable-stream": "^2.0.4"
|
|
11
|
-
},
|
|
10
|
+
"dependencies": {},
|
|
12
11
|
"devDependencies": {
|
|
13
|
-
"chai": "
|
|
14
|
-
"eslint": "^
|
|
12
|
+
"chai": "^4.2.0",
|
|
13
|
+
"eslint": "^5.16.0",
|
|
15
14
|
"eslint-config-standard": "^10.2.1",
|
|
16
15
|
"eslint-plugin-import": "^2.7.0",
|
|
17
16
|
"eslint-plugin-node": "^5.1.1",
|
|
18
17
|
"eslint-plugin-promise": "^3.5.0",
|
|
19
18
|
"eslint-plugin-standard": "^3.0.1",
|
|
20
|
-
"mocha": "^
|
|
21
|
-
"nodemon": "^1.
|
|
19
|
+
"mocha": "^5.2.0",
|
|
20
|
+
"nodemon": "^1.18.9"
|
|
22
21
|
},
|
|
23
22
|
"scripts": {
|
|
24
|
-
"
|
|
25
|
-
"test": "mocha tests",
|
|
23
|
+
"test:lint": "eslint .",
|
|
24
|
+
"test:unit": "mocha tests",
|
|
25
|
+
"test": "npm run test:lint && npm run test:unit",
|
|
26
26
|
"watch": "nodemon -q -i node_modules -x npm test"
|
|
27
27
|
},
|
|
28
28
|
"repository": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"Alexej Yaroshevich (https://github.com/zxqfox)",
|
|
40
40
|
"Dieter Oberkofler (https://github.com/doberkofler)",
|
|
41
41
|
"Evgeny Reznichenko (https://github.com/zxcabs)",
|
|
42
|
+
"Javier \"Ciberma\" Mora (https://github.com/jhm-ciberman)",
|
|
42
43
|
"Jordan Harband (https://github.com/ljharb)",
|
|
43
44
|
"tengattack (https://github.com/tengattack)"
|
|
44
45
|
],
|
package/parser.js
CHANGED
|
@@ -101,7 +101,7 @@ function parse_block (source, opts) {
|
|
|
101
101
|
.reduce(function (tags, line) {
|
|
102
102
|
line.source = trim(line.source)
|
|
103
103
|
|
|
104
|
-
if (line.source.match(/^\s*@(\
|
|
104
|
+
if (line.source.match(/^\s*@(\S+)/)) {
|
|
105
105
|
tags.push({source: [line.source], line: line.number})
|
|
106
106
|
} else {
|
|
107
107
|
var tag = tags[tags.length - 1]
|
package/parsers.js
CHANGED
|
@@ -51,26 +51,35 @@ PARSERS.parse_name = function parse_name (str, data) {
|
|
|
51
51
|
var pos = skipws(str)
|
|
52
52
|
var name = ''
|
|
53
53
|
var brackets = 0
|
|
54
|
+
var res = {optional: false}
|
|
55
|
+
|
|
56
|
+
// if it starts with quoted group assume it is a literal
|
|
57
|
+
var quotedGroups = str.slice(pos).split('"')
|
|
58
|
+
if (quotedGroups.length > 1 && quotedGroups[0] === '' && quotedGroups.length % 2 === 1) {
|
|
59
|
+
name = quotedGroups[1]
|
|
60
|
+
pos += name.length + 2
|
|
61
|
+
// assume name is non-space string or anything wrapped into brackets
|
|
62
|
+
} else {
|
|
63
|
+
while (pos < str.length) {
|
|
64
|
+
brackets += (str[pos] === '[' ? 1 : (str[pos] === ']' ? -1 : 0))
|
|
65
|
+
name += str[pos]
|
|
66
|
+
pos++
|
|
67
|
+
if (brackets === 0 && /\s/.test(str[pos])) { break }
|
|
68
|
+
}
|
|
54
69
|
|
|
55
|
-
|
|
56
|
-
brackets += (str[pos] === '[' ? 1 : (str[pos] === ']' ? -1 : 0))
|
|
57
|
-
name += str[pos]
|
|
58
|
-
pos++
|
|
59
|
-
if (brackets === 0 && /\s/.test(str[pos])) { break }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (brackets !== 0) { throw new Error('Invalid `name`, unpaired brackets') }
|
|
70
|
+
if (brackets !== 0) { throw new Error('Invalid `name`, unpaired brackets') }
|
|
63
71
|
|
|
64
|
-
|
|
72
|
+
res = {name: name, optional: false}
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
if (name[0] === '[' && name[name.length - 1] === ']') {
|
|
75
|
+
res.optional = true
|
|
76
|
+
name = name.slice(1, -1)
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
if (name.indexOf('=') !== -1) {
|
|
79
|
+
var parts = name.split('=')
|
|
80
|
+
name = parts[0]
|
|
81
|
+
res.default = parts[1].replace(/^(["'])(.+)(\1)$/, '$2')
|
|
82
|
+
}
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
85
|
|
package/tests/parse.js
CHANGED
|
@@ -11,8 +11,8 @@ var parse = require('../index')
|
|
|
11
11
|
|
|
12
12
|
module.exports = function (func, opts) {
|
|
13
13
|
var str = func.toString()
|
|
14
|
-
|
|
15
|
-
str.indexOf('{') + 1,
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
str = str
|
|
15
|
+
.slice(str.indexOf('{') + 1, str.lastIndexOf('}'))
|
|
16
|
+
.replace(/\r\n/g, '\n')
|
|
17
|
+
return parse(str, opts)
|
|
18
18
|
}
|
package/tests/parse.spec.js
CHANGED
|
@@ -459,6 +459,47 @@ describe('Comment string parsing', function () {
|
|
|
459
459
|
})
|
|
460
460
|
})
|
|
461
461
|
|
|
462
|
+
it('should tolerate loose tag names', function () {
|
|
463
|
+
expect(parse(function () {
|
|
464
|
+
/**
|
|
465
|
+
Description text
|
|
466
|
+
@.tag0 tagname Tag 0 description
|
|
467
|
+
@-tag1 tagname Tag 1 description
|
|
468
|
+
@+tag2 tagname Tag 2 description
|
|
469
|
+
*/
|
|
470
|
+
})[0])
|
|
471
|
+
.eql({
|
|
472
|
+
description: 'Description text',
|
|
473
|
+
source: 'Description text\n@.tag0 tagname Tag 0 description\n@-tag1 tagname Tag 1 description\n@+tag2 tagname Tag 2 description',
|
|
474
|
+
line: 1,
|
|
475
|
+
tags: [{
|
|
476
|
+
tag: '.tag0',
|
|
477
|
+
name: 'tagname',
|
|
478
|
+
optional: false,
|
|
479
|
+
description: 'Tag 0 description',
|
|
480
|
+
type: '',
|
|
481
|
+
line: 3,
|
|
482
|
+
source: '@.tag0 tagname Tag 0 description'
|
|
483
|
+
}, {
|
|
484
|
+
tag: '-tag1',
|
|
485
|
+
name: 'tagname',
|
|
486
|
+
optional: false,
|
|
487
|
+
description: 'Tag 1 description',
|
|
488
|
+
type: '',
|
|
489
|
+
line: 4,
|
|
490
|
+
source: '@-tag1 tagname Tag 1 description'
|
|
491
|
+
}, {
|
|
492
|
+
tag: '+tag2',
|
|
493
|
+
name: 'tagname',
|
|
494
|
+
optional: false,
|
|
495
|
+
description: 'Tag 2 description',
|
|
496
|
+
type: '',
|
|
497
|
+
line: 5,
|
|
498
|
+
source: '@+tag2 tagname Tag 2 description'
|
|
499
|
+
}]
|
|
500
|
+
})
|
|
501
|
+
})
|
|
502
|
+
|
|
462
503
|
it('should tolerate default value with whitespces `@tag {my.type} [name=John Doe]`', function () {
|
|
463
504
|
expect(parse(function () {
|
|
464
505
|
/**
|
|
@@ -612,7 +653,7 @@ describe('Comment string parsing', function () {
|
|
|
612
653
|
* @my-tag name.sub-name
|
|
613
654
|
* @my-tag name.sub-name.sub-sub-name
|
|
614
655
|
*/
|
|
615
|
-
}, {dotted_names: true})[0])
|
|
656
|
+
}, { dotted_names: true })[0])
|
|
616
657
|
.to.eql({
|
|
617
658
|
line: 1,
|
|
618
659
|
description: 'Description',
|
|
@@ -888,4 +929,154 @@ describe('Comment string parsing', function () {
|
|
|
888
929
|
}]
|
|
889
930
|
})
|
|
890
931
|
})
|
|
932
|
+
|
|
933
|
+
it('should parse same line closing section (issue #22)', function () {
|
|
934
|
+
expect(parse(function () {
|
|
935
|
+
/**
|
|
936
|
+
* Start here
|
|
937
|
+
* Here is more stuff */
|
|
938
|
+
var a
|
|
939
|
+
})[0])
|
|
940
|
+
.to.eql({
|
|
941
|
+
description: 'Start here\nHere is more stuff',
|
|
942
|
+
line: 1,
|
|
943
|
+
source: 'Start here\nHere is more stuff',
|
|
944
|
+
tags: []
|
|
945
|
+
})
|
|
946
|
+
})
|
|
947
|
+
|
|
948
|
+
it('should tolerate inconsistent formatting (issue #29)', function () {
|
|
949
|
+
expect(parse(function () {
|
|
950
|
+
/**
|
|
951
|
+
* @param {Object} options 配置
|
|
952
|
+
* @return {Any} obj 组件返回的对象
|
|
953
|
+
* @example
|
|
954
|
+
* var widget = XX.showWidget('searchlist', {
|
|
955
|
+
* onComplete: function() {
|
|
956
|
+
* todoSomething();
|
|
957
|
+
* }
|
|
958
|
+
* });
|
|
959
|
+
*/
|
|
960
|
+
}, {
|
|
961
|
+
join: 1,
|
|
962
|
+
trim: false
|
|
963
|
+
})[0]).to.eql({
|
|
964
|
+
description: '',
|
|
965
|
+
line: 1,
|
|
966
|
+
source: "\n@param {Object} options 配置\n@return {Any} obj 组件返回的对象\n@example\nvar widget = XX.showWidget('searchlist', {\n onComplete: function() {\n todoSomething();\n }\n});\n",
|
|
967
|
+
tags: [{
|
|
968
|
+
description: '配置',
|
|
969
|
+
line: 2,
|
|
970
|
+
name: 'options',
|
|
971
|
+
optional: false,
|
|
972
|
+
source: '@param {Object} options 配置',
|
|
973
|
+
tag: 'param',
|
|
974
|
+
type: 'Object'
|
|
975
|
+
}, {
|
|
976
|
+
description: '组件返回的对象',
|
|
977
|
+
line: 3,
|
|
978
|
+
name: 'obj',
|
|
979
|
+
optional: false,
|
|
980
|
+
source: '@return {Any} obj 组件返回的对象',
|
|
981
|
+
tag: 'return',
|
|
982
|
+
type: 'Any'
|
|
983
|
+
}, {
|
|
984
|
+
description: "widget = XX.showWidget('searchlist', {\n onComplete: function() {\n todoSomething();\n }\n});\n",
|
|
985
|
+
line: 4,
|
|
986
|
+
name: '\nvar',
|
|
987
|
+
optional: false,
|
|
988
|
+
source: "@example\nvar widget = XX.showWidget('searchlist', {\n onComplete: function() {\n todoSomething();\n }\n});\n",
|
|
989
|
+
tag: 'example',
|
|
990
|
+
type: ''
|
|
991
|
+
}]
|
|
992
|
+
})
|
|
993
|
+
})
|
|
994
|
+
|
|
995
|
+
it('should keep optional names spaces (issue #41)`', function () {
|
|
996
|
+
expect(parse(function () {
|
|
997
|
+
/**
|
|
998
|
+
* @section [Brand Colors] Here you can find all the brand colors
|
|
999
|
+
*/
|
|
1000
|
+
})[0])
|
|
1001
|
+
.to.eql({
|
|
1002
|
+
line: 1,
|
|
1003
|
+
source: '@section [Brand Colors] Here you can find all the brand colors',
|
|
1004
|
+
description: '',
|
|
1005
|
+
tags: [{
|
|
1006
|
+
tag: 'section',
|
|
1007
|
+
line: 2,
|
|
1008
|
+
type: '',
|
|
1009
|
+
name: 'Brand Colors',
|
|
1010
|
+
source: '@section [Brand Colors] Here you can find all the brand colors',
|
|
1011
|
+
optional: true,
|
|
1012
|
+
description: 'Here you can find all the brand colors'
|
|
1013
|
+
}]
|
|
1014
|
+
})
|
|
1015
|
+
})
|
|
1016
|
+
|
|
1017
|
+
it('should keep quotes in description (issue #41)`', function () {
|
|
1018
|
+
expect(parse(function () {
|
|
1019
|
+
/**
|
|
1020
|
+
* @section "Brand Colors" Here you can find all the brand colors
|
|
1021
|
+
*/
|
|
1022
|
+
})[0])
|
|
1023
|
+
.to.eql({
|
|
1024
|
+
line: 1,
|
|
1025
|
+
source: '@section "Brand Colors" Here you can find all the brand colors',
|
|
1026
|
+
description: '',
|
|
1027
|
+
tags: [{
|
|
1028
|
+
tag: 'section',
|
|
1029
|
+
line: 2,
|
|
1030
|
+
type: '',
|
|
1031
|
+
name: 'Brand Colors',
|
|
1032
|
+
source: '@section "Brand Colors" Here you can find all the brand colors',
|
|
1033
|
+
optional: false,
|
|
1034
|
+
description: 'Here you can find all the brand colors'
|
|
1035
|
+
}]
|
|
1036
|
+
})
|
|
1037
|
+
})
|
|
1038
|
+
|
|
1039
|
+
it('should use only quoted name (issue #41)`', function () {
|
|
1040
|
+
expect(parse(function () {
|
|
1041
|
+
/**
|
|
1042
|
+
* @section "Brand Colors" Here you can find "all" the brand colors
|
|
1043
|
+
*/
|
|
1044
|
+
})[0])
|
|
1045
|
+
.to.eql({
|
|
1046
|
+
line: 1,
|
|
1047
|
+
source: '@section "Brand Colors" Here you can find "all" the brand colors',
|
|
1048
|
+
description: '',
|
|
1049
|
+
tags: [{
|
|
1050
|
+
tag: 'section',
|
|
1051
|
+
line: 2,
|
|
1052
|
+
type: '',
|
|
1053
|
+
name: 'Brand Colors',
|
|
1054
|
+
source: '@section "Brand Colors" Here you can find "all" the brand colors',
|
|
1055
|
+
optional: false,
|
|
1056
|
+
description: 'Here you can find "all" the brand colors'
|
|
1057
|
+
}]
|
|
1058
|
+
})
|
|
1059
|
+
})
|
|
1060
|
+
|
|
1061
|
+
it('should ignore inconsitent quoted groups (issue #41)`', function () {
|
|
1062
|
+
expect(parse(function () {
|
|
1063
|
+
/**
|
|
1064
|
+
* @section "Brand Colors Here you can find all the brand colors
|
|
1065
|
+
*/
|
|
1066
|
+
})[0])
|
|
1067
|
+
.to.eql({
|
|
1068
|
+
line: 1,
|
|
1069
|
+
source: '@section "Brand Colors Here you can find all the brand colors',
|
|
1070
|
+
description: '',
|
|
1071
|
+
tags: [{
|
|
1072
|
+
tag: 'section',
|
|
1073
|
+
line: 2,
|
|
1074
|
+
type: '',
|
|
1075
|
+
name: '"Brand',
|
|
1076
|
+
source: '@section "Brand Colors Here you can find all the brand colors',
|
|
1077
|
+
optional: false,
|
|
1078
|
+
description: 'Colors Here you can find all the brand colors'
|
|
1079
|
+
}]
|
|
1080
|
+
})
|
|
1081
|
+
})
|
|
891
1082
|
})
|