comment-parser 0.2.1 → 0.3.0

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.
@@ -0,0 +1,139 @@
1
+ var fs = require('fs');
2
+ var expect = require('chai').expect;
3
+ var parse = require('../index');
4
+
5
+ describe('parse() with custom tag parsers', function() {
6
+
7
+ function parsed(func, opts) {
8
+ var str = func.toString();
9
+ return parse(str.slice(
10
+ str.indexOf('{') + 1,
11
+ str.lastIndexOf('}')
12
+ ).trim(), opts);
13
+ }
14
+
15
+ function sample() {
16
+ /**
17
+ * @tag {type} name description
18
+ */
19
+ var a;
20
+ }
21
+
22
+ it('should use `opts.parsers`', function() {
23
+ var parsers = [
24
+ function everything(str) {
25
+ return {
26
+ source : str,
27
+ data : {
28
+ tag : 'tag',
29
+ type : 'type',
30
+ name : 'name',
31
+ optional : false,
32
+ description : 'description'
33
+ }
34
+ };
35
+ }
36
+ ];
37
+
38
+ expect(parsed(sample, {parsers: parsers})[0])
39
+ .to.eql({
40
+ line : 0,
41
+ description : '',
42
+ source : '@tag {type} name description',
43
+ tags: [{
44
+ tag : 'tag',
45
+ type : 'type',
46
+ name : 'name',
47
+ description : 'description',
48
+ optional : false,
49
+ source : '@tag {type} name description',
50
+ line : 1
51
+ }]
52
+ });
53
+ });
54
+
55
+ it('should merge parsers result', function() {
56
+ var parsers = [
57
+ function parser1(str) {
58
+ return {
59
+ source : '',
60
+ data : {tag: 'tag'},
61
+ };
62
+ },
63
+ function parser2(str) {
64
+ return {
65
+ source : '',
66
+ data : {type: 'type'},
67
+ };
68
+ },
69
+ function parser3(str) {
70
+ return {
71
+ source : '',
72
+ data : {
73
+ name : 'name',
74
+ description : 'description'
75
+ },
76
+ };
77
+ }
78
+ ];
79
+
80
+ expect(parsed(sample, {parsers: parsers})[0])
81
+ .to.eql({
82
+ line : 0,
83
+ description : '',
84
+ source : '@tag {type} name description',
85
+ tags: [{
86
+ tag : 'tag',
87
+ type : 'type',
88
+ name : 'name',
89
+ description : 'description',
90
+ optional : false,
91
+ source : '@tag {type} name description',
92
+ line : 1
93
+ }]
94
+ });
95
+ });
96
+
97
+ it('should catch parser exceptions and populate `errors` field', function() {
98
+ var parsers = [
99
+ function parser1(str) {
100
+ return {
101
+ source : '',
102
+ data : {tag: 'tag'}
103
+ };
104
+ },
105
+ function parser2(str) {
106
+ throw new Error('error 1');
107
+ },
108
+ function parser3(str) {
109
+ throw new Error('error 2');
110
+ },
111
+ function parser4(str) {
112
+ return {
113
+ source : '',
114
+ data : {name: 'name'}
115
+ };
116
+ },
117
+ ];
118
+
119
+ expect(parsed(sample, {parsers: parsers})[0])
120
+ .to.eql({
121
+ line : 0,
122
+ description : '',
123
+ source : '@tag {type} name description',
124
+ tags: [{
125
+ tag : 'tag',
126
+ type : '',
127
+ name : 'name',
128
+ description : '',
129
+ optional : false,
130
+ source : '@tag {type} name description',
131
+ errors : [
132
+ 'parser2: error 1',
133
+ 'parser3: error 2'
134
+ ],
135
+ line : 1
136
+ }]
137
+ });
138
+ });
139
+ });
@@ -2,39 +2,71 @@ var fs = require('fs');
2
2
  var expect = require('chai').expect;
3
3
  var parse = require('../index');
4
4
 
