@dcf-micro/eslint-config 5.0.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.
- package/dist/chunks/eslint-plugin-prettier.mjs +1716 -0
- package/dist/chunks/index.mjs +1341 -0
- package/dist/chunks/index10.mjs +39595 -0
- package/dist/chunks/index11.mjs +24 -0
- package/dist/chunks/index12.mjs +75273 -0
- package/dist/chunks/index13.mjs +55129 -0
- package/dist/chunks/index14.mjs +24 -0
- package/dist/chunks/index15.mjs +1441 -0
- package/dist/chunks/index2.mjs +31864 -0
- package/dist/chunks/index3.mjs +8154 -0
- package/dist/chunks/index4.mjs +24 -0
- package/dist/chunks/index5.mjs +44093 -0
- package/dist/chunks/index6.mjs +10371 -0
- package/dist/chunks/index7.mjs +21890 -0
- package/dist/chunks/index8.mjs +14424 -0
- package/dist/chunks/index9.mjs +194 -0
- package/dist/chunks/jiti.mjs +320 -0
- package/dist/index.d.mts +3897 -0
- package/dist/index.d.ts +3897 -0
- package/dist/index.mjs +4 -0
- package/dist/shared/eslint-config.BDBLGvXj.mjs +5282 -0
- package/dist/shared/eslint-config.BEdqg1el.mjs +12256 -0
- package/dist/shared/eslint-config.BKmXKm8B.mjs +5533 -0
- package/dist/shared/eslint-config.BjUMgISS.mjs +9012 -0
- package/dist/shared/eslint-config.Bk-3rH6Y.mjs +1355 -0
- package/dist/shared/eslint-config.BytuZ0Ec.mjs +20 -0
- package/dist/shared/eslint-config.C1V0I4Np.mjs +16900 -0
- package/dist/shared/eslint-config.CGxZQKHV.mjs +2091 -0
- package/dist/shared/eslint-config.COweQ1RR.mjs +5 -0
- package/dist/shared/eslint-config.CSnk9Q4w.mjs +9339 -0
- package/dist/shared/eslint-config.CWvTq0mr.mjs +2914 -0
- package/dist/shared/eslint-config.Ca4PTK8E.mjs +646 -0
- package/dist/shared/eslint-config.CmPTszkJ.mjs +3583 -0
- package/dist/shared/eslint-config.CqEANaNA.mjs +139622 -0
- package/dist/shared/eslint-config.CsePEcYJ.mjs +71 -0
- package/dist/shared/eslint-config.Cw6mETSZ.mjs +2580 -0
- package/dist/shared/eslint-config.DTVnsecK.mjs +1751 -0
- package/dist/shared/eslint-config.DWoU09EE.mjs +6958 -0
- package/dist/shared/eslint-config.DZvqTQUU.mjs +3818 -0
- package/dist/shared/eslint-config.Dhg7lT0g.mjs +1807 -0
- package/dist/shared/eslint-config.Du5y5qmf.mjs +200673 -0
- package/dist/shared/eslint-config.FKVuBSa4.mjs +394 -0
- package/dist/shared/eslint-config.I8d-HnmI.mjs +2654 -0
- package/dist/shared/eslint-config.YntqsQY1.mjs +40 -0
- package/dist/shared/eslint-config.uGTBNMD0.mjs +687 -0
- package/package.json +56 -0
|
@@ -0,0 +1,2580 @@
|
|
|
1
|
+
var dist$1 = {exports: {}};
|
|
2
|
+
|
|
3
|
+
var dist = dist$1.exports;
|
|
4
|
+
|
|
5
|
+
var hasRequiredDist;
|
|
6
|
+
|
|
7
|
+
function requireDist () {
|
|
8
|
+
if (hasRequiredDist) return dist$1.exports;
|
|
9
|
+
hasRequiredDist = 1;
|
|
10
|
+
(function (module, exports) {
|
|
11
|
+
(function (global, factory) {
|
|
12
|
+
factory(exports) ;
|
|
13
|
+
})(dist, (function (exports) {
|
|
14
|
+
function tokenToString(token) {
|
|
15
|
+
if (token.text !== undefined && token.text !== '') {
|
|
16
|
+
return `'${token.type}' with value '${token.text}'`;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return `'${token.type}'`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
class NoParsletFoundError extends Error {
|
|
23
|
+
constructor(token) {
|
|
24
|
+
super(`No parslet found for token: ${tokenToString(token)}`);
|
|
25
|
+
this.token = token;
|
|
26
|
+
Object.setPrototypeOf(this, NoParsletFoundError.prototype);
|
|
27
|
+
}
|
|
28
|
+
getToken() {
|
|
29
|
+
return this.token;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class EarlyEndOfParseError extends Error {
|
|
33
|
+
constructor(token) {
|
|
34
|
+
super(`The parsing ended early. The next token was: ${tokenToString(token)}`);
|
|
35
|
+
this.token = token;
|
|
36
|
+
Object.setPrototypeOf(this, EarlyEndOfParseError.prototype);
|
|
37
|
+
}
|
|
38
|
+
getToken() {
|
|
39
|
+
return this.token;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class UnexpectedTypeError extends Error {
|
|
43
|
+
constructor(result, message) {
|
|
44
|
+
let error = `Unexpected type: '${result.type}'.`;
|
|
45
|
+
if (message !== undefined) {
|
|
46
|
+
error += ` Message: ${message}`;
|
|
47
|
+
}
|
|
48
|
+
super(error);
|
|
49
|
+
Object.setPrototypeOf(this, UnexpectedTypeError.prototype);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// export class UnexpectedTokenError extends Error {
|
|
53
|
+
// private expected: Token
|
|
54
|
+
// private found: Token
|
|
55
|
+
//
|
|
56
|
+
// constructor (expected: Token, found: Token) {
|
|
57
|
+
// super(`The parsing ended early. The next token was: ${tokenToString(token)}`)
|
|
58
|
+
//
|
|
59
|
+
// this.token = token
|
|
60
|
+
//
|
|
61
|
+
// Object.setPrototypeOf(this, EarlyEndOfParseError.prototype)
|
|
62
|
+
// }
|
|
63
|
+
//
|
|
64
|
+
// getToken() {
|
|
65
|
+
// return this.token
|
|
66
|
+
// }
|
|
67
|
+
// }
|
|
68
|
+
|
|
69
|
+
function makePunctuationRule(type) {
|
|
70
|
+
return text => {
|
|
71
|
+
if (text.startsWith(type)) {
|
|
72
|
+
return { type, text: type };
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function getQuoted(text) {
|
|
80
|
+
let position = 0;
|
|
81
|
+
let char;
|
|
82
|
+
const mark = text[0];
|
|
83
|
+
let escaped = false;
|
|
84
|
+
if (mark !== '\'' && mark !== '"') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
while (position < text.length) {
|
|
88
|
+
position++;
|
|
89
|
+
char = text[position];
|
|
90
|
+
if (!escaped && char === mark) {
|
|
91
|
+
position++;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
escaped = !escaped && char === '\\';
|
|
95
|
+
}
|
|
96
|
+
if (char !== mark) {
|
|
97
|
+
throw new Error('Unterminated String');
|
|
98
|
+
}
|
|
99
|
+
return text.slice(0, position);
|
|
100
|
+
}
|
|
101
|
+
const identifierStartRegex = /[$_\p{ID_Start}]|\\u\p{Hex_Digit}{4}|\\u\{0*(?:\p{Hex_Digit}{1,5}|10\p{Hex_Digit}{4})\}/u;
|
|
102
|
+
// A hyphen is not technically allowed, but to keep it liberal for now,
|
|
103
|
+
// adding it here
|
|
104
|
+
const identifierContinueRegex = /[$\-\p{ID_Continue}\u200C\u200D]|\\u\p{Hex_Digit}{4}|\\u\{0*(?:\p{Hex_Digit}{1,5}|10\p{Hex_Digit}{4})\}/u;
|
|
105
|
+
function getIdentifier(text) {
|
|
106
|
+
let char = text[0];
|
|
107
|
+
if (!identifierStartRegex.test(char)) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
let position = 1;
|
|
111
|
+
do {
|
|
112
|
+
char = text[position];
|
|
113
|
+
if (!identifierContinueRegex.test(char)) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
position++;
|
|
117
|
+
} while (position < text.length);
|
|
118
|
+
return text.slice(0, position);
|
|
119
|
+
}
|
|
120
|
+
// we are a bit more liberal than TypeScript here and allow `NaN`, `Infinity` and `-Infinity`
|
|
121
|
+
const numberRegex = /^(NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity))/;
|
|
122
|
+
function getNumber(text) {
|
|
123
|
+
var _a, _b;
|
|
124
|
+
return (_b = (_a = numberRegex.exec(text)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null;
|
|
125
|
+
}
|
|
126
|
+
const identifierRule = text => {
|
|
127
|
+
const value = getIdentifier(text);
|
|
128
|
+
if (value == null) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
type: 'Identifier',
|
|
133
|
+
text: value
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
function makeKeyWordRule(type) {
|
|
137
|
+
return text => {
|
|
138
|
+
if (!text.startsWith(type)) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const prepends = text[type.length];
|
|
142
|
+
if (prepends !== undefined && identifierContinueRegex.test(prepends)) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
type,
|
|
147
|
+
text: type
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const stringValueRule = text => {
|
|
152
|
+
const value = getQuoted(text);
|
|
153
|
+
if (value == null) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
type: 'StringValue',
|
|
158
|
+
text: value
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
const eofRule = text => {
|
|
162
|
+
if (text.length > 0) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
type: 'EOF',
|
|
167
|
+
text: ''
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
const numberRule = text => {
|
|
171
|
+
const value = getNumber(text);
|
|
172
|
+
if (value === null) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
type: 'Number',
|
|
177
|
+
text: value
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
const rules = [
|
|
181
|
+
eofRule,
|
|
182
|
+
makePunctuationRule('=>'),
|
|
183
|
+
makePunctuationRule('('),
|
|
184
|
+
makePunctuationRule(')'),
|
|
185
|
+
makePunctuationRule('{'),
|
|
186
|
+
makePunctuationRule('}'),
|
|
187
|
+
makePunctuationRule('['),
|
|
188
|
+
makePunctuationRule(']'),
|
|
189
|
+
makePunctuationRule('|'),
|
|
190
|
+
makePunctuationRule('&'),
|
|
191
|
+
makePunctuationRule('<'),
|
|
192
|
+
makePunctuationRule('>'),
|
|
193
|
+
makePunctuationRule(','),
|
|
194
|
+
makePunctuationRule(';'),
|
|
195
|
+
makePunctuationRule('*'),
|
|
196
|
+
makePunctuationRule('?'),
|
|
197
|
+
makePunctuationRule('!'),
|
|
198
|
+
makePunctuationRule('='),
|
|
199
|
+
makePunctuationRule(':'),
|
|
200
|
+
makePunctuationRule('...'),
|
|
201
|
+
makePunctuationRule('.'),
|
|
202
|
+
makePunctuationRule('#'),
|
|
203
|
+
makePunctuationRule('~'),
|
|
204
|
+
makePunctuationRule('/'),
|
|
205
|
+
makePunctuationRule('@'),
|
|
206
|
+
makeKeyWordRule('undefined'),
|
|
207
|
+
makeKeyWordRule('null'),
|
|
208
|
+
makeKeyWordRule('function'),
|
|
209
|
+
makeKeyWordRule('this'),
|
|
210
|
+
makeKeyWordRule('new'),
|
|
211
|
+
makeKeyWordRule('module'),
|
|
212
|
+
makeKeyWordRule('event'),
|
|
213
|
+
makeKeyWordRule('external'),
|
|
214
|
+
makeKeyWordRule('typeof'),
|
|
215
|
+
makeKeyWordRule('keyof'),
|
|
216
|
+
makeKeyWordRule('readonly'),
|
|
217
|
+
makeKeyWordRule('import'),
|
|
218
|
+
makeKeyWordRule('is'),
|
|
219
|
+
makeKeyWordRule('in'),
|
|
220
|
+
makeKeyWordRule('asserts'),
|
|
221
|
+
numberRule,
|
|
222
|
+
identifierRule,
|
|
223
|
+
stringValueRule
|
|
224
|
+
];
|
|
225
|
+
const breakingWhitespaceRegex = /^\s*\n\s*/;
|
|
226
|
+
class Lexer {
|
|
227
|
+
static create(text) {
|
|
228
|
+
const current = this.read(text);
|
|
229
|
+
text = current.text;
|
|
230
|
+
const next = this.read(text);
|
|
231
|
+
text = next.text;
|
|
232
|
+
return new Lexer(text, undefined, current.token, next.token);
|
|
233
|
+
}
|
|
234
|
+
constructor(text, previous, current, next) {
|
|
235
|
+
this.text = '';
|
|
236
|
+
this.text = text;
|
|
237
|
+
this.previous = previous;
|
|
238
|
+
this.current = current;
|
|
239
|
+
this.next = next;
|
|
240
|
+
}
|
|
241
|
+
static read(text, startOfLine = false) {
|
|
242
|
+
startOfLine = startOfLine || breakingWhitespaceRegex.test(text);
|
|
243
|
+
text = text.trim();
|
|
244
|
+
for (const rule of rules) {
|
|
245
|
+
const partial = rule(text);
|
|
246
|
+
if (partial !== null) {
|
|
247
|
+
const token = Object.assign(Object.assign({}, partial), { startOfLine });
|
|
248
|
+
text = text.slice(token.text.length);
|
|
249
|
+
return { text, token };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
throw new Error('Unexpected Token ' + text);
|
|
253
|
+
}
|
|
254
|
+
advance() {
|
|
255
|
+
const next = Lexer.read(this.text);
|
|
256
|
+
return new Lexer(next.text, this.current, this.next, next.token);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Throws an error if the provided result is not a {@link RootResult}
|
|
262
|
+
*/
|
|
263
|
+
function assertRootResult(result) {
|
|
264
|
+
if (result === undefined) {
|
|
265
|
+
throw new Error('Unexpected undefined');
|
|
266
|
+
}
|
|
267
|
+
if (result.type === 'JsdocTypeKeyValue' || result.type === 'JsdocTypeParameterList' ||
|
|
268
|
+
result.type === 'JsdocTypeProperty' || result.type === 'JsdocTypeReadonlyProperty' ||
|
|
269
|
+
result.type === 'JsdocTypeObjectField' || result.type === 'JsdocTypeJsdocObjectField' ||
|
|
270
|
+
result.type === 'JsdocTypeIndexSignature' || result.type === 'JsdocTypeMappedType') {
|
|
271
|
+
throw new UnexpectedTypeError(result);
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
function assertPlainKeyValueOrRootResult(result) {
|
|
276
|
+
if (result.type === 'JsdocTypeKeyValue') {
|
|
277
|
+
return assertPlainKeyValueResult(result);
|
|
278
|
+
}
|
|
279
|
+
return assertRootResult(result);
|
|
280
|
+
}
|
|
281
|
+
function assertPlainKeyValueOrNameResult(result) {
|
|
282
|
+
if (result.type === 'JsdocTypeName') {
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
return assertPlainKeyValueResult(result);
|
|
286
|
+
}
|
|
287
|
+
function assertPlainKeyValueResult(result) {
|
|
288
|
+
if (result.type !== 'JsdocTypeKeyValue') {
|
|
289
|
+
throw new UnexpectedTypeError(result);
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
function assertNumberOrVariadicNameResult(result) {
|
|
294
|
+
var _a;
|
|
295
|
+
if (result.type === 'JsdocTypeVariadic') {
|
|
296
|
+
if (((_a = result.element) === null || _a === void 0 ? void 0 : _a.type) === 'JsdocTypeName') {
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
throw new UnexpectedTypeError(result);
|
|
300
|
+
}
|
|
301
|
+
if (result.type !== 'JsdocTypeNumber' && result.type !== 'JsdocTypeName') {
|
|
302
|
+
throw new UnexpectedTypeError(result);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
function isSquaredProperty(result) {
|
|
307
|
+
return result.type === 'JsdocTypeIndexSignature' || result.type === 'JsdocTypeMappedType';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// higher precedence = higher importance
|
|
311
|
+
var Precedence;
|
|
312
|
+
(function (Precedence) {
|
|
313
|
+
Precedence[Precedence["ALL"] = 0] = "ALL";
|
|
314
|
+
Precedence[Precedence["PARAMETER_LIST"] = 1] = "PARAMETER_LIST";
|
|
315
|
+
Precedence[Precedence["OBJECT"] = 2] = "OBJECT";
|
|
316
|
+
Precedence[Precedence["KEY_VALUE"] = 3] = "KEY_VALUE";
|
|
317
|
+
Precedence[Precedence["INDEX_BRACKETS"] = 4] = "INDEX_BRACKETS";
|
|
318
|
+
Precedence[Precedence["UNION"] = 5] = "UNION";
|
|
319
|
+
Precedence[Precedence["INTERSECTION"] = 6] = "INTERSECTION";
|
|
320
|
+
Precedence[Precedence["PREFIX"] = 7] = "PREFIX";
|
|
321
|
+
Precedence[Precedence["INFIX"] = 8] = "INFIX";
|
|
322
|
+
Precedence[Precedence["TUPLE"] = 9] = "TUPLE";
|
|
323
|
+
Precedence[Precedence["SYMBOL"] = 10] = "SYMBOL";
|
|
324
|
+
Precedence[Precedence["OPTIONAL"] = 11] = "OPTIONAL";
|
|
325
|
+
Precedence[Precedence["NULLABLE"] = 12] = "NULLABLE";
|
|
326
|
+
Precedence[Precedence["KEY_OF_TYPE_OF"] = 13] = "KEY_OF_TYPE_OF";
|
|
327
|
+
Precedence[Precedence["FUNCTION"] = 14] = "FUNCTION";
|
|
328
|
+
Precedence[Precedence["ARROW"] = 15] = "ARROW";
|
|
329
|
+
Precedence[Precedence["ARRAY_BRACKETS"] = 16] = "ARRAY_BRACKETS";
|
|
330
|
+
Precedence[Precedence["GENERIC"] = 17] = "GENERIC";
|
|
331
|
+
Precedence[Precedence["NAME_PATH"] = 18] = "NAME_PATH";
|
|
332
|
+
Precedence[Precedence["PARENTHESIS"] = 19] = "PARENTHESIS";
|
|
333
|
+
Precedence[Precedence["SPECIAL_TYPES"] = 20] = "SPECIAL_TYPES";
|
|
334
|
+
})(Precedence || (Precedence = {}));
|
|
335
|
+
|
|
336
|
+
class Parser {
|
|
337
|
+
constructor(grammar, textOrLexer, baseParser) {
|
|
338
|
+
this.grammar = grammar;
|
|
339
|
+
if (typeof textOrLexer === 'string') {
|
|
340
|
+
this._lexer = Lexer.create(textOrLexer);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
this._lexer = textOrLexer;
|
|
344
|
+
}
|
|
345
|
+
this.baseParser = baseParser;
|
|
346
|
+
}
|
|
347
|
+
get lexer() {
|
|
348
|
+
return this._lexer;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Parses a given string and throws an error if the parse ended before the end of the string.
|
|
352
|
+
*/
|
|
353
|
+
parse() {
|
|
354
|
+
const result = this.parseType(Precedence.ALL);
|
|
355
|
+
if (this.lexer.current.type !== 'EOF') {
|
|
356
|
+
throw new EarlyEndOfParseError(this.lexer.current);
|
|
357
|
+
}
|
|
358
|
+
return result;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Parses with the current lexer and asserts that the result is a {@link RootResult}.
|
|
362
|
+
*/
|
|
363
|
+
parseType(precedence) {
|
|
364
|
+
return assertRootResult(this.parseIntermediateType(precedence));
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* The main parsing function. First it tries to parse the current state in the prefix step, and then it continues
|
|
368
|
+
* to parse the state in the infix step.
|
|
369
|
+
*/
|
|
370
|
+
parseIntermediateType(precedence) {
|
|
371
|
+
const result = this.tryParslets(null, precedence);
|
|
372
|
+
if (result === null) {
|
|
373
|
+
throw new NoParsletFoundError(this.lexer.current);
|
|
374
|
+
}
|
|
375
|
+
return this.parseInfixIntermediateType(result, precedence);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* In the infix parsing step the parser continues to parse the current state with all parslets until none returns
|
|
379
|
+
* a result.
|
|
380
|
+
*/
|
|
381
|
+
parseInfixIntermediateType(left, precedence) {
|
|
382
|
+
let result = this.tryParslets(left, precedence);
|
|
383
|
+
while (result !== null) {
|
|
384
|
+
left = result;
|
|
385
|
+
result = this.tryParslets(left, precedence);
|
|
386
|
+
}
|
|
387
|
+
return left;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Tries to parse the current state with all parslets in the grammar and returns the first non null result.
|
|
391
|
+
*/
|
|
392
|
+
tryParslets(left, precedence) {
|
|
393
|
+
for (const parslet of this.grammar) {
|
|
394
|
+
const result = parslet(this, precedence, left);
|
|
395
|
+
if (result !== null) {
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* If the given type equals the current type of the {@link Lexer} advance the lexer. Return true if the lexer was
|
|
403
|
+
* advanced.
|
|
404
|
+
*/
|
|
405
|
+
consume(types) {
|
|
406
|
+
if (!Array.isArray(types)) {
|
|
407
|
+
types = [types];
|
|
408
|
+
}
|
|
409
|
+
if (types.includes(this.lexer.current.type)) {
|
|
410
|
+
this._lexer = this.lexer.advance();
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
acceptLexerState(parser) {
|
|
418
|
+
this._lexer = parser.lexer;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function isQuestionMarkUnknownType(next) {
|
|
423
|
+
return next === 'EOF' || next === '|' || next === ',' || next === ')' || next === '>';
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const nullableParslet = (parser, precedence, left) => {
|
|
427
|
+
const type = parser.lexer.current.type;
|
|
428
|
+
const next = parser.lexer.next.type;
|
|
429
|
+
const accept = ((left == null) && type === '?' && !isQuestionMarkUnknownType(next)) ||
|
|
430
|
+
((left != null) && type === '?');
|
|
431
|
+
if (!accept) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
parser.consume('?');
|
|
435
|
+
if (left == null) {
|
|
436
|
+
return {
|
|
437
|
+
type: 'JsdocTypeNullable',
|
|
438
|
+
element: parser.parseType(Precedence.NULLABLE),
|
|
439
|
+
meta: {
|
|
440
|
+
position: 'prefix'
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
return {
|
|
446
|
+
type: 'JsdocTypeNullable',
|
|
447
|
+
element: assertRootResult(left),
|
|
448
|
+
meta: {
|
|
449
|
+
position: 'suffix'
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
function composeParslet(options) {
|
|
456
|
+
const parslet = (parser, curPrecedence, left) => {
|
|
457
|
+
const type = parser.lexer.current.type;
|
|
458
|
+
const next = parser.lexer.next.type;
|
|
459
|
+
if (left === null) {
|
|
460
|
+
if ('parsePrefix' in options) {
|
|
461
|
+
if (options.accept(type, next)) {
|
|
462
|
+
return options.parsePrefix(parser);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
if ('parseInfix' in options) {
|
|
468
|
+
if (options.precedence > curPrecedence && options.accept(type, next)) {
|
|
469
|
+
return options.parseInfix(parser, left);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
};
|
|
475
|
+
// for debugging
|
|
476
|
+
Object.defineProperty(parslet, 'name', {
|
|
477
|
+
value: options.name
|
|
478
|
+
});
|
|
479
|
+
return parslet;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const optionalParslet = composeParslet({
|
|
483
|
+
name: 'optionalParslet',
|
|
484
|
+
accept: type => type === '=',
|
|
485
|
+
precedence: Precedence.OPTIONAL,
|
|
486
|
+
parsePrefix: parser => {
|
|
487
|
+
parser.consume('=');
|
|
488
|
+
return {
|
|
489
|
+
type: 'JsdocTypeOptional',
|
|
490
|
+
element: parser.parseType(Precedence.OPTIONAL),
|
|
491
|
+
meta: {
|
|
492
|
+
position: 'prefix'
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
},
|
|
496
|
+
parseInfix: (parser, left) => {
|
|
497
|
+
parser.consume('=');
|
|
498
|
+
return {
|
|
499
|
+
type: 'JsdocTypeOptional',
|
|
500
|
+
element: assertRootResult(left),
|
|
501
|
+
meta: {
|
|
502
|
+
position: 'suffix'
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
const numberParslet = composeParslet({
|
|
509
|
+
name: 'numberParslet',
|
|
510
|
+
accept: type => type === 'Number',
|
|
511
|
+
parsePrefix: parser => {
|
|
512
|
+
const value = parseFloat(parser.lexer.current.text);
|
|
513
|
+
parser.consume('Number');
|
|
514
|
+
return {
|
|
515
|
+
type: 'JsdocTypeNumber',
|
|
516
|
+
value
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
const parenthesisParslet = composeParslet({
|
|
522
|
+
name: 'parenthesisParslet',
|
|
523
|
+
accept: type => type === '(',
|
|
524
|
+
parsePrefix: parser => {
|
|
525
|
+
parser.consume('(');
|
|
526
|
+
if (parser.consume(')')) {
|
|
527
|
+
return {
|
|
528
|
+
type: 'JsdocTypeParameterList',
|
|
529
|
+
elements: []
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
const result = parser.parseIntermediateType(Precedence.ALL);
|
|
533
|
+
if (!parser.consume(')')) {
|
|
534
|
+
throw new Error('Unterminated parenthesis');
|
|
535
|
+
}
|
|
536
|
+
if (result.type === 'JsdocTypeParameterList') {
|
|
537
|
+
return result;
|
|
538
|
+
}
|
|
539
|
+
else if (result.type === 'JsdocTypeKeyValue') {
|
|
540
|
+
return {
|
|
541
|
+
type: 'JsdocTypeParameterList',
|
|
542
|
+
elements: [result]
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return {
|
|
546
|
+
type: 'JsdocTypeParenthesis',
|
|
547
|
+
element: assertRootResult(result)
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
const specialTypesParslet = composeParslet({
|
|
553
|
+
name: 'specialTypesParslet',
|
|
554
|
+
accept: (type, next) => (type === '?' && isQuestionMarkUnknownType(next)) ||
|
|
555
|
+
type === 'null' || type === 'undefined' || type === '*',
|
|
556
|
+
parsePrefix: parser => {
|
|
557
|
+
if (parser.consume('null')) {
|
|
558
|
+
return {
|
|
559
|
+
type: 'JsdocTypeNull'
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
if (parser.consume('undefined')) {
|
|
563
|
+
return {
|
|
564
|
+
type: 'JsdocTypeUndefined'
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
if (parser.consume('*')) {
|
|
568
|
+
return {
|
|
569
|
+
type: 'JsdocTypeAny'
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
if (parser.consume('?')) {
|
|
573
|
+
return {
|
|
574
|
+
type: 'JsdocTypeUnknown'
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
throw new Error('Unacceptable token: ' + parser.lexer.current.text);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
const notNullableParslet = composeParslet({
|
|
582
|
+
name: 'notNullableParslet',
|
|
583
|
+
accept: type => type === '!',
|
|
584
|
+
precedence: Precedence.NULLABLE,
|
|
585
|
+
parsePrefix: parser => {
|
|
586
|
+
parser.consume('!');
|
|
587
|
+
return {
|
|
588
|
+
type: 'JsdocTypeNotNullable',
|
|
589
|
+
element: parser.parseType(Precedence.NULLABLE),
|
|
590
|
+
meta: {
|
|
591
|
+
position: 'prefix'
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
},
|
|
595
|
+
parseInfix: (parser, left) => {
|
|
596
|
+
parser.consume('!');
|
|
597
|
+
return {
|
|
598
|
+
type: 'JsdocTypeNotNullable',
|
|
599
|
+
element: assertRootResult(left),
|
|
600
|
+
meta: {
|
|
601
|
+
position: 'suffix'
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
function createParameterListParslet({ allowTrailingComma }) {
|
|
608
|
+
return composeParslet({
|
|
609
|
+
name: 'parameterListParslet',
|
|
610
|
+
accept: type => type === ',',
|
|
611
|
+
precedence: Precedence.PARAMETER_LIST,
|
|
612
|
+
parseInfix: (parser, left) => {
|
|
613
|
+
const elements = [
|
|
614
|
+
assertPlainKeyValueOrRootResult(left)
|
|
615
|
+
];
|
|
616
|
+
parser.consume(',');
|
|
617
|
+
do {
|
|
618
|
+
try {
|
|
619
|
+
const next = parser.parseIntermediateType(Precedence.PARAMETER_LIST);
|
|
620
|
+
elements.push(assertPlainKeyValueOrRootResult(next));
|
|
621
|
+
}
|
|
622
|
+
catch (e) {
|
|
623
|
+
if (e instanceof NoParsletFoundError) {
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
throw e;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
} while (parser.consume(','));
|
|
631
|
+
if (elements.length > 0 && elements.slice(0, -1).some(e => e.type === 'JsdocTypeVariadic')) {
|
|
632
|
+
throw new Error('Only the last parameter may be a rest parameter');
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
type: 'JsdocTypeParameterList',
|
|
636
|
+
elements
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const genericParslet = composeParslet({
|
|
643
|
+
name: 'genericParslet',
|
|
644
|
+
accept: (type, next) => type === '<' || (type === '.' && next === '<'),
|
|
645
|
+
precedence: Precedence.GENERIC,
|
|
646
|
+
parseInfix: (parser, left) => {
|
|
647
|
+
const dot = parser.consume('.');
|
|
648
|
+
parser.consume('<');
|
|
649
|
+
const objects = [];
|
|
650
|
+
do {
|
|
651
|
+
objects.push(parser.parseType(Precedence.PARAMETER_LIST));
|
|
652
|
+
} while (parser.consume(','));
|
|
653
|
+
if (!parser.consume('>')) {
|
|
654
|
+
throw new Error('Unterminated generic parameter list');
|
|
655
|
+
}
|
|
656
|
+
return {
|
|
657
|
+
type: 'JsdocTypeGeneric',
|
|
658
|
+
left: assertRootResult(left),
|
|
659
|
+
elements: objects,
|
|
660
|
+
meta: {
|
|
661
|
+
brackets: 'angle',
|
|
662
|
+
dot
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
const unionParslet = composeParslet({
|
|
669
|
+
name: 'unionParslet',
|
|
670
|
+
accept: type => type === '|',
|
|
671
|
+
precedence: Precedence.UNION,
|
|
672
|
+
parseInfix: (parser, left) => {
|
|
673
|
+
parser.consume('|');
|
|
674
|
+
const elements = [];
|
|
675
|
+
do {
|
|
676
|
+
elements.push(parser.parseType(Precedence.UNION));
|
|
677
|
+
} while (parser.consume('|'));
|
|
678
|
+
return {
|
|
679
|
+
type: 'JsdocTypeUnion',
|
|
680
|
+
elements: [assertRootResult(left), ...elements]
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
const baseGrammar = [
|
|
686
|
+
nullableParslet,
|
|
687
|
+
optionalParslet,
|
|
688
|
+
numberParslet,
|
|
689
|
+
parenthesisParslet,
|
|
690
|
+
specialTypesParslet,
|
|
691
|
+
notNullableParslet,
|
|
692
|
+
createParameterListParslet({
|
|
693
|
+
allowTrailingComma: true
|
|
694
|
+
}),
|
|
695
|
+
genericParslet,
|
|
696
|
+
unionParslet,
|
|
697
|
+
optionalParslet
|
|
698
|
+
];
|
|
699
|
+
|
|
700
|
+
function createNamePathParslet({ allowSquareBracketsOnAnyType, allowJsdocNamePaths, pathGrammar }) {
|
|
701
|
+
return function namePathParslet(parser, precedence, left) {
|
|
702
|
+
if ((left == null) || precedence >= Precedence.NAME_PATH) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
const type = parser.lexer.current.type;
|
|
706
|
+
const next = parser.lexer.next.type;
|
|
707
|
+
const accept = (type === '.' && next !== '<') ||
|
|
708
|
+
(type === '[' && (allowSquareBracketsOnAnyType || left.type === 'JsdocTypeName')) ||
|
|
709
|
+
(allowJsdocNamePaths && (type === '~' || type === '#'));
|
|
710
|
+
if (!accept) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
let pathType;
|
|
714
|
+
let brackets = false;
|
|
715
|
+
if (parser.consume('.')) {
|
|
716
|
+
pathType = 'property';
|
|
717
|
+
}
|
|
718
|
+
else if (parser.consume('[')) {
|
|
719
|
+
pathType = 'property-brackets';
|
|
720
|
+
brackets = true;
|
|
721
|
+
}
|
|
722
|
+
else if (parser.consume('~')) {
|
|
723
|
+
pathType = 'inner';
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
parser.consume('#');
|
|
727
|
+
pathType = 'instance';
|
|
728
|
+
}
|
|
729
|
+
const pathParser = pathGrammar !== null
|
|
730
|
+
? new Parser(pathGrammar, parser.lexer, parser)
|
|
731
|
+
: parser;
|
|
732
|
+
const parsed = pathParser.parseIntermediateType(Precedence.NAME_PATH);
|
|
733
|
+
parser.acceptLexerState(pathParser);
|
|
734
|
+
let right;
|
|
735
|
+
switch (parsed.type) {
|
|
736
|
+
case 'JsdocTypeName':
|
|
737
|
+
right = {
|
|
738
|
+
type: 'JsdocTypeProperty',
|
|
739
|
+
value: parsed.value,
|
|
740
|
+
meta: {
|
|
741
|
+
quote: undefined
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
break;
|
|
745
|
+
case 'JsdocTypeNumber':
|
|
746
|
+
right = {
|
|
747
|
+
type: 'JsdocTypeProperty',
|
|
748
|
+
value: parsed.value.toString(10),
|
|
749
|
+
meta: {
|
|
750
|
+
quote: undefined
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
break;
|
|
754
|
+
case 'JsdocTypeStringValue':
|
|
755
|
+
right = {
|
|
756
|
+
type: 'JsdocTypeProperty',
|
|
757
|
+
value: parsed.value,
|
|
758
|
+
meta: {
|
|
759
|
+
quote: parsed.meta.quote
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
break;
|
|
763
|
+
case 'JsdocTypeSpecialNamePath':
|
|
764
|
+
if (parsed.specialType === 'event') {
|
|
765
|
+
right = parsed;
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
throw new UnexpectedTypeError(parsed, 'Type \'JsdocTypeSpecialNamePath\' is only allowed with specialType \'event\'');
|
|
769
|
+
}
|
|
770
|
+
break;
|
|
771
|
+
default:
|
|
772
|
+
throw new UnexpectedTypeError(parsed, 'Expecting \'JsdocTypeName\', \'JsdocTypeNumber\', \'JsdocStringValue\' or \'JsdocTypeSpecialNamePath\'');
|
|
773
|
+
}
|
|
774
|
+
if (brackets && !parser.consume(']')) {
|
|
775
|
+
const token = parser.lexer.current;
|
|
776
|
+
throw new Error(`Unterminated square brackets. Next token is '${token.type}' ` +
|
|
777
|
+
`with text '${token.text}'`);
|
|
778
|
+
}
|
|
779
|
+
return {
|
|
780
|
+
type: 'JsdocTypeNamePath',
|
|
781
|
+
left: assertRootResult(left),
|
|
782
|
+
right,
|
|
783
|
+
pathType
|
|
784
|
+
};
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function createNameParslet({ allowedAdditionalTokens }) {
|
|
789
|
+
return composeParslet({
|
|
790
|
+
name: 'nameParslet',
|
|
791
|
+
accept: type => type === 'Identifier' || type === 'this' || type === 'new' || allowedAdditionalTokens.includes(type),
|
|
792
|
+
parsePrefix: parser => {
|
|
793
|
+
const { type, text } = parser.lexer.current;
|
|
794
|
+
parser.consume(type);
|
|
795
|
+
return {
|
|
796
|
+
type: 'JsdocTypeName',
|
|
797
|
+
value: text
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
const stringValueParslet = composeParslet({
|
|
804
|
+
name: 'stringValueParslet',
|
|
805
|
+
accept: type => type === 'StringValue',
|
|
806
|
+
parsePrefix: parser => {
|
|
807
|
+
const text = parser.lexer.current.text;
|
|
808
|
+
parser.consume('StringValue');
|
|
809
|
+
return {
|
|
810
|
+
type: 'JsdocTypeStringValue',
|
|
811
|
+
value: text.slice(1, -1),
|
|
812
|
+
meta: {
|
|
813
|
+
quote: text[0] === '\'' ? 'single' : 'double'
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
function createSpecialNamePathParslet({ pathGrammar, allowedTypes }) {
|
|
820
|
+
return composeParslet({
|
|
821
|
+
name: 'specialNamePathParslet',
|
|
822
|
+
accept: type => allowedTypes.includes(type),
|
|
823
|
+
parsePrefix: parser => {
|
|
824
|
+
const type = parser.lexer.current.type;
|
|
825
|
+
parser.consume(type);
|
|
826
|
+
if (!parser.consume(':')) {
|
|
827
|
+
return {
|
|
828
|
+
type: 'JsdocTypeName',
|
|
829
|
+
value: type
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
let result;
|
|
833
|
+
let token = parser.lexer.current;
|
|
834
|
+
if (parser.consume('StringValue')) {
|
|
835
|
+
result = {
|
|
836
|
+
type: 'JsdocTypeSpecialNamePath',
|
|
837
|
+
value: token.text.slice(1, -1),
|
|
838
|
+
specialType: type,
|
|
839
|
+
meta: {
|
|
840
|
+
quote: token.text[0] === '\'' ? 'single' : 'double'
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
let value = '';
|
|
846
|
+
const allowed = ['Identifier', '@', '/'];
|
|
847
|
+
while (allowed.some(type => parser.consume(type))) {
|
|
848
|
+
value += token.text;
|
|
849
|
+
token = parser.lexer.current;
|
|
850
|
+
}
|
|
851
|
+
result = {
|
|
852
|
+
type: 'JsdocTypeSpecialNamePath',
|
|
853
|
+
value,
|
|
854
|
+
specialType: type,
|
|
855
|
+
meta: {
|
|
856
|
+
quote: undefined
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
const moduleParser = new Parser(pathGrammar, parser.lexer, parser);
|
|
861
|
+
const moduleResult = moduleParser.parseInfixIntermediateType(result, Precedence.ALL);
|
|
862
|
+
parser.acceptLexerState(moduleParser);
|
|
863
|
+
return assertRootResult(moduleResult);
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const basePathGrammar = [
|
|
869
|
+
createNameParslet({
|
|
870
|
+
allowedAdditionalTokens: ['external', 'module']
|
|
871
|
+
}),
|
|
872
|
+
stringValueParslet,
|
|
873
|
+
numberParslet,
|
|
874
|
+
createNamePathParslet({
|
|
875
|
+
allowSquareBracketsOnAnyType: false,
|
|
876
|
+
allowJsdocNamePaths: true,
|
|
877
|
+
pathGrammar: null
|
|
878
|
+
})
|
|
879
|
+
];
|
|
880
|
+
const pathGrammar = [
|
|
881
|
+
...basePathGrammar,
|
|
882
|
+
createSpecialNamePathParslet({
|
|
883
|
+
allowedTypes: ['event'],
|
|
884
|
+
pathGrammar: basePathGrammar
|
|
885
|
+
})
|
|
886
|
+
];
|
|
887
|
+
|
|
888
|
+
function getParameters(value) {
|
|
889
|
+
let parameters;
|
|
890
|
+
if (value.type === 'JsdocTypeParameterList') {
|
|
891
|
+
parameters = value.elements;
|
|
892
|
+
}
|
|
893
|
+
else if (value.type === 'JsdocTypeParenthesis') {
|
|
894
|
+
parameters = [value.element];
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
throw new UnexpectedTypeError(value);
|
|
898
|
+
}
|
|
899
|
+
return parameters.map(p => assertPlainKeyValueOrRootResult(p));
|
|
900
|
+
}
|
|
901
|
+
function getUnnamedParameters(value) {
|
|
902
|
+
const parameters = getParameters(value);
|
|
903
|
+
if (parameters.some(p => p.type === 'JsdocTypeKeyValue')) {
|
|
904
|
+
throw new Error('No parameter should be named');
|
|
905
|
+
}
|
|
906
|
+
return parameters;
|
|
907
|
+
}
|
|
908
|
+
function createFunctionParslet({ allowNamedParameters, allowNoReturnType, allowWithoutParenthesis, allowNewAsFunctionKeyword }) {
|
|
909
|
+
return composeParslet({
|
|
910
|
+
name: 'functionParslet',
|
|
911
|
+
accept: (type, next) => type === 'function' || (allowNewAsFunctionKeyword && type === 'new' && next === '('),
|
|
912
|
+
parsePrefix: parser => {
|
|
913
|
+
const newKeyword = parser.consume('new');
|
|
914
|
+
parser.consume('function');
|
|
915
|
+
const hasParenthesis = parser.lexer.current.type === '(';
|
|
916
|
+
if (!hasParenthesis) {
|
|
917
|
+
if (!allowWithoutParenthesis) {
|
|
918
|
+
throw new Error('function is missing parameter list');
|
|
919
|
+
}
|
|
920
|
+
return {
|
|
921
|
+
type: 'JsdocTypeName',
|
|
922
|
+
value: 'function'
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
let result = {
|
|
926
|
+
type: 'JsdocTypeFunction',
|
|
927
|
+
parameters: [],
|
|
928
|
+
arrow: false,
|
|
929
|
+
constructor: newKeyword,
|
|
930
|
+
parenthesis: hasParenthesis
|
|
931
|
+
};
|
|
932
|
+
const value = parser.parseIntermediateType(Precedence.FUNCTION);
|
|
933
|
+
if (allowNamedParameters === undefined) {
|
|
934
|
+
result.parameters = getUnnamedParameters(value);
|
|
935
|
+
}
|
|
936
|
+
else if (newKeyword && value.type === 'JsdocTypeFunction' && value.arrow) {
|
|
937
|
+
result = value;
|
|
938
|
+
result.constructor = true;
|
|
939
|
+
return result;
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
result.parameters = getParameters(value);
|
|
943
|
+
for (const p of result.parameters) {
|
|
944
|
+
if (p.type === 'JsdocTypeKeyValue' && (!allowNamedParameters.includes(p.key))) {
|
|
945
|
+
throw new Error(`only allowed named parameters are ${allowNamedParameters.join(', ')} but got ${p.type}`);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (parser.consume(':')) {
|
|
950
|
+
result.returnType = parser.parseType(Precedence.PREFIX);
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
if (!allowNoReturnType) {
|
|
954
|
+
throw new Error('function is missing return type');
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return result;
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function createVariadicParslet({ allowPostfix, allowEnclosingBrackets }) {
|
|
963
|
+
return composeParslet({
|
|
964
|
+
name: 'variadicParslet',
|
|
965
|
+
accept: type => type === '...',
|
|
966
|
+
precedence: Precedence.PREFIX,
|
|
967
|
+
parsePrefix: parser => {
|
|
968
|
+
parser.consume('...');
|
|
969
|
+
const brackets = allowEnclosingBrackets && parser.consume('[');
|
|
970
|
+
try {
|
|
971
|
+
const element = parser.parseType(Precedence.PREFIX);
|
|
972
|
+
if (brackets && !parser.consume(']')) {
|
|
973
|
+
throw new Error('Unterminated variadic type. Missing \']\'');
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
type: 'JsdocTypeVariadic',
|
|
977
|
+
element: assertRootResult(element),
|
|
978
|
+
meta: {
|
|
979
|
+
position: 'prefix',
|
|
980
|
+
squareBrackets: brackets
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
catch (e) {
|
|
985
|
+
if (e instanceof NoParsletFoundError) {
|
|
986
|
+
if (brackets) {
|
|
987
|
+
throw new Error('Empty square brackets for variadic are not allowed.');
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
type: 'JsdocTypeVariadic',
|
|
991
|
+
meta: {
|
|
992
|
+
position: undefined,
|
|
993
|
+
squareBrackets: false
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
throw e;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
parseInfix: allowPostfix
|
|
1003
|
+
? (parser, left) => {
|
|
1004
|
+
parser.consume('...');
|
|
1005
|
+
return {
|
|
1006
|
+
type: 'JsdocTypeVariadic',
|
|
1007
|
+
element: assertRootResult(left),
|
|
1008
|
+
meta: {
|
|
1009
|
+
position: 'suffix',
|
|
1010
|
+
squareBrackets: false
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
: undefined
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const symbolParslet = composeParslet({
|
|
1019
|
+
name: 'symbolParslet',
|
|
1020
|
+
accept: type => type === '(',
|
|
1021
|
+
precedence: Precedence.SYMBOL,
|
|
1022
|
+
parseInfix: (parser, left) => {
|
|
1023
|
+
if (left.type !== 'JsdocTypeName') {
|
|
1024
|
+
throw new Error('Symbol expects a name on the left side. (Reacting on \'(\')');
|
|
1025
|
+
}
|
|
1026
|
+
parser.consume('(');
|
|
1027
|
+
const result = {
|
|
1028
|
+
type: 'JsdocTypeSymbol',
|
|
1029
|
+
value: left.value
|
|
1030
|
+
};
|
|
1031
|
+
if (!parser.consume(')')) {
|
|
1032
|
+
const next = parser.parseIntermediateType(Precedence.SYMBOL);
|
|
1033
|
+
result.element = assertNumberOrVariadicNameResult(next);
|
|
1034
|
+
if (!parser.consume(')')) {
|
|
1035
|
+
throw new Error('Symbol does not end after value');
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return result;
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
const arrayBracketsParslet = composeParslet({
|
|
1043
|
+
name: 'arrayBracketsParslet',
|
|
1044
|
+
precedence: Precedence.ARRAY_BRACKETS,
|
|
1045
|
+
accept: (type, next) => type === '[' && next === ']',
|
|
1046
|
+
parseInfix: (parser, left) => {
|
|
1047
|
+
parser.consume('[');
|
|
1048
|
+
parser.consume(']');
|
|
1049
|
+
return {
|
|
1050
|
+
type: 'JsdocTypeGeneric',
|
|
1051
|
+
left: {
|
|
1052
|
+
type: 'JsdocTypeName',
|
|
1053
|
+
value: 'Array'
|
|
1054
|
+
},
|
|
1055
|
+
elements: [
|
|
1056
|
+
assertRootResult(left)
|
|
1057
|
+
],
|
|
1058
|
+
meta: {
|
|
1059
|
+
brackets: 'square',
|
|
1060
|
+
dot: false
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
function createObjectParslet({ objectFieldGrammar, allowKeyTypes }) {
|
|
1067
|
+
return composeParslet({
|
|
1068
|
+
name: 'objectParslet',
|
|
1069
|
+
accept: type => type === '{',
|
|
1070
|
+
parsePrefix: parser => {
|
|
1071
|
+
parser.consume('{');
|
|
1072
|
+
const result = {
|
|
1073
|
+
type: 'JsdocTypeObject',
|
|
1074
|
+
meta: {
|
|
1075
|
+
separator: 'comma'
|
|
1076
|
+
},
|
|
1077
|
+
elements: []
|
|
1078
|
+
};
|
|
1079
|
+
if (!parser.consume('}')) {
|
|
1080
|
+
let separator;
|
|
1081
|
+
const fieldParser = new Parser(objectFieldGrammar, parser.lexer, parser);
|
|
1082
|
+
while (true) {
|
|
1083
|
+
fieldParser.acceptLexerState(parser);
|
|
1084
|
+
let field = fieldParser.parseIntermediateType(Precedence.OBJECT);
|
|
1085
|
+
parser.acceptLexerState(fieldParser);
|
|
1086
|
+
if (field === undefined && allowKeyTypes) {
|
|
1087
|
+
field = parser.parseIntermediateType(Precedence.OBJECT);
|
|
1088
|
+
}
|
|
1089
|
+
let optional = false;
|
|
1090
|
+
if (field.type === 'JsdocTypeNullable') {
|
|
1091
|
+
optional = true;
|
|
1092
|
+
field = field.element;
|
|
1093
|
+
}
|
|
1094
|
+
if (field.type === 'JsdocTypeNumber' || field.type === 'JsdocTypeName' || field.type === 'JsdocTypeStringValue') {
|
|
1095
|
+
let quote;
|
|
1096
|
+
if (field.type === 'JsdocTypeStringValue') {
|
|
1097
|
+
quote = field.meta.quote;
|
|
1098
|
+
}
|
|
1099
|
+
result.elements.push({
|
|
1100
|
+
type: 'JsdocTypeObjectField',
|
|
1101
|
+
key: field.value.toString(),
|
|
1102
|
+
right: undefined,
|
|
1103
|
+
optional,
|
|
1104
|
+
readonly: false,
|
|
1105
|
+
meta: {
|
|
1106
|
+
quote
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
else if (field.type === 'JsdocTypeObjectField' || field.type === 'JsdocTypeJsdocObjectField') {
|
|
1111
|
+
result.elements.push(field);
|
|
1112
|
+
}
|
|
1113
|
+
else {
|
|
1114
|
+
throw new UnexpectedTypeError(field);
|
|
1115
|
+
}
|
|
1116
|
+
if (parser.lexer.current.startOfLine) {
|
|
1117
|
+
separator = 'linebreak';
|
|
1118
|
+
}
|
|
1119
|
+
else if (parser.consume(',')) {
|
|
1120
|
+
separator = 'comma';
|
|
1121
|
+
}
|
|
1122
|
+
else if (parser.consume(';')) {
|
|
1123
|
+
separator = 'semicolon';
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
break;
|
|
1127
|
+
}
|
|
1128
|
+
const type = parser.lexer.current.type;
|
|
1129
|
+
if (type === '}') {
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
result.meta.separator = separator !== null && separator !== void 0 ? separator : 'comma'; // TODO: use undefined here
|
|
1134
|
+
if (!parser.consume('}')) {
|
|
1135
|
+
throw new Error('Unterminated record type. Missing \'}\'');
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return result;
|
|
1139
|
+
}
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function createObjectFieldParslet({ allowSquaredProperties, allowKeyTypes, allowReadonly, allowOptional }) {
|
|
1144
|
+
return composeParslet({
|
|
1145
|
+
name: 'objectFieldParslet',
|
|
1146
|
+
precedence: Precedence.KEY_VALUE,
|
|
1147
|
+
accept: type => type === ':',
|
|
1148
|
+
parseInfix: (parser, left) => {
|
|
1149
|
+
var _a;
|
|
1150
|
+
let optional = false;
|
|
1151
|
+
let readonlyProperty = false;
|
|
1152
|
+
if (allowOptional && left.type === 'JsdocTypeNullable') {
|
|
1153
|
+
optional = true;
|
|
1154
|
+
left = left.element;
|
|
1155
|
+
}
|
|
1156
|
+
if (allowReadonly && left.type === 'JsdocTypeReadonlyProperty') {
|
|
1157
|
+
readonlyProperty = true;
|
|
1158
|
+
left = left.element;
|
|
1159
|
+
}
|
|
1160
|
+
// object parslet uses a special grammar and for the value we want to switch back to the parent
|
|
1161
|
+
const parentParser = (_a = parser.baseParser) !== null && _a !== void 0 ? _a : parser;
|
|
1162
|
+
parentParser.acceptLexerState(parser);
|
|
1163
|
+
if (left.type === 'JsdocTypeNumber' || left.type === 'JsdocTypeName' || left.type === 'JsdocTypeStringValue' ||
|
|
1164
|
+
isSquaredProperty(left)) {
|
|
1165
|
+
if (isSquaredProperty(left) && !allowSquaredProperties) {
|
|
1166
|
+
throw new UnexpectedTypeError(left);
|
|
1167
|
+
}
|
|
1168
|
+
parentParser.consume(':');
|
|
1169
|
+
let quote;
|
|
1170
|
+
if (left.type === 'JsdocTypeStringValue') {
|
|
1171
|
+
quote = left.meta.quote;
|
|
1172
|
+
}
|
|
1173
|
+
const right = parentParser.parseType(Precedence.KEY_VALUE);
|
|
1174
|
+
parser.acceptLexerState(parentParser);
|
|
1175
|
+
return {
|
|
1176
|
+
type: 'JsdocTypeObjectField',
|
|
1177
|
+
key: isSquaredProperty(left) ? left : left.value.toString(),
|
|
1178
|
+
right,
|
|
1179
|
+
optional,
|
|
1180
|
+
readonly: readonlyProperty,
|
|
1181
|
+
meta: {
|
|
1182
|
+
quote
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
else {
|
|
1187
|
+
if (!allowKeyTypes) {
|
|
1188
|
+
throw new UnexpectedTypeError(left);
|
|
1189
|
+
}
|
|
1190
|
+
parentParser.consume(':');
|
|
1191
|
+
const right = parentParser.parseType(Precedence.KEY_VALUE);
|
|
1192
|
+
parser.acceptLexerState(parentParser);
|
|
1193
|
+
return {
|
|
1194
|
+
type: 'JsdocTypeJsdocObjectField',
|
|
1195
|
+
left: assertRootResult(left),
|
|
1196
|
+
right
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function createKeyValueParslet({ allowOptional, allowVariadic }) {
|
|
1204
|
+
return composeParslet({
|
|
1205
|
+
name: 'keyValueParslet',
|
|
1206
|
+
precedence: Precedence.KEY_VALUE,
|
|
1207
|
+
accept: type => type === ':',
|
|
1208
|
+
parseInfix: (parser, left) => {
|
|
1209
|
+
let optional = false;
|
|
1210
|
+
let variadic = false;
|
|
1211
|
+
if (allowOptional && left.type === 'JsdocTypeNullable') {
|
|
1212
|
+
optional = true;
|
|
1213
|
+
left = left.element;
|
|
1214
|
+
}
|
|
1215
|
+
if (allowVariadic && left.type === 'JsdocTypeVariadic' && left.element !== undefined) {
|
|
1216
|
+
variadic = true;
|
|
1217
|
+
left = left.element;
|
|
1218
|
+
}
|
|
1219
|
+
if (left.type !== 'JsdocTypeName') {
|
|
1220
|
+
throw new UnexpectedTypeError(left);
|
|
1221
|
+
}
|
|
1222
|
+
parser.consume(':');
|
|
1223
|
+
const right = parser.parseType(Precedence.KEY_VALUE);
|
|
1224
|
+
return {
|
|
1225
|
+
type: 'JsdocTypeKeyValue',
|
|
1226
|
+
key: left.value,
|
|
1227
|
+
right,
|
|
1228
|
+
optional,
|
|
1229
|
+
variadic
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
const jsdocBaseGrammar = [
|
|
1236
|
+
...baseGrammar,
|
|
1237
|
+
createFunctionParslet({
|
|
1238
|
+
allowWithoutParenthesis: true,
|
|
1239
|
+
allowNamedParameters: ['this', 'new'],
|
|
1240
|
+
allowNoReturnType: true,
|
|
1241
|
+
allowNewAsFunctionKeyword: false
|
|
1242
|
+
}),
|
|
1243
|
+
stringValueParslet,
|
|
1244
|
+
createSpecialNamePathParslet({
|
|
1245
|
+
allowedTypes: ['module', 'external', 'event'],
|
|
1246
|
+
pathGrammar
|
|
1247
|
+
}),
|
|
1248
|
+
createVariadicParslet({
|
|
1249
|
+
allowEnclosingBrackets: true,
|
|
1250
|
+
allowPostfix: true
|
|
1251
|
+
}),
|
|
1252
|
+
createNameParslet({
|
|
1253
|
+
allowedAdditionalTokens: ['keyof']
|
|
1254
|
+
}),
|
|
1255
|
+
symbolParslet,
|
|
1256
|
+
arrayBracketsParslet,
|
|
1257
|
+
createNamePathParslet({
|
|
1258
|
+
allowSquareBracketsOnAnyType: false,
|
|
1259
|
+
allowJsdocNamePaths: true,
|
|
1260
|
+
pathGrammar
|
|
1261
|
+
})
|
|
1262
|
+
];
|
|
1263
|
+
const jsdocGrammar = [
|
|
1264
|
+
...jsdocBaseGrammar,
|
|
1265
|
+
createObjectParslet({
|
|
1266
|
+
// jsdoc syntax allows full types as keys, so we need to pull in the full grammar here
|
|
1267
|
+
// we leave out the object type deliberately
|
|
1268
|
+
objectFieldGrammar: [
|
|
1269
|
+
createNameParslet({
|
|
1270
|
+
allowedAdditionalTokens: ['module', 'in']
|
|
1271
|
+
}),
|
|
1272
|
+
createObjectFieldParslet({
|
|
1273
|
+
allowSquaredProperties: false,
|
|
1274
|
+
allowKeyTypes: true,
|
|
1275
|
+
allowOptional: false,
|
|
1276
|
+
allowReadonly: false
|
|
1277
|
+
}),
|
|
1278
|
+
...jsdocBaseGrammar
|
|
1279
|
+
],
|
|
1280
|
+
allowKeyTypes: true
|
|
1281
|
+
}),
|
|
1282
|
+
createKeyValueParslet({
|
|
1283
|
+
allowOptional: true,
|
|
1284
|
+
allowVariadic: true
|
|
1285
|
+
})
|
|
1286
|
+
];
|
|
1287
|
+
|
|
1288
|
+
const typeOfParslet = composeParslet({
|
|
1289
|
+
name: 'typeOfParslet',
|
|
1290
|
+
accept: type => type === 'typeof',
|
|
1291
|
+
parsePrefix: parser => {
|
|
1292
|
+
parser.consume('typeof');
|
|
1293
|
+
return {
|
|
1294
|
+
type: 'JsdocTypeTypeof',
|
|
1295
|
+
element: assertRootResult(parser.parseType(Precedence.KEY_OF_TYPE_OF))
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
const objectFieldGrammar$1 = [
|
|
1301
|
+
createNameParslet({
|
|
1302
|
+
allowedAdditionalTokens: ['module', 'keyof', 'event', 'external', 'in']
|
|
1303
|
+
}),
|
|
1304
|
+
nullableParslet,
|
|
1305
|
+
optionalParslet,
|
|
1306
|
+
stringValueParslet,
|
|
1307
|
+
numberParslet,
|
|
1308
|
+
createObjectFieldParslet({
|
|
1309
|
+
allowSquaredProperties: false,
|
|
1310
|
+
allowKeyTypes: false,
|
|
1311
|
+
allowOptional: false,
|
|
1312
|
+
allowReadonly: false
|
|
1313
|
+
})
|
|
1314
|
+
];
|
|
1315
|
+
const closureGrammar = [
|
|
1316
|
+
...baseGrammar,
|
|
1317
|
+
createObjectParslet({
|
|
1318
|
+
allowKeyTypes: false,
|
|
1319
|
+
objectFieldGrammar: objectFieldGrammar$1
|
|
1320
|
+
}),
|
|
1321
|
+
createNameParslet({
|
|
1322
|
+
allowedAdditionalTokens: ['event', 'external', 'in']
|
|
1323
|
+
}),
|
|
1324
|
+
typeOfParslet,
|
|
1325
|
+
createFunctionParslet({
|
|
1326
|
+
allowWithoutParenthesis: false,
|
|
1327
|
+
allowNamedParameters: ['this', 'new'],
|
|
1328
|
+
allowNoReturnType: true,
|
|
1329
|
+
allowNewAsFunctionKeyword: false
|
|
1330
|
+
}),
|
|
1331
|
+
createVariadicParslet({
|
|
1332
|
+
allowEnclosingBrackets: false,
|
|
1333
|
+
allowPostfix: false
|
|
1334
|
+
}),
|
|
1335
|
+
// additional name parslet is needed for some special cases
|
|
1336
|
+
createNameParslet({
|
|
1337
|
+
allowedAdditionalTokens: ['keyof']
|
|
1338
|
+
}),
|
|
1339
|
+
createSpecialNamePathParslet({
|
|
1340
|
+
allowedTypes: ['module'],
|
|
1341
|
+
pathGrammar
|
|
1342
|
+
}),
|
|
1343
|
+
createNamePathParslet({
|
|
1344
|
+
allowSquareBracketsOnAnyType: false,
|
|
1345
|
+
allowJsdocNamePaths: true,
|
|
1346
|
+
pathGrammar
|
|
1347
|
+
}),
|
|
1348
|
+
createKeyValueParslet({
|
|
1349
|
+
allowOptional: false,
|
|
1350
|
+
allowVariadic: false
|
|
1351
|
+
}),
|
|
1352
|
+
symbolParslet
|
|
1353
|
+
];
|
|
1354
|
+
|
|
1355
|
+
const assertsParslet = composeParslet({
|
|
1356
|
+
name: 'assertsParslet',
|
|
1357
|
+
accept: type => type === 'asserts',
|
|
1358
|
+
parsePrefix: (parser) => {
|
|
1359
|
+
parser.consume('asserts');
|
|
1360
|
+
const left = parser.parseIntermediateType(Precedence.SYMBOL);
|
|
1361
|
+
if (left.type !== 'JsdocTypeName') {
|
|
1362
|
+
throw new UnexpectedTypeError(left, 'A typescript asserts always has to have a name on the left side.');
|
|
1363
|
+
}
|
|
1364
|
+
parser.consume('is');
|
|
1365
|
+
return {
|
|
1366
|
+
type: 'JsdocTypeAsserts',
|
|
1367
|
+
left,
|
|
1368
|
+
right: assertRootResult(parser.parseIntermediateType(Precedence.INFIX))
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
function createTupleParslet({ allowQuestionMark }) {
|
|
1374
|
+
return composeParslet({
|
|
1375
|
+
name: 'tupleParslet',
|
|
1376
|
+
accept: type => type === '[',
|
|
1377
|
+
parsePrefix: parser => {
|
|
1378
|
+
parser.consume('[');
|
|
1379
|
+
const result = {
|
|
1380
|
+
type: 'JsdocTypeTuple',
|
|
1381
|
+
elements: []
|
|
1382
|
+
};
|
|
1383
|
+
if (parser.consume(']')) {
|
|
1384
|
+
return result;
|
|
1385
|
+
}
|
|
1386
|
+
const typeList = parser.parseIntermediateType(Precedence.ALL);
|
|
1387
|
+
if (typeList.type === 'JsdocTypeParameterList') {
|
|
1388
|
+
if (typeList.elements[0].type === 'JsdocTypeKeyValue') {
|
|
1389
|
+
result.elements = typeList.elements.map(assertPlainKeyValueResult);
|
|
1390
|
+
}
|
|
1391
|
+
else {
|
|
1392
|
+
result.elements = typeList.elements.map(assertRootResult);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
else {
|
|
1396
|
+
if (typeList.type === 'JsdocTypeKeyValue') {
|
|
1397
|
+
result.elements = [assertPlainKeyValueResult(typeList)];
|
|
1398
|
+
}
|
|
1399
|
+
else {
|
|
1400
|
+
result.elements = [assertRootResult(typeList)];
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (!parser.consume(']')) {
|
|
1404
|
+
throw new Error('Unterminated \'[\'');
|
|
1405
|
+
}
|
|
1406
|
+
if (result.elements.some((e) => e.type === 'JsdocTypeUnknown')) {
|
|
1407
|
+
throw new Error('Question mark in tuple not allowed');
|
|
1408
|
+
}
|
|
1409
|
+
return result;
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
const keyOfParslet = composeParslet({
|
|
1415
|
+
name: 'keyOfParslet',
|
|
1416
|
+
accept: type => type === 'keyof',
|
|
1417
|
+
parsePrefix: parser => {
|
|
1418
|
+
parser.consume('keyof');
|
|
1419
|
+
return {
|
|
1420
|
+
type: 'JsdocTypeKeyof',
|
|
1421
|
+
element: assertRootResult(parser.parseType(Precedence.KEY_OF_TYPE_OF))
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
const importParslet = composeParslet({
|
|
1427
|
+
name: 'importParslet',
|
|
1428
|
+
accept: type => type === 'import',
|
|
1429
|
+
parsePrefix: parser => {
|
|
1430
|
+
parser.consume('import');
|
|
1431
|
+
if (!parser.consume('(')) {
|
|
1432
|
+
throw new Error('Missing parenthesis after import keyword');
|
|
1433
|
+
}
|
|
1434
|
+
const path = parser.parseType(Precedence.PREFIX);
|
|
1435
|
+
if (path.type !== 'JsdocTypeStringValue') {
|
|
1436
|
+
throw new Error('Only string values are allowed as paths for imports');
|
|
1437
|
+
}
|
|
1438
|
+
if (!parser.consume(')')) {
|
|
1439
|
+
throw new Error('Missing closing parenthesis after import keyword');
|
|
1440
|
+
}
|
|
1441
|
+
return {
|
|
1442
|
+
type: 'JsdocTypeImport',
|
|
1443
|
+
element: path
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1448
|
+
const readonlyPropertyParslet = composeParslet({
|
|
1449
|
+
name: 'readonlyPropertyParslet',
|
|
1450
|
+
accept: type => type === 'readonly',
|
|
1451
|
+
parsePrefix: parser => {
|
|
1452
|
+
parser.consume('readonly');
|
|
1453
|
+
return {
|
|
1454
|
+
type: 'JsdocTypeReadonlyProperty',
|
|
1455
|
+
element: parser.parseType(Precedence.KEY_VALUE)
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
const arrowFunctionParslet = composeParslet({
|
|
1461
|
+
name: 'arrowFunctionParslet',
|
|
1462
|
+
precedence: Precedence.ARROW,
|
|
1463
|
+
accept: type => type === '=>',
|
|
1464
|
+
parseInfix: (parser, left) => {
|
|
1465
|
+
parser.consume('=>');
|
|
1466
|
+
return {
|
|
1467
|
+
type: 'JsdocTypeFunction',
|
|
1468
|
+
parameters: getParameters(left).map(assertPlainKeyValueOrNameResult),
|
|
1469
|
+
arrow: true,
|
|
1470
|
+
constructor: false,
|
|
1471
|
+
parenthesis: true,
|
|
1472
|
+
returnType: parser.parseType(Precedence.OBJECT)
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
|
|
1477
|
+
const intersectionParslet = composeParslet({
|
|
1478
|
+
name: 'intersectionParslet',
|
|
1479
|
+
accept: type => type === '&',
|
|
1480
|
+
precedence: Precedence.INTERSECTION,
|
|
1481
|
+
parseInfix: (parser, left) => {
|
|
1482
|
+
parser.consume('&');
|
|
1483
|
+
const elements = [];
|
|
1484
|
+
do {
|
|
1485
|
+
elements.push(parser.parseType(Precedence.INTERSECTION));
|
|
1486
|
+
} while (parser.consume('&'));
|
|
1487
|
+
return {
|
|
1488
|
+
type: 'JsdocTypeIntersection',
|
|
1489
|
+
elements: [assertRootResult(left), ...elements]
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
const predicateParslet = composeParslet({
|
|
1495
|
+
name: 'predicateParslet',
|
|
1496
|
+
precedence: Precedence.INFIX,
|
|
1497
|
+
accept: type => type === 'is',
|
|
1498
|
+
parseInfix: (parser, left) => {
|
|
1499
|
+
if (left.type !== 'JsdocTypeName') {
|
|
1500
|
+
throw new UnexpectedTypeError(left, 'A typescript predicate always has to have a name on the left side.');
|
|
1501
|
+
}
|
|
1502
|
+
parser.consume('is');
|
|
1503
|
+
return {
|
|
1504
|
+
type: 'JsdocTypePredicate',
|
|
1505
|
+
left,
|
|
1506
|
+
right: assertRootResult(parser.parseIntermediateType(Precedence.INFIX))
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
const objectSquaredPropertyParslet = composeParslet({
|
|
1512
|
+
name: 'objectSquareBracketPropertyParslet',
|
|
1513
|
+
accept: type => type === '[',
|
|
1514
|
+
parsePrefix: parser => {
|
|
1515
|
+
if (parser.baseParser === undefined) {
|
|
1516
|
+
throw new Error('Only allowed inside object grammar');
|
|
1517
|
+
}
|
|
1518
|
+
parser.consume('[');
|
|
1519
|
+
const key = parser.lexer.current.text;
|
|
1520
|
+
parser.consume('Identifier');
|
|
1521
|
+
let result;
|
|
1522
|
+
if (parser.consume(':')) {
|
|
1523
|
+
const parentParser = parser.baseParser;
|
|
1524
|
+
parentParser.acceptLexerState(parser);
|
|
1525
|
+
result = {
|
|
1526
|
+
type: 'JsdocTypeIndexSignature',
|
|
1527
|
+
key,
|
|
1528
|
+
right: parentParser.parseType(Precedence.INDEX_BRACKETS)
|
|
1529
|
+
};
|
|
1530
|
+
parser.acceptLexerState(parentParser);
|
|
1531
|
+
}
|
|
1532
|
+
else if (parser.consume('in')) {
|
|
1533
|
+
const parentParser = parser.baseParser;
|
|
1534
|
+
parentParser.acceptLexerState(parser);
|
|
1535
|
+
result = {
|
|
1536
|
+
type: 'JsdocTypeMappedType',
|
|
1537
|
+
key,
|
|
1538
|
+
right: parentParser.parseType(Precedence.ARRAY_BRACKETS)
|
|
1539
|
+
};
|
|
1540
|
+
parser.acceptLexerState(parentParser);
|
|
1541
|
+
}
|
|
1542
|
+
else {
|
|
1543
|
+
throw new Error('Missing \':\' or \'in\' inside square bracketed property.');
|
|
1544
|
+
}
|
|
1545
|
+
if (!parser.consume(']')) {
|
|
1546
|
+
throw new Error('Unterminated square brackets');
|
|
1547
|
+
}
|
|
1548
|
+
return result;
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
const objectFieldGrammar = [
|
|
1553
|
+
readonlyPropertyParslet,
|
|
1554
|
+
createNameParslet({
|
|
1555
|
+
allowedAdditionalTokens: ['module', 'event', 'keyof', 'event', 'external', 'in']
|
|
1556
|
+
}),
|
|
1557
|
+
nullableParslet,
|
|
1558
|
+
optionalParslet,
|
|
1559
|
+
stringValueParslet,
|
|
1560
|
+
numberParslet,
|
|
1561
|
+
createObjectFieldParslet({
|
|
1562
|
+
allowSquaredProperties: true,
|
|
1563
|
+
allowKeyTypes: false,
|
|
1564
|
+
allowOptional: true,
|
|
1565
|
+
allowReadonly: true
|
|
1566
|
+
}),
|
|
1567
|
+
objectSquaredPropertyParslet
|
|
1568
|
+
];
|
|
1569
|
+
const typescriptGrammar = [
|
|
1570
|
+
...baseGrammar,
|
|
1571
|
+
createObjectParslet({
|
|
1572
|
+
allowKeyTypes: false,
|
|
1573
|
+
objectFieldGrammar
|
|
1574
|
+
}),
|
|
1575
|
+
typeOfParslet,
|
|
1576
|
+
keyOfParslet,
|
|
1577
|
+
importParslet,
|
|
1578
|
+
stringValueParslet,
|
|
1579
|
+
createFunctionParslet({
|
|
1580
|
+
allowWithoutParenthesis: true,
|
|
1581
|
+
allowNoReturnType: false,
|
|
1582
|
+
allowNamedParameters: ['this', 'new', 'args'],
|
|
1583
|
+
allowNewAsFunctionKeyword: true
|
|
1584
|
+
}),
|
|
1585
|
+
createTupleParslet({
|
|
1586
|
+
allowQuestionMark: false
|
|
1587
|
+
}),
|
|
1588
|
+
createVariadicParslet({
|
|
1589
|
+
allowEnclosingBrackets: false,
|
|
1590
|
+
allowPostfix: false
|
|
1591
|
+
}),
|
|
1592
|
+
assertsParslet,
|
|
1593
|
+
createNameParslet({
|
|
1594
|
+
allowedAdditionalTokens: ['event', 'external', 'in']
|
|
1595
|
+
}),
|
|
1596
|
+
createSpecialNamePathParslet({
|
|
1597
|
+
allowedTypes: ['module'],
|
|
1598
|
+
pathGrammar
|
|
1599
|
+
}),
|
|
1600
|
+
arrayBracketsParslet,
|
|
1601
|
+
arrowFunctionParslet,
|
|
1602
|
+
createNamePathParslet({
|
|
1603
|
+
allowSquareBracketsOnAnyType: true,
|
|
1604
|
+
allowJsdocNamePaths: false,
|
|
1605
|
+
pathGrammar
|
|
1606
|
+
}),
|
|
1607
|
+
intersectionParslet,
|
|
1608
|
+
predicateParslet,
|
|
1609
|
+
createKeyValueParslet({
|
|
1610
|
+
allowVariadic: true,
|
|
1611
|
+
allowOptional: true
|
|
1612
|
+
})
|
|
1613
|
+
];
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* This function parses the given expression in the given mode and produces a {@link RootResult}.
|
|
1617
|
+
* @param expression
|
|
1618
|
+
* @param mode
|
|
1619
|
+
*/
|
|
1620
|
+
function parse(expression, mode) {
|
|
1621
|
+
switch (mode) {
|
|
1622
|
+
case 'closure':
|
|
1623
|
+
return (new Parser(closureGrammar, expression)).parse();
|
|
1624
|
+
case 'jsdoc':
|
|
1625
|
+
return (new Parser(jsdocGrammar, expression)).parse();
|
|
1626
|
+
case 'typescript':
|
|
1627
|
+
return (new Parser(typescriptGrammar, expression)).parse();
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1631
|
+
* This function tries to parse the given expression in multiple modes and returns the first successful
|
|
1632
|
+
* {@link RootResult}. By default it tries `'typescript'`, `'closure'` and `'jsdoc'` in this order. If
|
|
1633
|
+
* no mode was successful it throws the error that was produced by the last parsing attempt.
|
|
1634
|
+
* @param expression
|
|
1635
|
+
* @param modes
|
|
1636
|
+
*/
|
|
1637
|
+
function tryParse(expression, modes = ['typescript', 'closure', 'jsdoc']) {
|
|
1638
|
+
let error;
|
|
1639
|
+
for (const mode of modes) {
|
|
1640
|
+
try {
|
|
1641
|
+
return parse(expression, mode);
|
|
1642
|
+
}
|
|
1643
|
+
catch (e) {
|
|
1644
|
+
error = e;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
throw error;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
function transform(rules, parseResult) {
|
|
1651
|
+
const rule = rules[parseResult.type];
|
|
1652
|
+
if (rule === undefined) {
|
|
1653
|
+
throw new Error(`In this set of transform rules exists no rule for type ${parseResult.type}.`);
|
|
1654
|
+
}
|
|
1655
|
+
return rule(parseResult, aParseResult => transform(rules, aParseResult));
|
|
1656
|
+
}
|
|
1657
|
+
function notAvailableTransform(parseResult) {
|
|
1658
|
+
throw new Error('This transform is not available. Are you trying the correct parsing mode?');
|
|
1659
|
+
}
|
|
1660
|
+
function extractSpecialParams(source) {
|
|
1661
|
+
const result = {
|
|
1662
|
+
params: []
|
|
1663
|
+
};
|
|
1664
|
+
for (const param of source.parameters) {
|
|
1665
|
+
if (param.type === 'JsdocTypeKeyValue') {
|
|
1666
|
+
if (param.key === 'this') {
|
|
1667
|
+
result.this = param.right;
|
|
1668
|
+
}
|
|
1669
|
+
else if (param.key === 'new') {
|
|
1670
|
+
result.new = param.right;
|
|
1671
|
+
}
|
|
1672
|
+
else {
|
|
1673
|
+
result.params.push(param);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
result.params.push(param);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
return result;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
function applyPosition(position, target, value) {
|
|
1684
|
+
return position === 'prefix' ? value + target : target + value;
|
|
1685
|
+
}
|
|
1686
|
+
function quote(value, quote) {
|
|
1687
|
+
switch (quote) {
|
|
1688
|
+
case 'double':
|
|
1689
|
+
return `"${value}"`;
|
|
1690
|
+
case 'single':
|
|
1691
|
+
return `'${value}'`;
|
|
1692
|
+
case undefined:
|
|
1693
|
+
return value;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
function stringifyRules() {
|
|
1697
|
+
return {
|
|
1698
|
+
JsdocTypeParenthesis: (result, transform) => `(${result.element !== undefined ? transform(result.element) : ''})`,
|
|
1699
|
+
JsdocTypeKeyof: (result, transform) => `keyof ${transform(result.element)}`,
|
|
1700
|
+
JsdocTypeFunction: (result, transform) => {
|
|
1701
|
+
if (!result.arrow) {
|
|
1702
|
+
let stringified = result.constructor ? 'new' : 'function';
|
|
1703
|
+
if (!result.parenthesis) {
|
|
1704
|
+
return stringified;
|
|
1705
|
+
}
|
|
1706
|
+
stringified += `(${result.parameters.map(transform).join(', ')})`;
|
|
1707
|
+
if (result.returnType !== undefined) {
|
|
1708
|
+
stringified += `: ${transform(result.returnType)}`;
|
|
1709
|
+
}
|
|
1710
|
+
return stringified;
|
|
1711
|
+
}
|
|
1712
|
+
else {
|
|
1713
|
+
if (result.returnType === undefined) {
|
|
1714
|
+
throw new Error('Arrow function needs a return type.');
|
|
1715
|
+
}
|
|
1716
|
+
let stringified = `(${result.parameters.map(transform).join(', ')}) => ${transform(result.returnType)}`;
|
|
1717
|
+
if (result.constructor) {
|
|
1718
|
+
stringified = 'new ' + stringified;
|
|
1719
|
+
}
|
|
1720
|
+
return stringified;
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
JsdocTypeName: result => result.value,
|
|
1724
|
+
JsdocTypeTuple: (result, transform) => `[${result.elements.map(transform).join(', ')}]`,
|
|
1725
|
+
JsdocTypeVariadic: (result, transform) => result.meta.position === undefined
|
|
1726
|
+
? '...'
|
|
1727
|
+
: applyPosition(result.meta.position, transform(result.element), '...'),
|
|
1728
|
+
JsdocTypeNamePath: (result, transform) => {
|
|
1729
|
+
const left = transform(result.left);
|
|
1730
|
+
const right = transform(result.right);
|
|
1731
|
+
switch (result.pathType) {
|
|
1732
|
+
case 'inner':
|
|
1733
|
+
return `${left}~${right}`;
|
|
1734
|
+
case 'instance':
|
|
1735
|
+
return `${left}#${right}`;
|
|
1736
|
+
case 'property':
|
|
1737
|
+
return `${left}.${right}`;
|
|
1738
|
+
case 'property-brackets':
|
|
1739
|
+
return `${left}[${right}]`;
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
JsdocTypeStringValue: result => quote(result.value, result.meta.quote),
|
|
1743
|
+
JsdocTypeAny: () => '*',
|
|
1744
|
+
JsdocTypeGeneric: (result, transform) => {
|
|
1745
|
+
if (result.meta.brackets === 'square') {
|
|
1746
|
+
const element = result.elements[0];
|
|
1747
|
+
const transformed = transform(element);
|
|
1748
|
+
if (element.type === 'JsdocTypeUnion' || element.type === 'JsdocTypeIntersection') {
|
|
1749
|
+
return `(${transformed})[]`;
|
|
1750
|
+
}
|
|
1751
|
+
else {
|
|
1752
|
+
return `${transformed}[]`;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
else {
|
|
1756
|
+
return `${transform(result.left)}${result.meta.dot ? '.' : ''}<${result.elements.map(transform).join(', ')}>`;
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
JsdocTypeImport: (result, transform) => `import(${transform(result.element)})`,
|
|
1760
|
+
JsdocTypeObjectField: (result, transform) => {
|
|
1761
|
+
let text = '';
|
|
1762
|
+
if (result.readonly) {
|
|
1763
|
+
text += 'readonly ';
|
|
1764
|
+
}
|
|
1765
|
+
if (typeof result.key === 'string') {
|
|
1766
|
+
text += quote(result.key, result.meta.quote);
|
|
1767
|
+
}
|
|
1768
|
+
else {
|
|
1769
|
+
text += transform(result.key);
|
|
1770
|
+
}
|
|
1771
|
+
if (result.optional) {
|
|
1772
|
+
text += '?';
|
|
1773
|
+
}
|
|
1774
|
+
if (result.right === undefined) {
|
|
1775
|
+
return text;
|
|
1776
|
+
}
|
|
1777
|
+
else {
|
|
1778
|
+
return text + `: ${transform(result.right)}`;
|
|
1779
|
+
}
|
|
1780
|
+
},
|
|
1781
|
+
JsdocTypeJsdocObjectField: (result, transform) => {
|
|
1782
|
+
return `${transform(result.left)}: ${transform(result.right)}`;
|
|
1783
|
+
},
|
|
1784
|
+
JsdocTypeKeyValue: (result, transform) => {
|
|
1785
|
+
let text = result.key;
|
|
1786
|
+
if (result.optional) {
|
|
1787
|
+
text += '?';
|
|
1788
|
+
}
|
|
1789
|
+
if (result.variadic) {
|
|
1790
|
+
text = '...' + text;
|
|
1791
|
+
}
|
|
1792
|
+
if (result.right === undefined) {
|
|
1793
|
+
return text;
|
|
1794
|
+
}
|
|
1795
|
+
else {
|
|
1796
|
+
return text + `: ${transform(result.right)}`;
|
|
1797
|
+
}
|
|
1798
|
+
},
|
|
1799
|
+
JsdocTypeSpecialNamePath: result => `${result.specialType}:${quote(result.value, result.meta.quote)}`,
|
|
1800
|
+
JsdocTypeNotNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), '!'),
|
|
1801
|
+
JsdocTypeNull: () => 'null',
|
|
1802
|
+
JsdocTypeNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), '?'),
|
|
1803
|
+
JsdocTypeNumber: result => result.value.toString(),
|
|
1804
|
+
JsdocTypeObject: (result, transform) => `{${result.elements.map(transform).join((result.meta.separator === 'comma' ? ',' : ';') + ' ')}}`,
|
|
1805
|
+
JsdocTypeOptional: (result, transform) => applyPosition(result.meta.position, transform(result.element), '='),
|
|
1806
|
+
JsdocTypeSymbol: (result, transform) => `${result.value}(${result.element !== undefined ? transform(result.element) : ''})`,
|
|
1807
|
+
JsdocTypeTypeof: (result, transform) => `typeof ${transform(result.element)}`,
|
|
1808
|
+
JsdocTypeUndefined: () => 'undefined',
|
|
1809
|
+
JsdocTypeUnion: (result, transform) => result.elements.map(transform).join(' | '),
|
|
1810
|
+
JsdocTypeUnknown: () => '?',
|
|
1811
|
+
JsdocTypeIntersection: (result, transform) => result.elements.map(transform).join(' & '),
|
|
1812
|
+
JsdocTypeProperty: result => quote(result.value, result.meta.quote),
|
|
1813
|
+
JsdocTypePredicate: (result, transform) => `${transform(result.left)} is ${transform(result.right)}`,
|
|
1814
|
+
JsdocTypeIndexSignature: (result, transform) => `[${result.key}: ${transform(result.right)}]`,
|
|
1815
|
+
JsdocTypeMappedType: (result, transform) => `[${result.key} in ${transform(result.right)}]`,
|
|
1816
|
+
JsdocTypeAsserts: (result, transform) => `asserts ${transform(result.left)} is ${transform(result.right)}`
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
const storedStringifyRules = stringifyRules();
|
|
1820
|
+
function stringify(result) {
|
|
1821
|
+
return transform(storedStringifyRules, result);
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
const reservedWords = [
|
|
1825
|
+
'null',
|
|
1826
|
+
'true',
|
|
1827
|
+
'false',
|
|
1828
|
+
'break',
|
|
1829
|
+
'case',
|
|
1830
|
+
'catch',
|
|
1831
|
+
'class',
|
|
1832
|
+
'const',
|
|
1833
|
+
'continue',
|
|
1834
|
+
'debugger',
|
|
1835
|
+
'default',
|
|
1836
|
+
'delete',
|
|
1837
|
+
'do',
|
|
1838
|
+
'else',
|
|
1839
|
+
'export',
|
|
1840
|
+
'extends',
|
|
1841
|
+
'finally',
|
|
1842
|
+
'for',
|
|
1843
|
+
'function',
|
|
1844
|
+
'if',
|
|
1845
|
+
'import',
|
|
1846
|
+
'in',
|
|
1847
|
+
'instanceof',
|
|
1848
|
+
'new',
|
|
1849
|
+
'return',
|
|
1850
|
+
'super',
|
|
1851
|
+
'switch',
|
|
1852
|
+
'this',
|
|
1853
|
+
'throw',
|
|
1854
|
+
'try',
|
|
1855
|
+
'typeof',
|
|
1856
|
+
'var',
|
|
1857
|
+
'void',
|
|
1858
|
+
'while',
|
|
1859
|
+
'with',
|
|
1860
|
+
'yield'
|
|
1861
|
+
];
|
|
1862
|
+
function makeName(value) {
|
|
1863
|
+
const result = {
|
|
1864
|
+
type: 'NameExpression',
|
|
1865
|
+
name: value
|
|
1866
|
+
};
|
|
1867
|
+
if (reservedWords.includes(value)) {
|
|
1868
|
+
result.reservedWord = true;
|
|
1869
|
+
}
|
|
1870
|
+
return result;
|
|
1871
|
+
}
|
|
1872
|
+
const catharsisTransformRules = {
|
|
1873
|
+
JsdocTypeOptional: (result, transform) => {
|
|
1874
|
+
const transformed = transform(result.element);
|
|
1875
|
+
transformed.optional = true;
|
|
1876
|
+
return transformed;
|
|
1877
|
+
},
|
|
1878
|
+
JsdocTypeNullable: (result, transform) => {
|
|
1879
|
+
const transformed = transform(result.element);
|
|
1880
|
+
transformed.nullable = true;
|
|
1881
|
+
return transformed;
|
|
1882
|
+
},
|
|
1883
|
+
JsdocTypeNotNullable: (result, transform) => {
|
|
1884
|
+
const transformed = transform(result.element);
|
|
1885
|
+
transformed.nullable = false;
|
|
1886
|
+
return transformed;
|
|
1887
|
+
},
|
|
1888
|
+
JsdocTypeVariadic: (result, transform) => {
|
|
1889
|
+
if (result.element === undefined) {
|
|
1890
|
+
throw new Error('dots without value are not allowed in catharsis mode');
|
|
1891
|
+
}
|
|
1892
|
+
const transformed = transform(result.element);
|
|
1893
|
+
transformed.repeatable = true;
|
|
1894
|
+
return transformed;
|
|
1895
|
+
},
|
|
1896
|
+
JsdocTypeAny: () => ({
|
|
1897
|
+
type: 'AllLiteral'
|
|
1898
|
+
}),
|
|
1899
|
+
JsdocTypeNull: () => ({
|
|
1900
|
+
type: 'NullLiteral'
|
|
1901
|
+
}),
|
|
1902
|
+
JsdocTypeStringValue: result => makeName(quote(result.value, result.meta.quote)),
|
|
1903
|
+
JsdocTypeUndefined: () => ({
|
|
1904
|
+
type: 'UndefinedLiteral'
|
|
1905
|
+
}),
|
|
1906
|
+
JsdocTypeUnknown: () => ({
|
|
1907
|
+
type: 'UnknownLiteral'
|
|
1908
|
+
}),
|
|
1909
|
+
JsdocTypeFunction: (result, transform) => {
|
|
1910
|
+
const params = extractSpecialParams(result);
|
|
1911
|
+
const transformed = {
|
|
1912
|
+
type: 'FunctionType',
|
|
1913
|
+
params: params.params.map(transform)
|
|
1914
|
+
};
|
|
1915
|
+
if (params.this !== undefined) {
|
|
1916
|
+
transformed.this = transform(params.this);
|
|
1917
|
+
}
|
|
1918
|
+
if (params.new !== undefined) {
|
|
1919
|
+
transformed.new = transform(params.new);
|
|
1920
|
+
}
|
|
1921
|
+
if (result.returnType !== undefined) {
|
|
1922
|
+
transformed.result = transform(result.returnType);
|
|
1923
|
+
}
|
|
1924
|
+
return transformed;
|
|
1925
|
+
},
|
|
1926
|
+
JsdocTypeGeneric: (result, transform) => ({
|
|
1927
|
+
type: 'TypeApplication',
|
|
1928
|
+
applications: result.elements.map(o => transform(o)),
|
|
1929
|
+
expression: transform(result.left)
|
|
1930
|
+
}),
|
|
1931
|
+
JsdocTypeSpecialNamePath: result => makeName(result.specialType + ':' + quote(result.value, result.meta.quote)),
|
|
1932
|
+
JsdocTypeName: result => {
|
|
1933
|
+
if (result.value !== 'function') {
|
|
1934
|
+
return makeName(result.value);
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
return {
|
|
1938
|
+
type: 'FunctionType',
|
|
1939
|
+
params: []
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
},
|
|
1943
|
+
JsdocTypeNumber: result => makeName(result.value.toString()),
|
|
1944
|
+
JsdocTypeObject: (result, transform) => {
|
|
1945
|
+
const transformed = {
|
|
1946
|
+
type: 'RecordType',
|
|
1947
|
+
fields: []
|
|
1948
|
+
};
|
|
1949
|
+
for (const field of result.elements) {
|
|
1950
|
+
if (field.type !== 'JsdocTypeObjectField' && field.type !== 'JsdocTypeJsdocObjectField') {
|
|
1951
|
+
transformed.fields.push({
|
|
1952
|
+
type: 'FieldType',
|
|
1953
|
+
key: transform(field),
|
|
1954
|
+
value: undefined
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
else {
|
|
1958
|
+
transformed.fields.push(transform(field));
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
return transformed;
|
|
1962
|
+
},
|
|
1963
|
+
JsdocTypeObjectField: (result, transform) => {
|
|
1964
|
+
if (typeof result.key !== 'string') {
|
|
1965
|
+
throw new Error('Index signatures and mapped types are not supported');
|
|
1966
|
+
}
|
|
1967
|
+
return {
|
|
1968
|
+
type: 'FieldType',
|
|
1969
|
+
key: makeName(quote(result.key, result.meta.quote)),
|
|
1970
|
+
value: result.right === undefined ? undefined : transform(result.right)
|
|
1971
|
+
};
|
|
1972
|
+
},
|
|
1973
|
+
JsdocTypeJsdocObjectField: (result, transform) => ({
|
|
1974
|
+
type: 'FieldType',
|
|
1975
|
+
key: transform(result.left),
|
|
1976
|
+
value: transform(result.right)
|
|
1977
|
+
}),
|
|
1978
|
+
JsdocTypeUnion: (result, transform) => ({
|
|
1979
|
+
type: 'TypeUnion',
|
|
1980
|
+
elements: result.elements.map(e => transform(e))
|
|
1981
|
+
}),
|
|
1982
|
+
JsdocTypeKeyValue: (result, transform) => {
|
|
1983
|
+
return {
|
|
1984
|
+
type: 'FieldType',
|
|
1985
|
+
key: makeName(result.key),
|
|
1986
|
+
value: result.right === undefined ? undefined : transform(result.right)
|
|
1987
|
+
};
|
|
1988
|
+
},
|
|
1989
|
+
JsdocTypeNamePath: (result, transform) => {
|
|
1990
|
+
const leftResult = transform(result.left);
|
|
1991
|
+
let rightValue;
|
|
1992
|
+
if (result.right.type === 'JsdocTypeSpecialNamePath') {
|
|
1993
|
+
rightValue = transform(result.right).name;
|
|
1994
|
+
}
|
|
1995
|
+
else {
|
|
1996
|
+
rightValue = quote(result.right.value, result.right.meta.quote);
|
|
1997
|
+
}
|
|
1998
|
+
const joiner = result.pathType === 'inner' ? '~' : result.pathType === 'instance' ? '#' : '.';
|
|
1999
|
+
return makeName(`${leftResult.name}${joiner}${rightValue}`);
|
|
2000
|
+
},
|
|
2001
|
+
JsdocTypeSymbol: result => {
|
|
2002
|
+
let value = '';
|
|
2003
|
+
let element = result.element;
|
|
2004
|
+
let trailingDots = false;
|
|
2005
|
+
if ((element === null || element === void 0 ? void 0 : element.type) === 'JsdocTypeVariadic') {
|
|
2006
|
+
if (element.meta.position === 'prefix') {
|
|
2007
|
+
value = '...';
|
|
2008
|
+
}
|
|
2009
|
+
else {
|
|
2010
|
+
trailingDots = true;
|
|
2011
|
+
}
|
|
2012
|
+
element = element.element;
|
|
2013
|
+
}
|
|
2014
|
+
if ((element === null || element === void 0 ? void 0 : element.type) === 'JsdocTypeName') {
|
|
2015
|
+
value += element.value;
|
|
2016
|
+
}
|
|
2017
|
+
else if ((element === null || element === void 0 ? void 0 : element.type) === 'JsdocTypeNumber') {
|
|
2018
|
+
value += element.value.toString();
|
|
2019
|
+
}
|
|
2020
|
+
if (trailingDots) {
|
|
2021
|
+
value += '...';
|
|
2022
|
+
}
|
|
2023
|
+
return makeName(`${result.value}(${value})`);
|
|
2024
|
+
},
|
|
2025
|
+
JsdocTypeParenthesis: (result, transform) => transform(assertRootResult(result.element)),
|
|
2026
|
+
JsdocTypeMappedType: notAvailableTransform,
|
|
2027
|
+
JsdocTypeIndexSignature: notAvailableTransform,
|
|
2028
|
+
JsdocTypeImport: notAvailableTransform,
|
|
2029
|
+
JsdocTypeKeyof: notAvailableTransform,
|
|
2030
|
+
JsdocTypeTuple: notAvailableTransform,
|
|
2031
|
+
JsdocTypeTypeof: notAvailableTransform,
|
|
2032
|
+
JsdocTypeIntersection: notAvailableTransform,
|
|
2033
|
+
JsdocTypeProperty: notAvailableTransform,
|
|
2034
|
+
JsdocTypePredicate: notAvailableTransform,
|
|
2035
|
+
JsdocTypeAsserts: notAvailableTransform
|
|
2036
|
+
};
|
|
2037
|
+
function catharsisTransform(result) {
|
|
2038
|
+
return transform(catharsisTransformRules, result);
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
function getQuoteStyle(quote) {
|
|
2042
|
+
switch (quote) {
|
|
2043
|
+
case undefined:
|
|
2044
|
+
return 'none';
|
|
2045
|
+
case 'single':
|
|
2046
|
+
return 'single';
|
|
2047
|
+
case 'double':
|
|
2048
|
+
return 'double';
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
function getMemberType(type) {
|
|
2052
|
+
switch (type) {
|
|
2053
|
+
case 'inner':
|
|
2054
|
+
return 'INNER_MEMBER';
|
|
2055
|
+
case 'instance':
|
|
2056
|
+
return 'INSTANCE_MEMBER';
|
|
2057
|
+
case 'property':
|
|
2058
|
+
return 'MEMBER';
|
|
2059
|
+
case 'property-brackets':
|
|
2060
|
+
return 'MEMBER';
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
function nestResults(type, results) {
|
|
2064
|
+
if (results.length === 2) {
|
|
2065
|
+
return {
|
|
2066
|
+
type,
|
|
2067
|
+
left: results[0],
|
|
2068
|
+
right: results[1]
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
else {
|
|
2072
|
+
return {
|
|
2073
|
+
type,
|
|
2074
|
+
left: results[0],
|
|
2075
|
+
right: nestResults(type, results.slice(1))
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
const jtpRules = {
|
|
2080
|
+
JsdocTypeOptional: (result, transform) => ({
|
|
2081
|
+
type: 'OPTIONAL',
|
|
2082
|
+
value: transform(result.element),
|
|
2083
|
+
meta: {
|
|
2084
|
+
syntax: result.meta.position === 'prefix' ? 'PREFIX_EQUAL_SIGN' : 'SUFFIX_EQUALS_SIGN'
|
|
2085
|
+
}
|
|
2086
|
+
}),
|
|
2087
|
+
JsdocTypeNullable: (result, transform) => ({
|
|
2088
|
+
type: 'NULLABLE',
|
|
2089
|
+
value: transform(result.element),
|
|
2090
|
+
meta: {
|
|
2091
|
+
syntax: result.meta.position === 'prefix' ? 'PREFIX_QUESTION_MARK' : 'SUFFIX_QUESTION_MARK'
|
|
2092
|
+
}
|
|
2093
|
+
}),
|
|
2094
|
+
JsdocTypeNotNullable: (result, transform) => ({
|
|
2095
|
+
type: 'NOT_NULLABLE',
|
|
2096
|
+
value: transform(result.element),
|
|
2097
|
+
meta: {
|
|
2098
|
+
syntax: result.meta.position === 'prefix' ? 'PREFIX_BANG' : 'SUFFIX_BANG'
|
|
2099
|
+
}
|
|
2100
|
+
}),
|
|
2101
|
+
JsdocTypeVariadic: (result, transform) => {
|
|
2102
|
+
const transformed = {
|
|
2103
|
+
type: 'VARIADIC',
|
|
2104
|
+
meta: {
|
|
2105
|
+
syntax: result.meta.position === 'prefix'
|
|
2106
|
+
? 'PREFIX_DOTS'
|
|
2107
|
+
: result.meta.position === 'suffix' ? 'SUFFIX_DOTS' : 'ONLY_DOTS'
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
if (result.element !== undefined) {
|
|
2111
|
+
transformed.value = transform(result.element);
|
|
2112
|
+
}
|
|
2113
|
+
return transformed;
|
|
2114
|
+
},
|
|
2115
|
+
JsdocTypeName: result => ({
|
|
2116
|
+
type: 'NAME',
|
|
2117
|
+
name: result.value
|
|
2118
|
+
}),
|
|
2119
|
+
JsdocTypeTypeof: (result, transform) => ({
|
|
2120
|
+
type: 'TYPE_QUERY',
|
|
2121
|
+
name: transform(result.element)
|
|
2122
|
+
}),
|
|
2123
|
+
JsdocTypeTuple: (result, transform) => ({
|
|
2124
|
+
type: 'TUPLE',
|
|
2125
|
+
entries: result.elements.map(transform)
|
|
2126
|
+
}),
|
|
2127
|
+
JsdocTypeKeyof: (result, transform) => ({
|
|
2128
|
+
type: 'KEY_QUERY',
|
|
2129
|
+
value: transform(result.element)
|
|
2130
|
+
}),
|
|
2131
|
+
JsdocTypeImport: result => ({
|
|
2132
|
+
type: 'IMPORT',
|
|
2133
|
+
path: {
|
|
2134
|
+
type: 'STRING_VALUE',
|
|
2135
|
+
quoteStyle: getQuoteStyle(result.element.meta.quote),
|
|
2136
|
+
string: result.element.value
|
|
2137
|
+
}
|
|
2138
|
+
}),
|
|
2139
|
+
JsdocTypeUndefined: () => ({
|
|
2140
|
+
type: 'NAME',
|
|
2141
|
+
name: 'undefined'
|
|
2142
|
+
}),
|
|
2143
|
+
JsdocTypeAny: () => ({
|
|
2144
|
+
type: 'ANY'
|
|
2145
|
+
}),
|
|
2146
|
+
JsdocTypeFunction: (result, transform) => {
|
|
2147
|
+
const specialParams = extractSpecialParams(result);
|
|
2148
|
+
const transformed = {
|
|
2149
|
+
type: result.arrow ? 'ARROW' : 'FUNCTION',
|
|
2150
|
+
params: specialParams.params.map(param => {
|
|
2151
|
+
if (param.type === 'JsdocTypeKeyValue') {
|
|
2152
|
+
if (param.right === undefined) {
|
|
2153
|
+
throw new Error('Function parameter without \':\' is not expected to be \'KEY_VALUE\'');
|
|
2154
|
+
}
|
|
2155
|
+
return {
|
|
2156
|
+
type: 'NAMED_PARAMETER',
|
|
2157
|
+
name: param.key,
|
|
2158
|
+
typeName: transform(param.right)
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
else {
|
|
2162
|
+
return transform(param);
|
|
2163
|
+
}
|
|
2164
|
+
}),
|
|
2165
|
+
new: null,
|
|
2166
|
+
returns: null
|
|
2167
|
+
};
|
|
2168
|
+
if (specialParams.this !== undefined) {
|
|
2169
|
+
transformed.this = transform(specialParams.this);
|
|
2170
|
+
}
|
|
2171
|
+
else if (!result.arrow) {
|
|
2172
|
+
transformed.this = null;
|
|
2173
|
+
}
|
|
2174
|
+
if (specialParams.new !== undefined) {
|
|
2175
|
+
transformed.new = transform(specialParams.new);
|
|
2176
|
+
}
|
|
2177
|
+
if (result.returnType !== undefined) {
|
|
2178
|
+
transformed.returns = transform(result.returnType);
|
|
2179
|
+
}
|
|
2180
|
+
return transformed;
|
|
2181
|
+
},
|
|
2182
|
+
JsdocTypeGeneric: (result, transform) => {
|
|
2183
|
+
const transformed = {
|
|
2184
|
+
type: 'GENERIC',
|
|
2185
|
+
subject: transform(result.left),
|
|
2186
|
+
objects: result.elements.map(transform),
|
|
2187
|
+
meta: {
|
|
2188
|
+
syntax: result.meta.brackets === 'square' ? 'SQUARE_BRACKET' : result.meta.dot ? 'ANGLE_BRACKET_WITH_DOT' : 'ANGLE_BRACKET'
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
if (result.meta.brackets === 'square' && result.elements[0].type === 'JsdocTypeFunction' && !result.elements[0].parenthesis) {
|
|
2192
|
+
transformed.objects[0] = {
|
|
2193
|
+
type: 'NAME',
|
|
2194
|
+
name: 'function'
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
return transformed;
|
|
2198
|
+
},
|
|
2199
|
+
JsdocTypeObjectField: (result, transform) => {
|
|
2200
|
+
if (typeof result.key !== 'string') {
|
|
2201
|
+
throw new Error('Index signatures and mapped types are not supported');
|
|
2202
|
+
}
|
|
2203
|
+
if (result.right === undefined) {
|
|
2204
|
+
return {
|
|
2205
|
+
type: 'RECORD_ENTRY',
|
|
2206
|
+
key: result.key,
|
|
2207
|
+
quoteStyle: getQuoteStyle(result.meta.quote),
|
|
2208
|
+
value: null,
|
|
2209
|
+
readonly: false
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
let right = transform(result.right);
|
|
2213
|
+
if (result.optional) {
|
|
2214
|
+
right = {
|
|
2215
|
+
type: 'OPTIONAL',
|
|
2216
|
+
value: right,
|
|
2217
|
+
meta: {
|
|
2218
|
+
syntax: 'SUFFIX_KEY_QUESTION_MARK'
|
|
2219
|
+
}
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
return {
|
|
2223
|
+
type: 'RECORD_ENTRY',
|
|
2224
|
+
key: result.key.toString(),
|
|
2225
|
+
quoteStyle: getQuoteStyle(result.meta.quote),
|
|
2226
|
+
value: right,
|
|
2227
|
+
readonly: false
|
|
2228
|
+
};
|
|
2229
|
+
},
|
|
2230
|
+
JsdocTypeJsdocObjectField: () => {
|
|
2231
|
+
throw new Error('Keys may not be typed in jsdoctypeparser.');
|
|
2232
|
+
},
|
|
2233
|
+
JsdocTypeKeyValue: (result, transform) => {
|
|
2234
|
+
if (result.right === undefined) {
|
|
2235
|
+
return {
|
|
2236
|
+
type: 'RECORD_ENTRY',
|
|
2237
|
+
key: result.key,
|
|
2238
|
+
quoteStyle: 'none',
|
|
2239
|
+
value: null,
|
|
2240
|
+
readonly: false
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
let right = transform(result.right);
|
|
2244
|
+
if (result.optional) {
|
|
2245
|
+
right = {
|
|
2246
|
+
type: 'OPTIONAL',
|
|
2247
|
+
value: right,
|
|
2248
|
+
meta: {
|
|
2249
|
+
syntax: 'SUFFIX_KEY_QUESTION_MARK'
|
|
2250
|
+
}
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
return {
|
|
2254
|
+
type: 'RECORD_ENTRY',
|
|
2255
|
+
key: result.key,
|
|
2256
|
+
quoteStyle: 'none',
|
|
2257
|
+
value: right,
|
|
2258
|
+
readonly: false
|
|
2259
|
+
};
|
|
2260
|
+
},
|
|
2261
|
+
JsdocTypeObject: (result, transform) => {
|
|
2262
|
+
const entries = [];
|
|
2263
|
+
for (const field of result.elements) {
|
|
2264
|
+
if (field.type === 'JsdocTypeObjectField' || field.type === 'JsdocTypeJsdocObjectField') {
|
|
2265
|
+
entries.push(transform(field));
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
return {
|
|
2269
|
+
type: 'RECORD',
|
|
2270
|
+
entries
|
|
2271
|
+
};
|
|
2272
|
+
},
|
|
2273
|
+
JsdocTypeSpecialNamePath: result => {
|
|
2274
|
+
if (result.specialType !== 'module') {
|
|
2275
|
+
throw new Error(`jsdoctypeparser does not support type ${result.specialType} at this point.`);
|
|
2276
|
+
}
|
|
2277
|
+
return {
|
|
2278
|
+
type: 'MODULE',
|
|
2279
|
+
value: {
|
|
2280
|
+
type: 'FILE_PATH',
|
|
2281
|
+
quoteStyle: getQuoteStyle(result.meta.quote),
|
|
2282
|
+
path: result.value
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
},
|
|
2286
|
+
JsdocTypeNamePath: (result, transform) => {
|
|
2287
|
+
let hasEventPrefix = false;
|
|
2288
|
+
let name;
|
|
2289
|
+
let quoteStyle;
|
|
2290
|
+
if (result.right.type === 'JsdocTypeSpecialNamePath' && result.right.specialType === 'event') {
|
|
2291
|
+
hasEventPrefix = true;
|
|
2292
|
+
name = result.right.value;
|
|
2293
|
+
quoteStyle = getQuoteStyle(result.right.meta.quote);
|
|
2294
|
+
}
|
|
2295
|
+
else {
|
|
2296
|
+
name = result.right.value;
|
|
2297
|
+
quoteStyle = getQuoteStyle(result.right.meta.quote);
|
|
2298
|
+
}
|
|
2299
|
+
const transformed = {
|
|
2300
|
+
type: getMemberType(result.pathType),
|
|
2301
|
+
owner: transform(result.left),
|
|
2302
|
+
name,
|
|
2303
|
+
quoteStyle,
|
|
2304
|
+
hasEventPrefix
|
|
2305
|
+
};
|
|
2306
|
+
if (transformed.owner.type === 'MODULE') {
|
|
2307
|
+
const tModule = transformed.owner;
|
|
2308
|
+
transformed.owner = transformed.owner.value;
|
|
2309
|
+
tModule.value = transformed;
|
|
2310
|
+
return tModule;
|
|
2311
|
+
}
|
|
2312
|
+
else {
|
|
2313
|
+
return transformed;
|
|
2314
|
+
}
|
|
2315
|
+
},
|
|
2316
|
+
JsdocTypeUnion: (result, transform) => nestResults('UNION', result.elements.map(transform)),
|
|
2317
|
+
JsdocTypeParenthesis: (result, transform) => ({
|
|
2318
|
+
type: 'PARENTHESIS',
|
|
2319
|
+
value: transform(assertRootResult(result.element))
|
|
2320
|
+
}),
|
|
2321
|
+
JsdocTypeNull: () => ({
|
|
2322
|
+
type: 'NAME',
|
|
2323
|
+
name: 'null'
|
|
2324
|
+
}),
|
|
2325
|
+
JsdocTypeUnknown: () => ({
|
|
2326
|
+
type: 'UNKNOWN'
|
|
2327
|
+
}),
|
|
2328
|
+
JsdocTypeStringValue: result => ({
|
|
2329
|
+
type: 'STRING_VALUE',
|
|
2330
|
+
quoteStyle: getQuoteStyle(result.meta.quote),
|
|
2331
|
+
string: result.value
|
|
2332
|
+
}),
|
|
2333
|
+
JsdocTypeIntersection: (result, transform) => nestResults('INTERSECTION', result.elements.map(transform)),
|
|
2334
|
+
JsdocTypeNumber: result => ({
|
|
2335
|
+
type: 'NUMBER_VALUE',
|
|
2336
|
+
number: result.value.toString()
|
|
2337
|
+
}),
|
|
2338
|
+
JsdocTypeSymbol: notAvailableTransform,
|
|
2339
|
+
JsdocTypeProperty: notAvailableTransform,
|
|
2340
|
+
JsdocTypePredicate: notAvailableTransform,
|
|
2341
|
+
JsdocTypeMappedType: notAvailableTransform,
|
|
2342
|
+
JsdocTypeIndexSignature: notAvailableTransform,
|
|
2343
|
+
JsdocTypeAsserts: notAvailableTransform
|
|
2344
|
+
};
|
|
2345
|
+
function jtpTransform(result) {
|
|
2346
|
+
return transform(jtpRules, result);
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
function identityTransformRules() {
|
|
2350
|
+
return {
|
|
2351
|
+
JsdocTypeIntersection: (result, transform) => ({
|
|
2352
|
+
type: 'JsdocTypeIntersection',
|
|
2353
|
+
elements: result.elements.map(transform)
|
|
2354
|
+
}),
|
|
2355
|
+
JsdocTypeGeneric: (result, transform) => ({
|
|
2356
|
+
type: 'JsdocTypeGeneric',
|
|
2357
|
+
left: transform(result.left),
|
|
2358
|
+
elements: result.elements.map(transform),
|
|
2359
|
+
meta: {
|
|
2360
|
+
dot: result.meta.dot,
|
|
2361
|
+
brackets: result.meta.brackets
|
|
2362
|
+
}
|
|
2363
|
+
}),
|
|
2364
|
+
JsdocTypeNullable: result => result,
|
|
2365
|
+
JsdocTypeUnion: (result, transform) => ({
|
|
2366
|
+
type: 'JsdocTypeUnion',
|
|
2367
|
+
elements: result.elements.map(transform)
|
|
2368
|
+
}),
|
|
2369
|
+
JsdocTypeUnknown: result => result,
|
|
2370
|
+
JsdocTypeUndefined: result => result,
|
|
2371
|
+
JsdocTypeTypeof: (result, transform) => ({
|
|
2372
|
+
type: 'JsdocTypeTypeof',
|
|
2373
|
+
element: transform(result.element)
|
|
2374
|
+
}),
|
|
2375
|
+
JsdocTypeSymbol: (result, transform) => {
|
|
2376
|
+
const transformed = {
|
|
2377
|
+
type: 'JsdocTypeSymbol',
|
|
2378
|
+
value: result.value
|
|
2379
|
+
};
|
|
2380
|
+
if (result.element !== undefined) {
|
|
2381
|
+
transformed.element = transform(result.element);
|
|
2382
|
+
}
|
|
2383
|
+
return transformed;
|
|
2384
|
+
},
|
|
2385
|
+
JsdocTypeOptional: (result, transform) => ({
|
|
2386
|
+
type: 'JsdocTypeOptional',
|
|
2387
|
+
element: transform(result.element),
|
|
2388
|
+
meta: {
|
|
2389
|
+
position: result.meta.position
|
|
2390
|
+
}
|
|
2391
|
+
}),
|
|
2392
|
+
JsdocTypeObject: (result, transform) => ({
|
|
2393
|
+
type: 'JsdocTypeObject',
|
|
2394
|
+
meta: {
|
|
2395
|
+
separator: 'comma'
|
|
2396
|
+
},
|
|
2397
|
+
elements: result.elements.map(transform)
|
|
2398
|
+
}),
|
|
2399
|
+
JsdocTypeNumber: result => result,
|
|
2400
|
+
JsdocTypeNull: result => result,
|
|
2401
|
+
JsdocTypeNotNullable: (result, transform) => ({
|
|
2402
|
+
type: 'JsdocTypeNotNullable',
|
|
2403
|
+
element: transform(result.element),
|
|
2404
|
+
meta: {
|
|
2405
|
+
position: result.meta.position
|
|
2406
|
+
}
|
|
2407
|
+
}),
|
|
2408
|
+
JsdocTypeSpecialNamePath: result => result,
|
|
2409
|
+
JsdocTypeObjectField: (result, transform) => ({
|
|
2410
|
+
type: 'JsdocTypeObjectField',
|
|
2411
|
+
key: result.key,
|
|
2412
|
+
right: result.right === undefined ? undefined : transform(result.right),
|
|
2413
|
+
optional: result.optional,
|
|
2414
|
+
readonly: result.readonly,
|
|
2415
|
+
meta: result.meta
|
|
2416
|
+
}),
|
|
2417
|
+
JsdocTypeJsdocObjectField: (result, transform) => ({
|
|
2418
|
+
type: 'JsdocTypeJsdocObjectField',
|
|
2419
|
+
left: transform(result.left),
|
|
2420
|
+
right: transform(result.right)
|
|
2421
|
+
}),
|
|
2422
|
+
JsdocTypeKeyValue: (result, transform) => {
|
|
2423
|
+
return {
|
|
2424
|
+
type: 'JsdocTypeKeyValue',
|
|
2425
|
+
key: result.key,
|
|
2426
|
+
right: result.right === undefined ? undefined : transform(result.right),
|
|
2427
|
+
optional: result.optional,
|
|
2428
|
+
variadic: result.variadic
|
|
2429
|
+
};
|
|
2430
|
+
},
|
|
2431
|
+
JsdocTypeImport: (result, transform) => ({
|
|
2432
|
+
type: 'JsdocTypeImport',
|
|
2433
|
+
element: transform(result.element)
|
|
2434
|
+
}),
|
|
2435
|
+
JsdocTypeAny: result => result,
|
|
2436
|
+
JsdocTypeStringValue: result => result,
|
|
2437
|
+
JsdocTypeNamePath: result => result,
|
|
2438
|
+
JsdocTypeVariadic: (result, transform) => {
|
|
2439
|
+
const transformed = {
|
|
2440
|
+
type: 'JsdocTypeVariadic',
|
|
2441
|
+
meta: {
|
|
2442
|
+
position: result.meta.position,
|
|
2443
|
+
squareBrackets: result.meta.squareBrackets
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
if (result.element !== undefined) {
|
|
2447
|
+
transformed.element = transform(result.element);
|
|
2448
|
+
}
|
|
2449
|
+
return transformed;
|
|
2450
|
+
},
|
|
2451
|
+
JsdocTypeTuple: (result, transform) => ({
|
|
2452
|
+
type: 'JsdocTypeTuple',
|
|
2453
|
+
elements: result.elements.map(transform)
|
|
2454
|
+
}),
|
|
2455
|
+
JsdocTypeName: result => result,
|
|
2456
|
+
JsdocTypeFunction: (result, transform) => {
|
|
2457
|
+
const transformed = {
|
|
2458
|
+
type: 'JsdocTypeFunction',
|
|
2459
|
+
arrow: result.arrow,
|
|
2460
|
+
parameters: result.parameters.map(transform),
|
|
2461
|
+
constructor: result.constructor,
|
|
2462
|
+
parenthesis: result.parenthesis
|
|
2463
|
+
};
|
|
2464
|
+
if (result.returnType !== undefined) {
|
|
2465
|
+
transformed.returnType = transform(result.returnType);
|
|
2466
|
+
}
|
|
2467
|
+
return transformed;
|
|
2468
|
+
},
|
|
2469
|
+
JsdocTypeKeyof: (result, transform) => ({
|
|
2470
|
+
type: 'JsdocTypeKeyof',
|
|
2471
|
+
element: transform(result.element)
|
|
2472
|
+
}),
|
|
2473
|
+
JsdocTypeParenthesis: (result, transform) => ({
|
|
2474
|
+
type: 'JsdocTypeParenthesis',
|
|
2475
|
+
element: transform(result.element)
|
|
2476
|
+
}),
|
|
2477
|
+
JsdocTypeProperty: result => result,
|
|
2478
|
+
JsdocTypePredicate: (result, transform) => ({
|
|
2479
|
+
type: 'JsdocTypePredicate',
|
|
2480
|
+
left: transform(result.left),
|
|
2481
|
+
right: transform(result.right)
|
|
2482
|
+
}),
|
|
2483
|
+
JsdocTypeIndexSignature: (result, transform) => ({
|
|
2484
|
+
type: 'JsdocTypeIndexSignature',
|
|
2485
|
+
key: result.key,
|
|
2486
|
+
right: transform(result.right)
|
|
2487
|
+
}),
|
|
2488
|
+
JsdocTypeMappedType: (result, transform) => ({
|
|
2489
|
+
type: 'JsdocTypeMappedType',
|
|
2490
|
+
key: result.key,
|
|
2491
|
+
right: transform(result.right)
|
|
2492
|
+
}),
|
|
2493
|
+
JsdocTypeAsserts: (result, transform) => ({
|
|
2494
|
+
type: 'JsdocTypeAsserts',
|
|
2495
|
+
left: transform(result.left),
|
|
2496
|
+
right: transform(result.right)
|
|
2497
|
+
})
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
const visitorKeys = {
|
|
2502
|
+
JsdocTypeAny: [],
|
|
2503
|
+
JsdocTypeFunction: ['parameters', 'returnType'],
|
|
2504
|
+
JsdocTypeGeneric: ['left', 'elements'],
|
|
2505
|
+
JsdocTypeImport: [],
|
|
2506
|
+
JsdocTypeIndexSignature: ['right'],
|
|
2507
|
+
JsdocTypeIntersection: ['elements'],
|
|
2508
|
+
JsdocTypeKeyof: ['element'],
|
|
2509
|
+
JsdocTypeKeyValue: ['right'],
|
|
2510
|
+
JsdocTypeMappedType: ['right'],
|
|
2511
|
+
JsdocTypeName: [],
|
|
2512
|
+
JsdocTypeNamePath: ['left', 'right'],
|
|
2513
|
+
JsdocTypeNotNullable: ['element'],
|
|
2514
|
+
JsdocTypeNull: [],
|
|
2515
|
+
JsdocTypeNullable: ['element'],
|
|
2516
|
+
JsdocTypeNumber: [],
|
|
2517
|
+
JsdocTypeObject: ['elements'],
|
|
2518
|
+
JsdocTypeObjectField: ['right'],
|
|
2519
|
+
JsdocTypeJsdocObjectField: ['left', 'right'],
|
|
2520
|
+
JsdocTypeOptional: ['element'],
|
|
2521
|
+
JsdocTypeParenthesis: ['element'],
|
|
2522
|
+
JsdocTypeSpecialNamePath: [],
|
|
2523
|
+
JsdocTypeStringValue: [],
|
|
2524
|
+
JsdocTypeSymbol: ['element'],
|
|
2525
|
+
JsdocTypeTuple: ['elements'],
|
|
2526
|
+
JsdocTypeTypeof: ['element'],
|
|
2527
|
+
JsdocTypeUndefined: [],
|
|
2528
|
+
JsdocTypeUnion: ['elements'],
|
|
2529
|
+
JsdocTypeUnknown: [],
|
|
2530
|
+
JsdocTypeVariadic: ['element'],
|
|
2531
|
+
JsdocTypeProperty: [],
|
|
2532
|
+
JsdocTypePredicate: ['left', 'right'],
|
|
2533
|
+
JsdocTypeAsserts: ['left', 'right']
|
|
2534
|
+
};
|
|
2535
|
+
|
|
2536
|
+
function _traverse(node, parentNode, property, onEnter, onLeave) {
|
|
2537
|
+
onEnter === null || onEnter === void 0 ? void 0 : onEnter(node, parentNode, property);
|
|
2538
|
+
const keysToVisit = visitorKeys[node.type];
|
|
2539
|
+
for (const key of keysToVisit) {
|
|
2540
|
+
const value = node[key];
|
|
2541
|
+
if (value !== undefined) {
|
|
2542
|
+
if (Array.isArray(value)) {
|
|
2543
|
+
for (const element of value) {
|
|
2544
|
+
_traverse(element, node, key, onEnter, onLeave);
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
else {
|
|
2548
|
+
_traverse(value, node, key, onEnter, onLeave);
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
onLeave === null || onLeave === void 0 ? void 0 : onLeave(node, parentNode, property);
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* A function to traverse an AST. It traverses it depth first.
|
|
2556
|
+
* @param node the node to start traversing at.
|
|
2557
|
+
* @param onEnter node visitor function that will be called on entering the node. This corresponds to preorder traversing.
|
|
2558
|
+
* @param onLeave node visitor function that will be called on leaving the node. This corresponds to postorder traversing.
|
|
2559
|
+
*/
|
|
2560
|
+
function traverse(node, onEnter, onLeave) {
|
|
2561
|
+
_traverse(node, undefined, undefined, onEnter, onLeave);
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
exports.catharsisTransform = catharsisTransform;
|
|
2565
|
+
exports.identityTransformRules = identityTransformRules;
|
|
2566
|
+
exports.jtpTransform = jtpTransform;
|
|
2567
|
+
exports.parse = parse;
|
|
2568
|
+
exports.stringify = stringify;
|
|
2569
|
+
exports.stringifyRules = stringifyRules;
|
|
2570
|
+
exports.transform = transform;
|
|
2571
|
+
exports.traverse = traverse;
|
|
2572
|
+
exports.tryParse = tryParse;
|
|
2573
|
+
exports.visitorKeys = visitorKeys;
|
|
2574
|
+
|
|
2575
|
+
}));
|
|
2576
|
+
} (dist$1, dist$1.exports));
|
|
2577
|
+
return dist$1.exports;
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
export { requireDist as r };
|