@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,234 @@
|
|
|
1
|
+
import {stringify as prattStringify} from '@cjser/jsdoc-type-pratt-parser';
|
|
2
|
+
|
|
3
|
+
import {encodeInlineTagText} from './inlineTagEscapes.js';
|
|
4
|
+
|
|
5
|
+
/* eslint-disable jsdoc/reject-function-type -- Different functions */
|
|
6
|
+
/** @type {Record<string, Function>} */
|
|
7
|
+
const stringifiers = {
|
|
8
|
+
/* eslint-enable jsdoc/reject-function-type -- Different functions */
|
|
9
|
+
JsdocBlock,
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {import('./commentParserToESTree.js').JsdocDescriptionLine} node
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
JsdocDescriptionLine ({
|
|
16
|
+
initial, delimiter, postDelimiter, description
|
|
17
|
+
}) {
|
|
18
|
+
return `${initial}${delimiter}${postDelimiter}${description}`;
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {import('./commentParserToESTree.js').JsdocTypeLine} node
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
JsdocTypeLine ({
|
|
26
|
+
initial, delimiter, postDelimiter, rawType
|
|
27
|
+
}) {
|
|
28
|
+
return `${initial}${delimiter}${postDelimiter}${rawType}`;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {import('./commentParserToESTree.js').JsdocInlineTag} node
|
|
33
|
+
*/
|
|
34
|
+
JsdocInlineTag ({format, namepathOrURL, tag, text}) {
|
|
35
|
+
const encodedText = encodeInlineTagText(text, format);
|
|
36
|
+
return format === 'pipe'
|
|
37
|
+
? `{@${tag} ${namepathOrURL}|${encodedText}}`
|
|
38
|
+
: format === 'plain'
|
|
39
|
+
? `{@${tag} ${namepathOrURL}}`
|
|
40
|
+
: format === 'prefix'
|
|
41
|
+
? `[${encodedText}]{@${tag} ${namepathOrURL}}`
|
|
42
|
+
// "space"
|
|
43
|
+
: `{@${tag} ${namepathOrURL} ${encodedText}}`;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
JsdocTag
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @todo convert for use by escodegen (until may be patched to support
|
|
51
|
+
* custom entries?).
|
|
52
|
+
* @param {import('./commentParserToESTree.js').JsdocBlock|
|
|
53
|
+
* import('./commentParserToESTree.js').JsdocDescriptionLine|
|
|
54
|
+
* import('./commentParserToESTree.js').JsdocTypeLine|
|
|
55
|
+
* import('./commentParserToESTree.js').JsdocTag|
|
|
56
|
+
* import('./commentParserToESTree.js').JsdocInlineTag|
|
|
57
|
+
* import('@cjser/jsdoc-type-pratt-parser').RootResult
|
|
58
|
+
* } node
|
|
59
|
+
* @param {import('./index.js').ESTreeToStringOptions} [opts]
|
|
60
|
+
* @throws {Error}
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
function estreeToString (node, opts = {}) {
|
|
64
|
+
if (Object.hasOwn(stringifiers, node.type)) {
|
|
65
|
+
return stringifiers[
|
|
66
|
+
/**
|
|
67
|
+
* @type {import('./commentParserToESTree.js').JsdocBlock|
|
|
68
|
+
* import('./commentParserToESTree.js').JsdocDescriptionLine|
|
|
69
|
+
* import('./commentParserToESTree.js').JsdocTypeLine|
|
|
70
|
+
* import('./commentParserToESTree.js').JsdocTag}
|
|
71
|
+
*/
|
|
72
|
+
(node).type
|
|
73
|
+
](
|
|
74
|
+
node,
|
|
75
|
+
opts
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// We use raw type instead but it is a key as other apps may wish to traverse
|
|
80
|
+
if (node.type.startsWith('JsdocType')) {
|
|
81
|
+
return opts.preferRawType
|
|
82
|
+
? ''
|
|
83
|
+
: `{${prattStringify(
|
|
84
|
+
/** @type {import('@cjser/jsdoc-type-pratt-parser').RootResult} */ (
|
|
85
|
+
node
|
|
86
|
+
),
|
|
87
|
+
opts.jtppStringificationRules
|
|
88
|
+
)}}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new Error(`Unhandled node type: ${node.type}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {import('./commentParserToESTree.js').JsdocBlock} node
|
|
96
|
+
* @param {import('./index.js').ESTreeToStringOptions} opts
|
|
97
|
+
* @returns {string}
|
|
98
|
+
*/
|
|
99
|
+
function JsdocBlock (node, opts) {
|
|
100
|
+
const {delimiter, delimiterLineBreak, descriptionLines,
|
|
101
|
+
initial, postDelimiter, preterminalLineBreak, tags, terminal} = node;
|
|
102
|
+
|
|
103
|
+
const terminalPrepend = preterminalLineBreak !== ''
|
|
104
|
+
? `${preterminalLineBreak}${initial} `
|
|
105
|
+
: '';
|
|
106
|
+
|
|
107
|
+
let result = `${initial}${delimiter}${postDelimiter}${delimiterLineBreak}`;
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < descriptionLines.length; i++) {
|
|
110
|
+
result += estreeToString(descriptionLines[i]);
|
|
111
|
+
|
|
112
|
+
if (i !== descriptionLines.length - 1 || tags.length) {
|
|
113
|
+
result += '\n';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < tags.length; i++) {
|
|
118
|
+
result += estreeToString(tags[i], opts);
|
|
119
|
+
|
|
120
|
+
if (i !== tags.length - 1) {
|
|
121
|
+
result += '\n';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
result += `${terminalPrepend}${terminal}`;
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {import('./commentParserToESTree.js').JsdocTag} node
|
|
132
|
+
* @param {import('./index.js').ESTreeToStringOptions} opts
|
|
133
|
+
* @returns {string}
|
|
134
|
+
*/
|
|
135
|
+
function JsdocTag (node, opts) {
|
|
136
|
+
const {
|
|
137
|
+
delimiter, descriptionLines, initial, name, parsedType, postDelimiter,
|
|
138
|
+
postName, postTag, postType, tag, typeLines
|
|
139
|
+
} = node;
|
|
140
|
+
|
|
141
|
+
let result = `${initial}${delimiter}${postDelimiter}@${tag}${postTag}`;
|
|
142
|
+
|
|
143
|
+
// Could do `rawType` but may have been changed; could also do
|
|
144
|
+
// `typeLines` but not as likely to be changed
|
|
145
|
+
// parsedType
|
|
146
|
+
// Comment this out later in favor of `parsedType`
|
|
147
|
+
// We can't use raw `typeLines` as first argument has delimiter on it
|
|
148
|
+
if (!parsedType || opts.preferRawType) {
|
|
149
|
+
if (typeLines.length) {
|
|
150
|
+
result += '{';
|
|
151
|
+
|
|
152
|
+
for (let i = 0; i < typeLines.length; i++) {
|
|
153
|
+
result += estreeToString(typeLines[i]);
|
|
154
|
+
|
|
155
|
+
if (i !== typeLines.length - 1) {
|
|
156
|
+
result += '\n';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
result += '}';
|
|
161
|
+
}
|
|
162
|
+
/* v8 ignore start */
|
|
163
|
+
} else if (parsedType?.type.startsWith('JsdocType')) {
|
|
164
|
+
result += `{${prattStringify(
|
|
165
|
+
/** @type {import('@cjser/jsdoc-type-pratt-parser').RootResult} */ (
|
|
166
|
+
parsedType
|
|
167
|
+
)
|
|
168
|
+
)}}`;
|
|
169
|
+
/* v8 ignore stop */
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check if the name appears on a separate line from the tag/type
|
|
173
|
+
// This is indicated by postTag and postType both being empty
|
|
174
|
+
let nameLineOffset = 0;
|
|
175
|
+
if (name && postTag === '' && postType === '') {
|
|
176
|
+
// The name is on a separate line from the tag
|
|
177
|
+
result += '\n';
|
|
178
|
+
|
|
179
|
+
if (descriptionLines.length > 0) {
|
|
180
|
+
const firstDescLine = descriptionLines[0];
|
|
181
|
+
/* v8 ignore next 3 */
|
|
182
|
+
if (firstDescLine.description === '' && firstDescLine.delimiter === '' &&
|
|
183
|
+
firstDescLine.postDelimiter === '' && firstDescLine.initial === '') {
|
|
184
|
+
// Empty first line, check if there's a second line with formatting
|
|
185
|
+
if (descriptionLines.length > 1) {
|
|
186
|
+
const nameLine = descriptionLines[1];
|
|
187
|
+
result += `${
|
|
188
|
+
nameLine.initial
|
|
189
|
+
}${nameLine.delimiter}${
|
|
190
|
+
nameLine.postDelimiter
|
|
191
|
+
}${name}${postName}${
|
|
192
|
+
nameLine.description
|
|
193
|
+
}`;
|
|
194
|
+
nameLineOffset = 2;
|
|
195
|
+
} else {
|
|
196
|
+
/* v8 ignore start */
|
|
197
|
+
// Fallback: just add name (shouldn't normally happen)
|
|
198
|
+
result += name + postName;
|
|
199
|
+
nameLineOffset = 1;
|
|
200
|
+
/* v8 ignore stop */
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
/* v8 ignore start */
|
|
204
|
+
// First description line has content, use it for the name line
|
|
205
|
+
const nameLine = descriptionLines[0];
|
|
206
|
+
result += `${nameLine.initial}${
|
|
207
|
+
nameLine.delimiter
|
|
208
|
+
}${nameLine.postDelimiter}${name}${postName}${nameLine.description}`;
|
|
209
|
+
nameLineOffset = 1;
|
|
210
|
+
/* v8 ignore stop */
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
// No description lines, need to construct the name line
|
|
214
|
+
// Use the same formatting as the tag line
|
|
215
|
+
result += `${initial}${delimiter}${postDelimiter}${name}${postName}`;
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
result += name ? `${postType}${name}${postName}` : postType;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (let i = nameLineOffset; i < descriptionLines.length; i++) {
|
|
222
|
+
const descriptionLine = descriptionLines[i];
|
|
223
|
+
|
|
224
|
+
if (i > 0 || nameLineOffset > 0) {
|
|
225
|
+
result += '\n';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
result += estreeToString(descriptionLine);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export {estreeToString};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* eslint-disable unicorn/no-barrel-files -- Reexports with typedefs */
|
|
2
|
+
/**
|
|
3
|
+
* An inline tag whose `text` is the unescaped label value.
|
|
4
|
+
* @typedef {import('./commentParserToESTree.js').JsdocInlineTagNoType & {
|
|
5
|
+
* start: number,
|
|
6
|
+
* end: number,
|
|
7
|
+
* }} InlineTag
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import('comment-parser').Spec & {
|
|
12
|
+
* line?: import('./commentParserToESTree.js').Integer,
|
|
13
|
+
* inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
|
|
14
|
+
* line?: import('./commentParserToESTree.js').Integer
|
|
15
|
+
* })[]
|
|
16
|
+
* }} JsdocTagWithInline
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Expands on comment-parser's `Block` interface.
|
|
21
|
+
* @typedef {{
|
|
22
|
+
* description: string,
|
|
23
|
+
* source: import('comment-parser').Line[],
|
|
24
|
+
* problems: import('comment-parser').Problem[],
|
|
25
|
+
* tags: JsdocTagWithInline[],
|
|
26
|
+
* inlineTags: (import('./commentParserToESTree.js').JsdocInlineTagNoType & {
|
|
27
|
+
* line?: import('./commentParserToESTree.js').Integer
|
|
28
|
+
* })[]
|
|
29
|
+
* }} JsdocBlockWithInline
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/* eslint-disable jsdoc/reject-any-type -- API */
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {{
|
|
35
|
+
* preferRawType?: boolean,
|
|
36
|
+
* jtppStringificationRules?: (
|
|
37
|
+
* node: import('estree').Node, options?: any
|
|
38
|
+
* ) => string
|
|
39
|
+
* }} ESTreeToStringOptions
|
|
40
|
+
*/
|
|
41
|
+
/* eslint-enable jsdoc/reject-any-type -- API */
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @callback CommentHandler
|
|
45
|
+
* @param {string} commentSelector
|
|
46
|
+
* @param {import('./index.js').JsdocBlockWithInline} jsdoc
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
export {visitorKeys as jsdocTypeVisitorKeys} from '@cjser/jsdoc-type-pratt-parser';
|
|
51
|
+
|
|
52
|
+
export * from '@cjser/jsdoc-type-pratt-parser';
|
|
53
|
+
|
|
54
|
+
export * from './commentHandler.js';
|
|
55
|
+
export * from './commentParserToESTree.js';
|
|
56
|
+
export * from './estreeToString.js';
|
|
57
|
+
export * from './jsdoccomment.js';
|
|
58
|
+
export * from './parseComment.js';
|
|
59
|
+
export * from './parseInlineTags.js';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {'pipe' | 'plain' | 'prefix' | 'space'} InlineTagFormat
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Gets the label delimiter for an inline-tag format.
|
|
7
|
+
* @param {InlineTagFormat} format
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
function getLabelDelimiter (format) {
|
|
11
|
+
return format === 'prefix' ? ']' : '}';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Decodes context-specific escape pairs in an inline-tag label.
|
|
16
|
+
* @param {string} text
|
|
17
|
+
* @param {InlineTagFormat} format
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function decodeInlineTagText (text, format) {
|
|
21
|
+
const delimiter = getLabelDelimiter(format);
|
|
22
|
+
let decoded = '';
|
|
23
|
+
let idx = 0;
|
|
24
|
+
|
|
25
|
+
while (idx < text.length) {
|
|
26
|
+
const character = text[idx];
|
|
27
|
+
if (character === '\\') {
|
|
28
|
+
const nextCharacter = text[idx + 1];
|
|
29
|
+
if (nextCharacter === '\\' || nextCharacter === delimiter) {
|
|
30
|
+
decoded += nextCharacter;
|
|
31
|
+
idx += 2;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
decoded += character;
|
|
36
|
+
idx++;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return decoded;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Minimally encodes an inline-tag label for its output context.
|
|
44
|
+
* @param {string} text
|
|
45
|
+
* @param {InlineTagFormat} format
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
export function encodeInlineTagText (text, format) {
|
|
49
|
+
const delimiter = getLabelDelimiter(format);
|
|
50
|
+
let encoded = '';
|
|
51
|
+
|
|
52
|
+
for (let idx = 0; idx < text.length; idx++) {
|
|
53
|
+
const character = text[idx];
|
|
54
|
+
if (character === delimiter) {
|
|
55
|
+
encoded += `\\${delimiter}`;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (character === '\\') {
|
|
60
|
+
const nextCharacter = text[idx + 1];
|
|
61
|
+
if (
|
|
62
|
+
[undefined, '\\', delimiter].includes(nextCharacter)
|
|
63
|
+
) {
|
|
64
|
+
encoded += '\\\\';
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
encoded += character;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return encoded;
|
|
73
|
+
}
|