5
- describe('Single comment string parsing', function() {
5
+ describe('Comment string parsing', function() {
6
+
7
+ /**
8
+ * Source lines numeration:
9
+ *
10
+ * 0 function() {
11
+ * 1 // source with comments
12
+ * 2 }
13
+ *
14
+ */
6
15
 
7
16
  function parsed(func, opts) {
8
17
  var str = func.toString();
9
18
  return parse(str.slice(
10
19
  str.indexOf('{') + 1,
11
20
  str.lastIndexOf('}')
12
- ).trim(), opts);
21
+ ), opts);
13
22
  }
14
23
 
15
- it('should split the description', function() {
24
+ it('should parse doc block with description', function() {
25
+ expect(parsed(function(){
26
+ /**
27
+ * Description
28
+ */
29
+ })[0])
30
+ .to.eql({
31
+ description : 'Description',
32
+ source : 'Description',
33
+ line : 1,
34
+ tags : []
35
+ });
36
+ });
37
+
38
+ it('should skip surrounding empty lines while preserving line numbers', function() {
16
39
  expect(parsed(function(){
17
40
  /**
41
+ *
42
+ *
18
43
  * Description first line
19
44
  *
20
45
  * Description second line
46
+ *
21
47
  */
22
48
  var a;
23
- })[0].description)
24
- .to.eq('Description first line\n\nDescription second line');
49
+ })[0])
50
+ .eql({
51
+ description : 'Description first line\n\nDescription second line',
52
+ source : 'Description first line\n\nDescription second line',
53
+ line : 1,
54
+ tags : []
55
+ });
25
56
  });
26
57
 
27
- it('should keep description "" if omitted', function() {
58
+ it('should skip empty blocks', function() {
59
+
28
60
  expect(parsed(function(){
29
61
  /**
30
- *
62
+ *
31
63
  */
32
64
  var a;
33
- })[0].description)
34
- .to.eq('');
65
+ }).length)
66
+ .to.eq(0);
35
67
  });
36
68
 
37
- it('should parse multiple comments', function() {
69
+ it('should parse multiple doc blocks', function() {
38
70
  var p = parsed(function(){
39
71
  /**
40
72
  * Description first line
@@ -50,22 +82,37 @@ describe('Single comment string parsing', function() {
50
82
  expect(p.length)
51
83
  .to.eq(2);
52
84
 
53
- expect(p[0].description)
54
- .to.eq('Description first line');
85
+ expect(p[0])
86
+ .to.eql({
87
+ description : 'Description first line',
88
+ source : 'Description first line',
89
+ line : 1,
90
+ tags : []
91
+ });
55
92
 
56
- expect(p[1].description)
57
- .to.eq('Description second line');
93
+ expect(p[1])
94
+ .to.eql({
95
+ description : 'Description second line',
96
+ source : 'Description second line',
97
+ line : 6,
98
+ tags : []
99
+ });
58
100
  });
59
101
 
60
- it('should not parse one line comment', function() {
102
+ it('should parse one line block', function() {
61
103
  expect(parsed(function(){
62
104
  /** Description */
63
105
  var a;
64
- }).length)
65
- .to.eq(0);
106
+ })[0])
107
+ .to.eql({
108
+ description : 'Description',
109
+ source : 'Description',
110
+ line : 1,
111
+ tags : []
112
+ });
66
113
  });
67
114
 
