@cjser/es-joy__jsdoccomment 0.96.0-cjser.2
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/CHANGES.md +883 -0
- package/LICENSE-MIT.txt +20 -0
- package/README.md +250 -0
- package/dist/index.d.ts +421 -0
- package/dist-cjser/index.cjs +1224 -0
- package/package.json +144 -0
- package/src/commentHandler.js +48 -0
- package/src/commentParserToESTree.js +525 -0
- package/src/estreeToString.js +234 -0
- package/src/index.js +59 -0
- package/src/inlineTagEscapes.js +73 -0
- package/src/jsdoccomment.js +705 -0
- package/src/parseComment.js +190 -0
- package/src/parseInlineTags.js +114 -0
- package/src/toCamelCase.js +13 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import {parse as jsdocTypePrattParse} from '@cjser/jsdoc-type-pratt-parser';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Removes initial and ending brackets from `rawType`
|
|
5
|
+
* @param {JsdocTypeLine[]|JsdocTag} container
|
|
6
|
+
* @param {boolean} [isArr]
|
|
7
|
+
* @returns {void}
|
|
8
|
+
*/
|
|
9
|
+
const stripEncapsulatingBrackets = (container, isArr) => {
|
|
10
|
+
if (isArr) {
|
|
11
|
+
const firstItem = /** @type {JsdocTypeLine[]} */ (container)[0];
|
|
12
|
+
firstItem.rawType = firstItem.rawType.replace(
|
|
13
|
+
/^\{/v, ''
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const lastItem = /** @type {JsdocTypeLine} */ (
|
|
17
|
+
/** @type {JsdocTypeLine[]} */ (
|
|
18
|
+
container
|
|
19
|
+
).at(-1)
|
|
20
|
+
);
|
|
21
|
+
lastItem.rawType = lastItem.rawType.replace(/\}$/v, '');
|
|
22
|
+
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
/** @type {JsdocTag} */ (container).rawType =
|
|
26
|
+
/** @type {JsdocTag} */ (container).rawType.replace(
|
|
27
|
+
/^\{/v, ''
|
|
28
|
+
).replace(/\}$/v, '');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {{
|
|
33
|
+
* delimiter: string,
|
|
34
|
+
* postDelimiter: string,
|
|
35
|
+
* rawType: string,
|
|
36
|
+
* initial: string,
|
|
37
|
+
* type: "JsdocTypeLine"
|
|
38
|
+
* }} JsdocTypeLine
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {{
|
|
43
|
+
* delimiter: string,
|
|
44
|
+
* description: string,
|
|
45
|
+
* postDelimiter: string,
|
|
46
|
+
* initial: string,
|
|
47
|
+
* type: "JsdocDescriptionLine"
|
|
48
|
+
* }} JsdocDescriptionLine
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* An inline tag whose `text` is the unescaped label value.
|
|
53
|
+
* @typedef {{
|
|
54
|
+
* format: 'pipe' | 'plain' | 'prefix' | 'space',
|
|
55
|
+
* namepathOrURL: string,
|
|
56
|
+
* tag: string,
|
|
57
|
+
* text: string,
|
|
58
|
+
* }} JsdocInlineTagNoType
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {JsdocInlineTagNoType & {
|
|
62
|
+
* type: "JsdocInlineTag"
|
|
63
|
+
* }} JsdocInlineTag
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @typedef {{
|
|
68
|
+
* delimiter: string,
|
|
69
|
+
* description: string,
|
|
70
|
+
* descriptionLines: JsdocDescriptionLine[],
|
|
71
|
+
* initial: string,
|
|
72
|
+
* inlineTags: JsdocInlineTag[]
|
|
73
|
+
* name: string,
|
|
74
|
+
* postDelimiter: string,
|
|
75
|
+
* postName: string,
|
|
76
|
+
* postTag: string,
|
|
77
|
+
* postType: string,
|
|
78
|
+
* rawType: string,
|
|
79
|
+
* parsedType: import('@cjser/jsdoc-type-pratt-parser').RootResult|null
|
|
80
|
+
* tag: string,
|
|
81
|
+
* type: "JsdocTag",
|
|
82
|
+
* typeLines: JsdocTypeLine[],
|
|
83
|
+
* }} JsdocTag
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @typedef {number} Integer
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {{
|
|
92
|
+
* delimiter: string,
|
|
93
|
+
* delimiterLineBreak: string,
|
|
94
|
+
* description: string,
|
|
95
|
+
* descriptionEndLine?: Integer,
|
|
96
|
+
* descriptionLines: JsdocDescriptionLine[],
|
|
97
|
+
* descriptionStartLine?: Integer,
|
|
98
|
+
* hasPreterminalDescription: 0|1,
|
|
99
|
+
* hasPreterminalTagDescription?: 1,
|
|
100
|
+
* initial: string,
|
|
101
|
+
* inlineTags: JsdocInlineTag[]
|
|
102
|
+
* lastDescriptionLine?: Integer,
|
|
103
|
+
* endLine: Integer,
|
|
104
|
+
* lineEnd: string,
|
|
105
|
+
* postDelimiter: string,
|
|
106
|
+
* tags: JsdocTag[],
|
|
107
|
+
* terminal: string,
|
|
108
|
+
* preterminalLineBreak: string,
|
|
109
|
+
* type: "JsdocBlock",
|
|
110
|
+
* }} JsdocBlock
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {object} cfg
|
|
115
|
+
* @param {string} cfg.text
|
|
116
|
+
* @param {string} cfg.tag
|
|
117
|
+
* @param {'pipe' | 'plain' | 'prefix' | 'space'} cfg.format
|
|
118
|
+
* @param {string} cfg.namepathOrURL
|
|
119
|
+
* @returns {JsdocInlineTag}
|
|
120
|
+
*/
|
|
121
|
+
const inlineTagToAST = ({text, tag, format, namepathOrURL}) => ({
|
|
122
|
+
text,
|
|
123
|
+
tag,
|
|
124
|
+
format,
|
|
125
|
+
namepathOrURL,
|
|
126
|
+
type: 'JsdocInlineTag'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/* eslint-disable jsdoc/reject-any-type -- API */
|
|
130
|
+
/**
|
|
131
|
+
* @typedef {{
|
|
132
|
+
* module?: boolean;
|
|
133
|
+
* strictMode?: boolean;
|
|
134
|
+
* asyncFunctionBody?: boolean;
|
|
135
|
+
* classContext?: boolean;
|
|
136
|
+
* computedPropertyParser?: (text: string, options?: any) => unknown;
|
|
137
|
+
* }} JtppOptions
|
|
138
|
+
*/
|
|
139
|
+
/* eslint-enable jsdoc/reject-any-type -- API */
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @typedef {object} CommentParserToESTreeOptions
|
|
143
|
+
* @property {'compact'|'preserve'} [spacing] By default, empty lines are
|
|
144
|
+
* compacted; set to 'preserve' to preserve empty comment lines.
|
|
145
|
+
* @property {boolean} [throwOnTypeParsingErrors]
|
|
146
|
+
* @property {JtppOptions} [jsdocTypePrattParserArgs]
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Converts comment parser AST to ESTree format.
|
|
151
|
+
* @param {import('./index.js').JsdocBlockWithInline} jsdoc
|
|
152
|
+
* @param {import('@cjser/jsdoc-type-pratt-parser').ParseMode} mode
|
|
153
|
+
* @param {CommentParserToESTreeOptions} [opts]
|
|
154
|
+
* @returns {JsdocBlock}
|
|
155
|
+
*/
|
|
156
|
+
const commentParserToESTree = (jsdoc, mode = 'typescript', {
|
|
157
|
+
spacing = 'compact',
|
|
158
|
+
throwOnTypeParsingErrors = false,
|
|
159
|
+
jsdocTypePrattParserArgs
|
|
160
|
+
} = {}) => {
|
|
161
|
+
/**
|
|
162
|
+
* Strips brackets from a tag's `rawType` values and adds `parsedType`
|
|
163
|
+
* @param {JsdocTag} lastTag
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
166
|
+
const cleanUpLastTag = (lastTag) => {
|
|
167
|
+
// Strip out `}` that encapsulates and is not part of
|
|
168
|
+
// the type
|
|
169
|
+
stripEncapsulatingBrackets(lastTag);
|
|
170
|
+
|
|
171
|
+
if (lastTag.typeLines.length) {
|
|
172
|
+
stripEncapsulatingBrackets(lastTag.typeLines, true);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Remove single empty line description.
|
|
176
|
+
if (lastTag.descriptionLines.length === 1 &&
|
|
177
|
+
lastTag.descriptionLines[0].description === '') {
|
|
178
|
+
lastTag.descriptionLines.length = 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// With even a multiline type now in full, add parsing
|
|
182
|
+
let parsedType = null;
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
parsedType = jsdocTypePrattParse(
|
|
186
|
+
lastTag.rawType, mode, jsdocTypePrattParserArgs
|
|
187
|
+
);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
// Ignore
|
|
190
|
+
if (throwOnTypeParsingErrors && lastTag.rawType) {
|
|
191
|
+
/** @type {Error} */ (
|
|
192
|
+
err
|
|
193
|
+
).message = `Tag @${lastTag.tag} with raw type ` +
|
|
194
|
+
`\`${lastTag.rawType}\` had parsing error: ${
|
|
195
|
+
/** @type {Error} */ (err).message}`;
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
lastTag.parsedType = parsedType;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const {source, inlineTags: blockInlineTags} = jsdoc;
|
|
204
|
+
|
|
205
|
+
const {tokens: {
|
|
206
|
+
delimiter: delimiterRoot,
|
|
207
|
+
lineEnd: lineEndRoot,
|
|
208
|
+
postDelimiter: postDelimiterRoot,
|
|
209
|
+
start: startRoot,
|
|
210
|
+
end: endRoot
|
|
211
|
+
}} = source[0];
|
|
212
|
+
|
|
213
|
+
const endLine = source.length - 1;
|
|
214
|
+
|
|
215
|
+
/** @type {JsdocBlock} */
|
|
216
|
+
const ast = {
|
|
217
|
+
delimiter: delimiterRoot,
|
|
218
|
+
delimiterLineBreak: '\n',
|
|
219
|
+
description: '',
|
|
220
|
+
|
|
221
|
+
descriptionLines: [],
|
|
222
|
+
inlineTags: blockInlineTags.map((t) => inlineTagToAST(t)),
|
|
223
|
+
|
|
224
|
+
initial: startRoot,
|
|
225
|
+
tags: [],
|
|
226
|
+
// `terminal` will be overwritten if there are other entries
|
|
227
|
+
terminal: endRoot,
|
|
228
|
+
preterminalLineBreak: '\n',
|
|
229
|
+
hasPreterminalDescription: 0,
|
|
230
|
+
endLine,
|
|
231
|
+
postDelimiter: postDelimiterRoot,
|
|
232
|
+
lineEnd: lineEndRoot,
|
|
233
|
+
|
|
234
|
+
type: 'JsdocBlock'
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @type {JsdocTag[]}
|
|
239
|
+
*/
|
|
240
|
+
const tags = [];
|
|
241
|
+
|
|
242
|
+
/** @type {Integer|undefined} */
|
|
243
|
+
let lastDescriptionLine;
|
|
244
|
+
|
|
245
|
+
/** @type {JsdocTag|null} */
|
|
246
|
+
let lastTag = null;
|
|
247
|
+
|
|
248
|
+
// Tracks when first valid tag description line is seen.
|
|
249
|
+
let tagDescriptionSeen = false;
|
|
250
|
+
|
|
251
|
+
let descLineStateOpen = true;
|
|
252
|
+
|
|
253
|
+
source.forEach((info, idx) => {
|
|
254
|
+
const {tokens} = info;
|
|
255
|
+
const {
|
|
256
|
+
delimiter,
|
|
257
|
+
description,
|
|
258
|
+
postDelimiter,
|
|
259
|
+
start: initial,
|
|
260
|
+
tag,
|
|
261
|
+
end,
|
|
262
|
+
type: rawType
|
|
263
|
+
} = tokens;
|
|
264
|
+
|
|
265
|
+
if (!tag && description && descLineStateOpen) {
|
|
266
|
+
if (ast.descriptionStartLine === undefined) {
|
|
267
|
+
ast.descriptionStartLine = idx;
|
|
268
|
+
}
|
|
269
|
+
ast.descriptionEndLine = idx;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (tag || end) {
|
|
273
|
+
descLineStateOpen = false;
|
|
274
|
+
if (lastDescriptionLine === undefined) {
|
|
275
|
+
lastDescriptionLine = idx;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Clean-up with last tag before end or new tag
|
|
279
|
+
if (lastTag) {
|
|
280
|
+
cleanUpLastTag(lastTag);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Stop the iteration when we reach the end
|
|
284
|
+
// but only when there is no tag earlier in the line
|
|
285
|
+
// to still process
|
|
286
|
+
if (end && !tag) {
|
|
287
|
+
ast.terminal = end;
|
|
288
|
+
|
|
289
|
+
// Check if there are any description lines and if not then this is a
|
|
290
|
+
// one line comment block.
|
|
291
|
+
const isDelimiterLine = ast.descriptionLines.length === 0 &&
|
|
292
|
+
delimiter === '/**';
|
|
293
|
+
|
|
294
|
+
// Remove delimiter line break for one line comments blocks.
|
|
295
|
+
if (isDelimiterLine) {
|
|
296
|
+
ast.delimiterLineBreak = '';
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (description) {
|
|
300
|
+
// Remove terminal line break at end when description is defined.
|
|
301
|
+
if (ast.terminal === '*/') {
|
|
302
|
+
ast.preterminalLineBreak = '';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (lastTag) {
|
|
306
|
+
ast.hasPreterminalTagDescription = 1;
|
|
307
|
+
} else {
|
|
308
|
+
ast.hasPreterminalDescription = 1;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const holder = lastTag || ast;
|
|
312
|
+
holder.description += (holder.description ? '\n' : '') + description;
|
|
313
|
+
|
|
314
|
+
// Do not include `delimiter` / `postDelimiter` for opening
|
|
315
|
+
// delimiter line.
|
|
316
|
+
|
|
317
|
+
holder.descriptionLines.push({
|
|
318
|
+
delimiter: isDelimiterLine ? '' : delimiter,
|
|
319
|
+
description,
|
|
320
|
+
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
|
321
|
+
initial,
|
|
322
|
+
type: 'JsdocDescriptionLine'
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const {
|
|
329
|
+
// eslint-disable-next-line no-unused-vars -- Discarding
|
|
330
|
+
end: ed,
|
|
331
|
+
delimiter: de,
|
|
332
|
+
postDelimiter: pd,
|
|
333
|
+
start: init,
|
|
334
|
+
...tkns
|
|
335
|
+
} = tokens;
|
|
336
|
+
|
|
337
|
+
if (!tokens.name) {
|
|
338
|
+
let i = 1;
|
|
339
|
+
while (Object.hasOwn(source, idx + i)) {
|
|
340
|
+
const {tokens: {
|
|
341
|
+
name,
|
|
342
|
+
postName,
|
|
343
|
+
postType,
|
|
344
|
+
tag: tg
|
|
345
|
+
}} = source[idx + i];
|
|
346
|
+
if (tg) {
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
if (name) {
|
|
350
|
+
tkns.postType = postType;
|
|
351
|
+
tkns.name = name;
|
|
352
|
+
tkns.postName = postName;
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
i++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* @type {JsdocInlineTag[]}
|
|
361
|
+
*/
|
|
362
|
+
const tagInlineTags = tag
|
|
363
|
+
// Assuming the tags from `source` are in the same order as `jsdoc.tags`
|
|
364
|
+
// we can use the `tags` length as index into the parser result tags.
|
|
365
|
+
// eslint-disable-next-line @stylistic/operator-linebreak -- Required
|
|
366
|
+
?
|
|
367
|
+
/**
|
|
368
|
+
* @type {import('comment-parser').Spec & {
|
|
369
|
+
* inlineTags: JsdocInlineTagNoType[]
|
|
370
|
+
* }}
|
|
371
|
+
*/ (
|
|
372
|
+
jsdoc.tags[tags.length]
|
|
373
|
+
).inlineTags.map(
|
|
374
|
+
(t) => inlineTagToAST(t)
|
|
375
|
+
)
|
|
376
|
+
: [];
|
|
377
|
+
|
|
378
|
+
/** @type {JsdocTag} */
|
|
379
|
+
const tagObj = {
|
|
380
|
+
...tkns,
|
|
381
|
+
initial: endLine ? init : '',
|
|
382
|
+
postDelimiter: lastDescriptionLine ? pd : '',
|
|
383
|
+
delimiter: lastDescriptionLine ? de : '',
|
|
384
|
+
descriptionLines: [],
|
|
385
|
+
inlineTags: tagInlineTags,
|
|
386
|
+
parsedType: null,
|
|
387
|
+
rawType: '',
|
|
388
|
+
type: 'JsdocTag',
|
|
389
|
+
typeLines: []
|
|
390
|
+
};
|
|
391
|
+
tagObj.tag = tagObj.tag.replace(/^@/v, '');
|
|
392
|
+
|
|
393
|
+
lastTag = tagObj;
|
|
394
|
+
tagDescriptionSeen = false;
|
|
395
|
+
|
|
396
|
+
tags.push(tagObj);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (rawType) {
|
|
400
|
+
// Will strip rawType brackets after this tag
|
|
401
|
+
/** @type {JsdocTag} */ (lastTag).typeLines.push(
|
|
402
|
+
/** @type {JsdocTag} */ (lastTag).typeLines.length
|
|
403
|
+
? {
|
|
404
|
+
delimiter,
|
|
405
|
+
postDelimiter,
|
|
406
|
+
rawType,
|
|
407
|
+
initial,
|
|
408
|
+
type: 'JsdocTypeLine'
|
|
409
|
+
}
|
|
410
|
+
: {
|
|
411
|
+
delimiter: '',
|
|
412
|
+
postDelimiter: '',
|
|
413
|
+
rawType,
|
|
414
|
+
initial: '',
|
|
415
|
+
type: 'JsdocTypeLine'
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
/** @type {JsdocTag} */ (lastTag).rawType += /** @type {JsdocTag} */ (
|
|
419
|
+
lastTag
|
|
420
|
+
).rawType
|
|
421
|
+
? '\n' + rawType
|
|
422
|
+
: rawType;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// In `compact` mode skip processing if `description` is an empty string
|
|
426
|
+
// unless lastTag is being processed.
|
|
427
|
+
//
|
|
428
|
+
// In `preserve` mode process when `description` is not the `empty string
|
|
429
|
+
// or the `delimiter` is not `/**` ensuring empty lines are preserved.
|
|
430
|
+
if ((lastTag || (spacing === 'compact' && description)) ||
|
|
431
|
+
(spacing === 'preserve' && (description || delimiter !== '/**'))) {
|
|
432
|
+
const holder = lastTag || ast;
|
|
433
|
+
|
|
434
|
+
// Check if there are any description lines and if not then this is a
|
|
435
|
+
// multi-line comment block with description on 0th line. Treat
|
|
436
|
+
// `delimiter` / `postDelimiter` / `initial` as being on a new line.
|
|
437
|
+
const isDelimiterLine = holder.descriptionLines.length === 0 &&
|
|
438
|
+
delimiter === '/**';
|
|
439
|
+
|
|
440
|
+
// Remove delimiter line break for one line comments blocks.
|
|
441
|
+
if (isDelimiterLine) {
|
|
442
|
+
ast.delimiterLineBreak = '';
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Track when the first description line is seen to avoid adding empty
|
|
446
|
+
// description lines for tag type lines.
|
|
447
|
+
tagDescriptionSeen ||= Boolean(lastTag &&
|
|
448
|
+
(rawType === '' || rawType?.endsWith('}')));
|
|
449
|
+
|
|
450
|
+
if (lastTag) {
|
|
451
|
+
if (tagDescriptionSeen) {
|
|
452
|
+
// The first tag description line is a continuation after type /
|
|
453
|
+
// name parsing.
|
|
454
|
+
const isFirstDescriptionLine = holder.descriptionLines.length === 0;
|
|
455
|
+
|
|
456
|
+
// For `compact` spacing must allow through first description line.
|
|
457
|
+
if (spacing === 'preserve' || (spacing === 'compact' &&
|
|
458
|
+
(description || isFirstDescriptionLine))) {
|
|
459
|
+
holder.descriptionLines.push({
|
|
460
|
+
delimiter: isFirstDescriptionLine ? '' : delimiter,
|
|
461
|
+
description,
|
|
462
|
+
postDelimiter: isFirstDescriptionLine ? '' : postDelimiter,
|
|
463
|
+
initial: isFirstDescriptionLine ? '' : initial,
|
|
464
|
+
type: 'JsdocDescriptionLine'
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
holder.descriptionLines.push({
|
|
470
|
+
delimiter: isDelimiterLine ? '' : delimiter,
|
|
471
|
+
description,
|
|
472
|
+
postDelimiter: isDelimiterLine ? '' : postDelimiter,
|
|
473
|
+
initial: isDelimiterLine ? `` : initial,
|
|
474
|
+
type: 'JsdocDescriptionLine'
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (!tag) {
|
|
479
|
+
if (lastTag) {
|
|
480
|
+
// For `compact` spacing must filter out any empty description lines
|
|
481
|
+
// after the initial `holder.description` has content.
|
|
482
|
+
if (tagDescriptionSeen && !(spacing === 'compact' &&
|
|
483
|
+
description === '' &&
|
|
484
|
+
holder.description)) {
|
|
485
|
+
holder.description += !holder.description
|
|
486
|
+
? description
|
|
487
|
+
: '\n' + description;
|
|
488
|
+
}
|
|
489
|
+
} else {
|
|
490
|
+
holder.description += !holder.description
|
|
491
|
+
? description
|
|
492
|
+
: '\n' + description;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Clean-up where last line itself has tag content
|
|
498
|
+
if (end && tag) {
|
|
499
|
+
ast.terminal = end;
|
|
500
|
+
ast.hasPreterminalTagDescription = 1;
|
|
501
|
+
|
|
502
|
+
// Remove terminal line break at end when tag is defined on last line.
|
|
503
|
+
if (ast.terminal === '*/') {
|
|
504
|
+
ast.preterminalLineBreak = '';
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
cleanUpLastTag(/** @type {JsdocTag} */ (lastTag));
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
ast.lastDescriptionLine = lastDescriptionLine;
|
|
512
|
+
ast.tags = tags;
|
|
513
|
+
|
|
514
|
+
return ast;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
const jsdocVisitorKeys = {
|
|
518
|
+
JsdocBlock: ['descriptionLines', 'tags', 'inlineTags'],
|
|
519
|
+
JsdocDescriptionLine: [],
|
|
520
|
+
JsdocTypeLine: [],
|
|
521
|
+
JsdocTag: ['parsedType', 'typeLines', 'descriptionLines', 'inlineTags'],
|
|
522
|
+
JsdocInlineTag: []
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
export {commentParserToESTree, jsdocVisitorKeys};
|