68
- it('should return `null` for `/* */` comments', function() {
115
+ it('should skip `/* */` comments', function() {
69
116
  expect(parsed(function(){
70
117
  /*
71
118
  *
@@ -75,7 +122,7 @@ describe('Single comment string parsing', function() {
75
122
  .to.eq(0);
76
123
  });
77
124
 
78
- it('should return `null` for `/*** */` comments', function() {
125
+ it('should skip `/*** */` comments', function() {
79
126
  expect(parsed(function(){
80
127
  /*
81
128
  *
@@ -85,21 +132,46 @@ describe('Single comment string parsing', function() {
85
132
  .to.eq(0);
86
133
  });
87
134
 
135
+ it('should parse one line block with tag', function() {
136
+ expect(parsed(function(){
137
+ /** @tag */
138
+ var a;
139
+ })[0])
140
+ .to.eql({
141
+ description : '',
142
+ line : 1,
143
+ source : '@tag',
144
+ tags : [{
145
+ tag : 'tag',
146
+ type : '',
147
+ name : '',
148
+ description : '',
149
+ line : 1,
150
+ optional : false,
151
+ source : '@tag'
152
+ }]
153
+ });
154
+ });
155
+
88
156
  it('should parse `@tag`', function() {
89
157
  expect(parsed(function(){
90
158
  /**
159
+ *
91
160
  * @my-tag
92
161
  */
93
162
  var a;
94
163
  })[0])
95
164
  .to.eql({
96
- line : 0,
165
+ line : 1,
166
+ source : '@my-tag',
97
167
  description : '',
98
168
  tags: [{
99
- line : 1,
169
+ line : 3,
100
170
  tag : 'my-tag',
171
+ source : '@my-tag',
101
172
  type : '',
102
173
  name : '',
174
+ optional : false,
103
175
  description : ''
104
176
  }]
105
177
  });
@@ -113,94 +185,265 @@ describe('Single comment string parsing', function() {
113
185
  var a;
114
186
  })[0])
115
187
  .to.eql({
116
- line : 0,
188
+ line : 1,
189
+ source : '@my-tag {my.type}',
117
190
  description : '',
118
191
  tags: [{
119
- line : 1,
192
+ line : 2,
120
193
  tag : 'my-tag',
121
194
  type : 'my.type',
122
195
  name : '',
196
+ source : '@my-tag {my.type}',
197
+ optional : false,
198
+ description : ''
199
+ }]
200
+ });
201
+ });
202
+
203
+ it('should parse tag with name only `@tag name`', function() {
204
+ expect(parsed(function(){
205
+ /**
206
+ * @my-tag name
207
+ */
208
+ })[0])
209
+ .to.eql({
210
+ line : 1,
211
+ description : '',
212
+ source : '@my-tag name',
213
+ tags: [{
214
+ line : 2,
215
+ tag : 'my-tag',
216
+ type : '',
217
+ name : 'name',
218
+ source : '@my-tag name',
219
+ optional : false,
123
220
  description : ''
124
221
  }]
125
222
  });
126
223
  });
127
224
 
128
- it('should parse `@tag {my.type} name`', function() {
225
+ it('should parse tag with type and name `@tag {my.type} name`', function() {
129
226
  expect(parsed(function(){
130
227
  /**
131
228
  * @my-tag {my.type} name
132
229
  */
133
- var a;
134
230
  })[0])
135
231
  .to.eql({
136
- line : 0,
232
+ line : 1,
233
+ source : '@my-tag {my.type} name',
137
234
  description : '',
138
235
  tags: [{
139
236
  tag : 'my-tag',
140
- line : 1,
237
+ line : 2,
141
238
  type : 'my.type',
142
239
  name : 'name',
143
- description : ''
240
+ source : '@my-tag {my.type} name',
241
+ description : '',
242
+ optional : false
144
243
  }]
145
244
  });
146
245
  });
147
246
 
148
- it('should parse `@tag name`', function() {
247
+ it('should parse tag with type, name and description `@tag {my.type} name description`', function() {
149
248
  expect(parsed(function(){
150
249
  /**
151
- * @my-tag name
250
+ * @my-tag {my.type} name description
152
251
  */
153
252
  })[0])
154
253
  .to.eql({
155
- line : 0,
254
+ line : 1,
255
+ source : '@my-tag {my.type} name description',
156
256
  description : '',
157
257
  tags: [{
158
- line : 1,
159
258
  tag : 'my-tag',
160
- type : '',
259
+ line : 2,
260
+ type : 'my.type',
161
261
  name : 'name',
162
- description : ''
262
+ source : '@my-tag {my.type} name description',
263
+ description : 'description',
264
+ optional : false
265
+ }]
266
+ });
267
+ });
268
+
269
+ it('should parse tag with multiline description', function() {
270
+ expect(parsed(function(){
271
+ /**
272
+ * @my-tag {my.type} name description line 1
273
+ * description line 2
274
+ * description line 3
275
+ */
276
+ })[0])
277
+ .to.eql({
278
+ line : 1,
279
+ source : '@my-tag {my.type} name description line 1\ndescription line 2\ndescription line 3',
280
+ description : '',
281
+ tags: [{
282
+ tag : 'my-tag',
283
+ line : 2,
284
+ type : 'my.type',
285
+ name : 'name',
286
+ source : '@my-tag {my.type} name description line 1\ndescription line 2\ndescription line 3',
287
+ description : 'description line 1\ndescription line 2\ndescription line 3',
288
+ optional : false
163
289
  }]
164
290
  });
165
291
  });
166
292
 
167
- it('should parse `@tag {my.type} [name]`', function() {
293
+ it('should parse tag with type and optional name `@tag {my.type} [name]`', function() {
168
294
  expect(parsed(function(){
169
295
  /**
170
296
  * @my-tag {my.type} [name]
171
297
  */
172
298
  })[0])
173
299
  .to.eql({
174
- line : 0,
300
+ line : 1,
175
301
  description : '',
302
+ source : '@my-tag {my.type} [name]',
176
303
  tags: [{
177
304
  tag : 'my-tag',
178
- line : 1,
305
+ line : 2,
179
306
  type : 'my.type',
180
307
  name : 'name',
181
308
  description : '',
309
+ source : '@my-tag {my.type} [name]',
182
310
  optional : true
183
311
  }]
184
312
  });
185
313
  });
186
314
 
187
- it('should parse `@tag {my.type} [name=value]`', function() {
315
+ it('should parse tag with type and optional name with default value `@tag {my.type} [name=value]`', function() {
188
316
  expect(parsed(function(){
189
317
  /**
190
318
  * @my-tag {my.type} [name=value]
191
319
  */
192
320
  })[0])
193
321
  .to.eql({
194
- line : 0,
322
+ line : 1,
323
+ description : '',
324
+ source : '@my-tag {my.type} [name=value]',
325
+ tags: [{
326
+ tag : 'my-tag',
327
+ line : 2,
328
+ type : 'my.type',
329
+ name : 'name',
330
+ default : 'value',
331
+ source : '@my-tag {my.type} [name=value]',
332
+ description : '',
333
+ optional : true
334
+ }]
335
+ });
336
+ });
337
+
338
+ it('should tolerate default value with whitespces `@tag {my.type} [name=John Doe]`', function() {
339
+ expect(parsed(function(){
340
+ /**
341
+ * @my-tag {my.type} [name=John Doe]
342
+ */
343
+ })[0])
344
+ .to.eql({
345
+ line : 1,
195
346
  description : '',
347
+ source : '@my-tag {my.type} [name=John Doe]',
196
348
  tags: [{
197
349
  tag : 'my-tag',
198
- line : 1,
350
+ line : 2,
199
351
  type : 'my.type',
200
352
  name : 'name',
201
353
  description : '',
354
+ source : '@my-tag {my.type} [name=John Doe]',
355
+ optional : true,
356
+ default : 'John Doe'
357
+ }]
358
+ });
359
+ });
360
+
361
+ it('should tolerate quoted default value `@tag [name="yay!"]`', function() {
362
+ expect(parsed(function(){
363
+ /**
364
+ * @tag {t} [name="yay!"]
365
+ */
366
+ })[0])
367
+ .to.eql({
368
+ line: 1,
369
+ source: '@tag {t} [name="yay!"]',
370
+ description: '',
371
+ tags: [{
372
+ tag : 'tag',
373
+ line : 2,
374
+ type : 't',
375
+ name : 'name',
376
+ source : '@tag {t} [name="yay!"]',
377
+ default : 'yay!',
378
+ optional : true,
379
+ description : ''
380
+ }]
381
+ });
382
+ });
383
+
384
+ it('should keep value as is if quotes are mismatched `@tag [name="yay\']`', function() {
385
+ expect(parsed(function(){
386
+ /**
387
+ * @tag {t} [name="yay!'] desc
388
+ */
389
+ })[0])
390
+ .to.eql({
391
+ line: 1,
392
+ description: '',
393
+ source : '@tag {t} [name="yay!\'] desc',
394
+ tags: [{
395
+ tag : 'tag',
396
+ line : 2,
397
+ type : 't',
398
+ name : 'name',
399
+ source : '@tag {t} [name="yay!\'] desc',
400
+ default : '"yay!\'',
401
+ optional : true,
402
+ description : 'desc'
403
+ }]
404
+ });
405
+ });
406
+
407
+ it('should parse rest names `@tag ...name desc`', function() {
408
+ expect(parsed(function(){
409
+ /**
410
+ * @tag {t} ...name desc
411
+ */
412
+ })[0])
413
+ .to.eql({
414
+ line : 1,
415
+ description : '',
416
+ source : '@tag {t} ...name desc',
417
+ tags: [{
418
+ tag : 'tag',
419
+ line : 2,
420
+ type : 't',
421
+ name : '...name',
422
+ optional : false,
423
+ source : '@tag {t} ...name desc',
424
+ description : 'desc'
425
+ }]
426
+ });
427
+ });
428
+
429
+ it('should parse optionalrest names `@tag [...name] desc`', function() {
430
+ expect(parsed(function(){
431
+ /**
432
+ * @tag {t} [...name] desc
433
+ */
434
+ })[0])
435
+ .to.eql({
436
+ line : 1,
437
+ description : '',
438
+ source : '@tag {t} [...name] desc',
439
+ tags: [{
440
+ tag : 'tag',
441
+ line : 2,
442
+ type : 't',
443
+ name : '...name',
202
444
  optional : true,
203
- default : 'value'
445
+ source : '@tag {t} [...name] desc',
446
+ description : 'desc'
204
447
  }]
205
448
  });
206
449
  });
@@ -216,17 +459,22 @@ describe('Single comment string parsing', function() {
216
459
  .to.eql({
217
460
  line : 1,
218
461
  description : 'Description',
462
+ source : 'Description\n@my-tag1\n@my-tag2',
219
463
  tags : [{
220
464
  tag : 'my-tag1',
221
- line : 2,
465
+ line : 3,
222
466
  type : '',
223
467
  name : '',
468
+ optional : false,
469
+ source : '@my-tag1',
224
470
  description : ''
225
471
  }, {
226
472
  tag : 'my-tag2',
227
- line : 3,
473
+ line : 4,
228
474
  type : '',
229
475
  name : '',
476
+ optional : false,
477
+ source : '@my-tag2',
230
478
  description : ''
231
479
  }]
232
480
  });
@@ -244,23 +492,30 @@ describe('Single comment string parsing', function() {
244
492
  .to.eql({
245
493
  line : 1,
246
494
  description : 'Description',
495
+ source : "Description\n@my-tag name\n@my-tag name.sub-name\n@my-tag name.sub-name.sub-sub-name",
247
496
  tags : [{
248
497
  tag : 'my-tag',
249
- line : 2,
498
+ line : 3,
250
499
  type : '',
251
500
  name : 'name',
501
+ source : '@my-tag name',
502
+ optional : false,
252
503
  description : '',
253
504
  tags : [{
254
505
  tag : 'my-tag',
255
- line : 3,
506
+ line : 4,
256
507
  type : '',
257
508
  name : 'sub-name',
509
+ optional : false,
510
+ source : '@my-tag name.sub-name',
258
511
  description : '',
259
512
  tags : [{
260
513
  tag : 'my-tag',
261
- line : 4,
514
+ line : 5,
262
515
  type : '',
263
516
  name : 'sub-sub-name',
517
+ optional : false,
518
+ source : '@my-tag name.sub-name.sub-sub-name',
264
519
  description : ''
265
520
  }]
266
521
  }]
@@ -275,13 +530,16 @@ describe('Single comment string parsing', function() {
275
530
  */
276
531
  })[0])
277
532
  .to.eql({
278
- line: 0,
279
- description: '',
533
+ line : 1,
534
+ source : '@my-tag {{a: number}} name',
535
+ description : '',
280
536
  tags: [{
281
537
  tag : 'my-tag',
282
- line : 1,
538
+ line : 2,
283
539
  type : '{a: number}',
284
540
  name : 'name',
541
+ source : '@my-tag {{a: number}} name',
542
+ optional : false,
285
543
  description : ''
286
544
  }]
287
545
  });
@@ -294,15 +552,18 @@ describe('Single comment string parsing', function() {
294
552
  */
295
553
  })[0])
296
554
  .to.eql({
297
- line: 0,
298
- description: '',
555
+ line : 1,
556
+ description : '',
557
+ source : '@my-tag {{a: number} name',
299
558
  tags: [{
300
559
  tag : 'my-tag',
301
- line : 1,
560
+ line : 2,
302
561
  type : '',
303
562
  name : '',
304
- description : '{{a: number} name',
305
- error : 'Unpaired curly in type doc'
563
+ description : '',
564
+ source : '@my-tag {{a: number} name',
565
+ optional : false,
566
+ errors : ['parse_type: Invalid `{type}`, unpaired curlies']
306
567
  }]
307
568
  });
308
569
  });