runtime-type-inspector 2.0.2 → 2.0.3

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.
Files changed (54) hide show
  1. package/build/rti-transpiler.cjs +2359 -0
  2. package/build/rti-transpiler.mjs +1979 -0
  3. package/package.json +4 -2
  4. package/.eslintrc.js +0 -480
  5. package/jsconfig.json +0 -10
  6. package/plugin-parcel/index.mjs +0 -4
  7. package/plugin-rollup/index.mjs +0 -78
  8. package/plugin-webpack/index.mjs +0 -4
  9. package/rollup.config.mjs +0 -183
  10. package/src-runtime/assertType.mjs +0 -54
  11. package/src-runtime/createDiv.mjs +0 -69
  12. package/src-runtime/index.mjs +0 -21
  13. package/src-runtime/makeJSDoc.mjs +0 -40
  14. package/src-runtime/registerClass.mjs +0 -11
  15. package/src-runtime/registerTypedef.mjs +0 -12
  16. package/src-runtime/typecheckDiv.mjs +0 -3
  17. package/src-runtime/typecheckEvery.mjs +0 -21
  18. package/src-runtime/typecheckOptions.mjs +0 -60
  19. package/src-runtime/typecheckTable.mjs +0 -14
  20. package/src-runtime/typecheckWarn.mjs +0 -23
  21. package/src-runtime/validateArray.mjs +0 -26
  22. package/src-runtime/validateDivision.mjs +0 -31
  23. package/src-runtime/validateMap.mjs +0 -37
  24. package/src-runtime/validateNumber.mjs +0 -29
  25. package/src-runtime/validateObject.mjs +0 -43
  26. package/src-runtime/validateRecord.mjs +0 -31
  27. package/src-runtime/validateSet.mjs +0 -26
  28. package/src-runtime/validateTuple.mjs +0 -28
  29. package/src-runtime/validateType.mjs +0 -214
  30. package/src-runtime/validateTypedef.mjs +0 -18
  31. package/src-runtime/validateUnion.mjs +0 -19
  32. package/src-runtime/youCanAddABreakpointHere.mjs +0 -11
  33. package/src-transpiler/Stringifier.mjs +0 -1275
  34. package/src-transpiler/StringifierWithTypeAssertions.mjs +0 -478
  35. package/src-transpiler/addTypeChecks.mjs +0 -20
  36. package/src-transpiler/ast2json.mjs +0 -13
  37. package/src-transpiler/ast2jsonForComparison.mjs +0 -28
  38. package/src-transpiler/code2ast2code.mjs +0 -16
  39. package/src-transpiler/expandType.mjs +0 -187
  40. package/src-transpiler/expandTypeDepFree.mjs +0 -122
  41. package/src-transpiler/extractNameAndOptionality.mjs +0 -23
  42. package/src-transpiler/index.mjs +0 -13
  43. package/src-transpiler/parseJSDoc.mjs +0 -69
  44. package/src-transpiler/parseJSDocSetter.mjs +0 -16
  45. package/src-transpiler/parseJSDocTypedef.mjs +0 -69
  46. package/src-transpiler/simplifyType.mjs +0 -31
  47. package/src-transpiler/stat.mjs +0 -13
  48. package/ui/babel-core.mjs +0 -5
  49. package/ui/babel-helper-plugin-utils.mjs +0 -7
  50. package/ui/babel-parser.mjs +0 -8
  51. package/ui/babel-plugin-syntax-typescript.mjs +0 -58
  52. package/ui/importmap.js +0 -38
  53. package/ui/index.html +0 -30
  54. package/ui/index.mjs +0 -379
@@ -0,0 +1,1979 @@
1
+ import { parse } from '@babel/parser';
2
+ import ts from 'typescript';
3
+
4
+ function expandTypeDepFree(type) {
5
+ type = type.trim();
6
+ while (!type.includes('|') && type[0] == '(' && type[type.length - 1] == ')') {
7
+ type = type.slice(1, -1).trim();
8
+ }
9
+ if (type[0] === '.' && type[1] === '.' && type[2] === '.') {
10
+ return {
11
+ type: 'array',
12
+ elementType: type.slice(3)
13
+ };
14
+ }
15
+ if (type.startsWith("Array<") && type.endsWith('>')) {
16
+ const typeSlice = type.slice(6, -1);
17
+ return {
18
+ type: "array",
19
+ elementType: expandTypeDepFree(typeSlice)
20
+ };
21
+ }
22
+ if ((type.startsWith("Object<") || type.startsWith("Record<")) && type.endsWith('>')) {
23
+ const recordSlice = type.slice(7, -1);
24
+ const firstComma = recordSlice.indexOf(',');
25
+ if (firstComma === -1) {
26
+ console.warn("expandTypeDepFree> invalid Object/Record");
27
+ }
28
+ const key = recordSlice.slice(0, firstComma).trim();
29
+ const val = recordSlice.slice(firstComma + 1).trim();
30
+ return {
31
+ type: "record",
32
+ key: expandTypeDepFree(key),
33
+ val: expandTypeDepFree(val)
34
+ };
35
+ }
36
+ if (type[0] == '{' && type[type.length - 1] == '}') {
37
+ const propertiesArray = type.slice(1, -1).split(',');
38
+ const properties = {};
39
+ propertiesArray.forEach(_ => {
40
+ const [propName, propType] = _.split(":").map(_ => _.trim());
41
+ if (!propName || !propType) {
42
+ console.warn('expandTypeDepFree> unexpected type format, fix');
43
+ return false;
44
+ }
45
+ properties[propName] = propType;
46
+ });
47
+ return {
48
+ type: 'object',
49
+ properties
50
+ };
51
+ }
52
+ const members = type.split("|");
53
+ if (members.length >= 2) {
54
+ members.forEach((_, i) => members[i] = _.trim());
55
+ return {
56
+ type: 'union',
57
+ members: members.map(expandTypeDepFree)
58
+ };
59
+ }
60
+ if (type.endsWith("[]")) {
61
+ const typeSlice = type.slice(0, -2);
62
+ return {
63
+ type: 'array',
64
+ elementType: expandTypeDepFree(typeSlice)
65
+ };
66
+ }
67
+ if (type[0] == '[' && type[type.length - 1] == ']') {
68
+ const elements = type.slice(1, -1).split(',');
69
+ return {
70
+ type: 'tuple',
71
+ elements: elements.map(expandTypeDepFree)
72
+ };
73
+ }
74
+ if (type === 'object' || type === 'Object') {
75
+ return {
76
+ type: 'object',
77
+ properties: {}
78
+ };
79
+ }
80
+ return type;
81
+ }
82
+
83
+ function simplifyType(type, optional) {
84
+ if (type instanceof Object) {
85
+ type.optional = optional;
86
+ } else if (typeof type === 'string') {
87
+ type = type.trim();
88
+ if (type != 'object' && type != 'object[]' && type != 'union' && !optional) {
89
+ return type;
90
+ }
91
+ type = {
92
+ type,
93
+ optional
94
+ };
95
+ } else {
96
+ debugger;
97
+ console.warn("simplifyType> neither object nor string for type", type);
98
+ }
99
+ if (type.type == 'object' && type.properties && Object.keys(type.properties).length === 0) {
100
+ delete type.properties;
101
+ }
102
+ return type;
103
+ }
104
+
105
+ function parseJSDoc(src, expandType = expandTypeDepFree) {
106
+ const regex = /@param \{(.*?)\} ([\[\]a-zA-Z0-9_$=\{\}\.'" ]+)/g;
107
+ const matches = [...src.matchAll(regex)];
108
+ const params = Object.create(null);
109
+ matches.forEach(_ => {
110
+ const type = expandType(_[1].trim());
111
+ let name = _[2].trim();
112
+ let optional = false;
113
+ if (name[0] === '[') {
114
+ const closer = name.lastIndexOf(']');
115
+ name = name.substring(1, closer);
116
+ optional = true;
117
+ }
118
+ name = name.split(' ')[0].split('=')[0].trim();
119
+ const simplifiedType = simplifyType(type, optional);
120
+ const parts = name.split(".");
121
+ if (parts.length == 3) {
122
+ let parts0 = parts[0];
123
+ let parts1 = parts[1];
124
+ let parts2 = parts[2];
125
+ const toptype = params[parts0];
126
+ toptype.properties[parts1].properties = toptype.properties[parts1].properties || {};
127
+ toptype.properties[parts1].properties[parts2] = simplifiedType;
128
+ } else if (parts.length == 2) {
129
+ let parts0 = parts[0];
130
+ let parts1 = parts[1];
131
+ if (parts0.endsWith('[]')) {
132
+ parts0 = parts0.slice(0, -2);
133
+ }
134
+ const toptype = params[parts0];
135
+ if ((toptype == null ? void 0 : toptype.type) == "union") {
136
+ const typeObject = toptype.members.find(_ => (_ == null ? void 0 : _.type) == 'object');
137
+ typeObject.properties[parts1] = simplifiedType;
138
+ } else if ((toptype == null ? void 0 : toptype.type) == "array") {
139
+ toptype.elementType.properties[parts1] = simplifiedType;
140
+ } else if ((toptype == null ? void 0 : toptype.type) == "object") {
141
+ toptype.properties = toptype.properties || {};
142
+ toptype.properties[parts1] = simplifiedType;
143
+ } else {
144
+ console.warn("parseJSDoc> skipping @param, unseen syntax detected, please check if your JSDoc is valid or open an issue about this", {
145
+ src,
146
+ toptype,
147
+ parts0,
148
+ parts1,
149
+ simplifiedType
150
+ });
151
+ }
152
+ } else {
153
+ params[name] = simplifiedType;
154
+ }
155
+ });
156
+ if (Object.keys(params).length === 0) {
157
+ return;
158
+ }
159
+ return params;
160
+ }
161
+
162
+ function parseJSDocSetter(src, expandType = expandTypeDepFree) {
163
+ const regex = /@type \{(.*?)\}/g;
164
+ const matches = [...src.matchAll(regex)];
165
+ if (matches.length === 1) {
166
+ const match = matches[0];
167
+ const type = expandType(match[1]);
168
+ const simplifiedType = simplifyType(type, false);
169
+ return simplifiedType;
170
+ }
171
+ }
172
+
173
+ function extractNameAndOptionality(rest) {
174
+ rest = rest.trim();
175
+ let optional = false;
176
+ if (rest[0] === '[') {
177
+ const closer = rest.lastIndexOf(']');
178
+ rest = rest.substring(1, closer);
179
+ optional = true;
180
+ }
181
+ const name = rest.split(' ')[0].split('=')[0].trim();
182
+ return [name, optional];
183
+ }
184
+
185
+ function extractCurlyContent(line) {
186
+ const firstCurly = line.indexOf('{');
187
+ let k = firstCurly + 1;
188
+ let count = 0;
189
+ for (; k < line.length; k++) {
190
+ const c = line[k];
191
+ if (c === '{') {
192
+ count++;
193
+ } else if (c === '}') {
194
+ count--;
195
+ }
196
+ if (count === -1) {
197
+ break;
198
+ }
199
+ }
200
+ const content = line.substring(firstCurly + 1, k);
201
+ return {
202
+ content,
203
+ nextIndex: k + 1
204
+ };
205
+ }
206
+ function parseJSDocTypedef(typedefs, warn, comment, expandType) {
207
+ const {
208
+ type,
209
+ value
210
+ } = comment;
211
+ if (type !== 'CommentBlock') {
212
+ return;
213
+ }
214
+ const lines = value.split('\n');
215
+ let lastTypedef = undefined;
216
+ for (let line of lines) {
217
+ line = line.trim();
218
+ if (line[0] === '*') {
219
+ line = line.slice(1).trim();
220
+ }
221
+ if (line.startsWith('@typedef')) {
222
+ const {
223
+ content: def,
224
+ nextIndex
225
+ } = extractCurlyContent(line);
226
+ let name = line.substring(nextIndex).trim();
227
+ name = name.split(' ')[0];
228
+ lastTypedef = expandType(def);
229
+ typedefs[name] = lastTypedef;
230
+ } else if (line.startsWith('@property')) {
231
+ var _lastTypedef;
232
+ if (!lastTypedef) {
233
+ continue;
234
+ }
235
+ const {
236
+ content,
237
+ nextIndex
238
+ } = extractCurlyContent(line);
239
+ const rest = line.substring(nextIndex);
240
+ const propType = expandType(content);
241
+ const [name, optional] = extractNameAndOptionality(rest);
242
+ const finalType = simplifyType(propType, optional);
243
+ if (((_lastTypedef = lastTypedef) == null ? void 0 : _lastTypedef.type) === 'object') {
244
+ lastTypedef.properties[name] = finalType;
245
+ } else {
246
+ warn("not an extensible type", lastTypedef);
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ function statReset(stat) {
253
+ stat.checked = 0;
254
+ stat.unchecked = 0;
255
+ }
256
+
257
+ class Stringifier {
258
+ constructor() {
259
+ this.forceCurly = false;
260
+ this.parents = [];
261
+ }
262
+ toSource(node) {
263
+ var _node$extra;
264
+ if (node === null) {
265
+ return '';
266
+ }
267
+ if (node.type === 'File') {
268
+ this.parents.length = 0;
269
+ }
270
+ this.parents.push(node);
271
+ let out = '';
272
+ let comments = '';
273
+ if (node && node.leadingComments) {
274
+ comments += this.mapToSource(node.leadingComments).join('');
275
+ }
276
+ if (node != null && (_node$extra = node.extra) != null && _node$extra.parenthesized) {
277
+ out += `(${comments}${this.toSource_(node)})`;
278
+ } else {
279
+ out += comments + this.toSource_(node);
280
+ }
281
+ this.parents.pop();
282
+ return out;
283
+ }
284
+ toSource_(node) {
285
+ if (!node) {
286
+ return '';
287
+ }
288
+ const {
289
+ type
290
+ } = node;
291
+ if (type === undefined) {
292
+ console.log("toSource> node without type", node);
293
+ }
294
+ if (this[type]) {
295
+ return this[type](node);
296
+ }
297
+ console.log(node);
298
+ const notOfInterest = ["start", "end", "loc", "type"];
299
+ const ofInterest = Object.keys(node).filter(_ => !notOfInterest.includes(_));
300
+ const props = ofInterest.join(', ');
301
+ const fn = `${type}(node) {\n const {${props}} = node;\n return ;\n}`;
302
+ console.warn('TODO ADD METHOD:', fn);
303
+ return `rtiUnhandled("${node.type}");\n`;
304
+ }
305
+ toSourceCurly(node) {
306
+ if (!this.forceCurly) {
307
+ return this.toSource(node);
308
+ }
309
+ const {
310
+ type
311
+ } = node;
312
+ const needCurly = type != 'BlockStatement' && type != 'EmptyStatement';
313
+ const spaces = this.spaces;
314
+ let out = '';
315
+ if (needCurly) {
316
+ out += ' {\n';
317
+ }
318
+ out += this.toSource(node);
319
+ if (needCurly) {
320
+ out += '\n';
321
+ out += spaces;
322
+ out += '}';
323
+ }
324
+ return out;
325
+ }
326
+ get parent() {
327
+ return this.parents[this.parents.length - 2];
328
+ }
329
+ get parentType() {
330
+ var _this$parent;
331
+ return (_this$parent = this.parent) == null ? void 0 : _this$parent.type;
332
+ }
333
+ get needSpaces() {
334
+ const t = this.parentType;
335
+ return t != "ForStatement" && t != "ForInStatement" && t != "ForOfStatement";
336
+ }
337
+ mapToSource(arr) {
338
+ return arr.map(_ => this.toSource(_));
339
+ }
340
+ generateTypeChecks(node) {
341
+ const {
342
+ spaces
343
+ } = this;
344
+ return `${spaces}/* Stub of Stringifier#generateTypeChecks({type=${node.type}}); */\n`;
345
+ }
346
+ get spaces() {
347
+ var _parents$, _parents$2;
348
+ const {
349
+ parents
350
+ } = this;
351
+ let n = parents.length;
352
+ if (((_parents$ = parents[0]) == null ? void 0 : _parents$.type) == 'File') {
353
+ n--;
354
+ }
355
+ if (((_parents$2 = parents[1]) == null ? void 0 : _parents$2.type) == 'Program') {
356
+ n--;
357
+ }
358
+ n -= parents.filter(_ => _.type === 'BlockStatement' || _.type === 'VariableDeclarator' || _.type === 'ObjectProperty' || _.type === 'ExportNamedDeclaration' || _.type === 'NewExpression' || _.type === 'AssignmentExpression' || _.type === 'ArrayExpression' || _.type === 'ClassBody').length;
359
+ n -= 1;
360
+ if (parents.some(_ => _.type === 'CallExpression') && parents.some(_ => _.type === 'ObjectExpression')) {
361
+ n--;
362
+ }
363
+ if (n < 0) {
364
+ n = 0;
365
+ }
366
+ return ' '.repeat(n);
367
+ }
368
+ AwaitExpression(node) {
369
+ const {
370
+ argument
371
+ } = node;
372
+ return `await ${this.toSource(argument)}`;
373
+ }
374
+ ClassProperty(node) {
375
+ const {
376
+ key,
377
+ computed,
378
+ value,
379
+ leadingComments
380
+ } = node;
381
+ const static_ = node.static;
382
+ const a = this.toSource(key);
383
+ const b = this.toSource(value);
384
+ let out = this.spaces;
385
+ if (static_) {
386
+ out += 'static ';
387
+ }
388
+ if (computed) {
389
+ out += `[${a}]`;
390
+ } else {
391
+ out += a;
392
+ }
393
+ if (b) {
394
+ out += ` = ${b}`;
395
+ }
396
+ out += ';';
397
+ return out;
398
+ }
399
+ FunctionDeclarationParams(params) {
400
+ return '(' + this.mapToSource(params).join(', ') + ')';
401
+ }
402
+ FunctionDeclaration(node) {
403
+ const {
404
+ async,
405
+ body,
406
+ generator,
407
+ id,
408
+ leadingComments,
409
+ params
410
+ } = node;
411
+ let out = '';
412
+ if (this.parentType !== 'ExportNamedDeclaration') {
413
+ out += this.spaces;
414
+ }
415
+ if (async) {
416
+ out += 'async ';
417
+ }
418
+ const asterix = generator ? '*' : '';
419
+ out += 'function' + asterix + ' ' + this.toSource(id) + this.FunctionDeclarationParams(params);
420
+ out += this.toSource(body);
421
+ return out;
422
+ }
423
+ FunctionExpression(node) {
424
+ const {
425
+ async,
426
+ body,
427
+ generator,
428
+ id,
429
+ params
430
+ } = node;
431
+ let out = '';
432
+ if (async) {
433
+ out += 'async ';
434
+ }
435
+ const star = generator ? '*' : '';
436
+ out += 'function' + star + ' ' + this.toSource(id) + this.FunctionDeclarationParams(params);
437
+ out += this.toSource(body);
438
+ return out;
439
+ }
440
+ ArrowFunctionExpression(node) {
441
+ const {
442
+ async,
443
+ body,
444
+ generator,
445
+ params
446
+ } = node;
447
+ let out = '';
448
+ if (async) {
449
+ out += 'async ';
450
+ }
451
+ if (generator) {
452
+ out += ' * ';
453
+ }
454
+ out += this.FunctionDeclarationParams(params);
455
+ out += ' => ';
456
+ out += this.toSource(body);
457
+ return out;
458
+ }
459
+ BigIntLiteral(node) {
460
+ const {
461
+ extra,
462
+ value
463
+ } = node;
464
+ return extra.raw;
465
+ }
466
+ BlockStatement(node) {
467
+ const {
468
+ body,
469
+ directives
470
+ } = node;
471
+ const spaces = this.spaces;
472
+ let out = '';
473
+ out += ' {\n';
474
+ if (directives && directives.length) {
475
+ out += this.mapToSource(directives).join('\n') + '\n';
476
+ }
477
+ out += this.generateTypeChecks(node);
478
+ out += this.mapToSource(body).join('\n') + '\n';
479
+ out += spaces;
480
+ out += '}';
481
+ return out;
482
+ }
483
+ ClassExpression(node) {
484
+ const {
485
+ id,
486
+ superClass,
487
+ body
488
+ } = node;
489
+ let out = 'class ';
490
+ if (id !== null) {
491
+ out += this.toSource(id) + ' ';
492
+ }
493
+ if (superClass !== null) {
494
+ const s = this.toSource(superClass);
495
+ out += `extends ${s} `;
496
+ }
497
+ const c = this.toSource(body);
498
+ out += `{\n${c}\n}`;
499
+ return out;
500
+ }
501
+ Directive(node) {
502
+ const {
503
+ value
504
+ } = node;
505
+ return this.toSource(value);
506
+ }
507
+ DirectiveLiteral(node) {
508
+ const {
509
+ extra,
510
+ value
511
+ } = node;
512
+ const {
513
+ spaces
514
+ } = this;
515
+ return `${spaces}${extra.raw};`;
516
+ }
517
+ ReturnStatement(node) {
518
+ const {
519
+ argument
520
+ } = node;
521
+ const {
522
+ spaces
523
+ } = this;
524
+ if (!argument) {
525
+ return spaces + 'return;';
526
+ }
527
+ return spaces + 'return ' + this.toSource(argument) + ';';
528
+ }
529
+ Identifier(node) {
530
+ return node.name;
531
+ }
532
+ IfStatement(node) {
533
+ const {
534
+ alternate,
535
+ consequent,
536
+ test
537
+ } = node;
538
+ const spaces = this.spaces;
539
+ let out = '';
540
+ {
541
+ out += spaces;
542
+ }
543
+ out += `if (${this.toSource(test)})`;
544
+ out += this.toSourceCurly(consequent);
545
+ if (alternate) {
546
+ out += ` else${this.toSourceCurly(alternate)}`;
547
+ }
548
+ return out;
549
+ }
550
+ LabeledStatement(node) {
551
+ const {
552
+ body,
553
+ label
554
+ } = node;
555
+ const {
556
+ spaces
557
+ } = this;
558
+ let out = '';
559
+ out += spaces + this.toSource(label);
560
+ out += ': \n';
561
+ out += spaces + this.toSource(body);
562
+ return out;
563
+ }
564
+ UnaryExpression(node) {
565
+ let out = '';
566
+ const {
567
+ argument,
568
+ operator,
569
+ prefix
570
+ } = node;
571
+ if (!prefix) {
572
+ console.warn("Stringifier#UnaryExpression> never considered !prefix", node);
573
+ }
574
+ const c = operator.charCodeAt(0);
575
+ let op = operator;
576
+ if (c >= 97 && c <= 122) {
577
+ op += ' ';
578
+ }
579
+ out += op;
580
+ out += this.toSource(argument);
581
+ return out;
582
+ }
583
+ MemberExpression(node) {
584
+ const {
585
+ computed,
586
+ object,
587
+ property
588
+ } = node;
589
+ if (computed) {
590
+ return `${this.toSource(object)}[${this.toSource(property)}]`;
591
+ }
592
+ return `${this.toSource(object)}.${this.toSource(property)}`;
593
+ }
594
+ MetaProperty(node) {
595
+ const {
596
+ meta,
597
+ property
598
+ } = node;
599
+ const lhs = this.toSource(meta);
600
+ const rhs = this.toSource(property);
601
+ return `${lhs}.${rhs}`;
602
+ }
603
+ ExpressionStatement(node) {
604
+ const {
605
+ expression
606
+ } = node;
607
+ return this.spaces + this.toSource(expression) + ';';
608
+ }
609
+ CallExpression(node) {
610
+ const {
611
+ callee,
612
+ arguments: args,
613
+ extra
614
+ } = node;
615
+ let out = this.toSource(callee);
616
+ out += "(";
617
+ out += this.mapToSource(args).join(', ');
618
+ if (!!(extra != null && extra.trailingComma)) {
619
+ out += ',';
620
+ }
621
+ out += ")";
622
+ return out;
623
+ }
624
+ ObjectExpression(node) {
625
+ const {
626
+ properties,
627
+ extra
628
+ } = node;
629
+ let out = '{';
630
+ if (properties.length) {
631
+ const props = this.mapToSource(properties).join(',\n');
632
+ out += '\n';
633
+ out += props;
634
+ if (extra != null && extra.trailingComma) {
635
+ out += ',';
636
+ }
637
+ out += '\n';
638
+ out += this.spaces.slice(2);
639
+ }
640
+ out += '}';
641
+ return out;
642
+ }
643
+ ObjectProperty(node) {
644
+ const {
645
+ computed,
646
+ key,
647
+ method,
648
+ shorthand,
649
+ value
650
+ } = node;
651
+ if (method) {
652
+ console.warn("ObjectProperty> unhandled method property:", {
653
+ method,
654
+ shorthand
655
+ });
656
+ }
657
+ const spaces = this.spaces;
658
+ let left = this.toSource(key);
659
+ const right = this.toSource(value);
660
+ let out = spaces;
661
+ if (computed) {
662
+ left = `[${left}]`;
663
+ }
664
+ if (!shorthand) {
665
+ out += left + ': ';
666
+ }
667
+ out += right;
668
+ return out;
669
+ }
670
+ BooleanLiteral(node) {
671
+ return node.value.toString();
672
+ }
673
+ AssignmentExpression(node) {
674
+ const {
675
+ left,
676
+ operator,
677
+ right
678
+ } = node;
679
+ const left_ = this.toSource(left);
680
+ const right_ = this.toSource(right);
681
+ return `${left_} ${operator} ${right_}`;
682
+ }
683
+ BinaryExpression(node) {
684
+ const {
685
+ left,
686
+ operator,
687
+ right
688
+ } = node;
689
+ const left_ = this.toSource(left);
690
+ const right_ = this.toSource(right);
691
+ return `${left_} ${operator} ${right_}`;
692
+ }
693
+ ThisExpression(node) {
694
+ return 'this';
695
+ }
696
+ ArrayExpression(node) {
697
+ const {
698
+ elements,
699
+ extra
700
+ } = node;
701
+ const e = !!(extra != null && extra.trailingComma) ? ',' : '';
702
+ return '[' + this.mapToSource(elements).join(', ') + e + ']';
703
+ }
704
+ VariableDeclaration(node) {
705
+ const {
706
+ declarations,
707
+ kind
708
+ } = node;
709
+ let spaces = '';
710
+ let semicolon = '';
711
+ if (this.needSpaces) {
712
+ semicolon = ';';
713
+ spaces = this.spaces;
714
+ }
715
+ return `${spaces}${kind} ${this.mapToSource(declarations).join(', ')}${semicolon}`;
716
+ }
717
+ VariableDeclarator(node) {
718
+ const {
719
+ id,
720
+ init
721
+ } = node;
722
+ if (init) {
723
+ return this.toSource(id) + ' = ' + this.toSource(init);
724
+ }
725
+ return this.toSource(id);
726
+ }
727
+ ConditionalExpression(node) {
728
+ const {
729
+ alternate,
730
+ consequent,
731
+ test
732
+ } = node;
733
+ return `${this.toSource(test)} ? ${this.toSource(consequent)} : ${this.toSource(alternate)}`;
734
+ }
735
+ LogicalExpression(node) {
736
+ const {
737
+ left,
738
+ operator,
739
+ right
740
+ } = node;
741
+ const l = this.toSource(left);
742
+ const r = this.toSource(right);
743
+ if (l === '') {
744
+ console.warn("LogicalExpression> unhandled empty left", node);
745
+ }
746
+ if (r === '') {
747
+ console.warn("LogicalExpression> unhandled empty right", node);
748
+ }
749
+ return `${l} ${operator} ${r}`;
750
+ }
751
+ ForStatement(node) {
752
+ const {
753
+ init,
754
+ test,
755
+ update,
756
+ body
757
+ } = node;
758
+ const spaces = this.spaces;
759
+ const i = this.toSource(init);
760
+ const t = this.toSource(test);
761
+ const u = this.toSource(update);
762
+ const b = this.toSourceCurly(body);
763
+ return `${spaces}for (${i}; ${t}; ${u})${b}`;
764
+ }
765
+ UpdateExpression(node) {
766
+ const {
767
+ operator,
768
+ prefix,
769
+ argument
770
+ } = node;
771
+ if (prefix) {
772
+ return `${operator}${this.toSource(argument)}`;
773
+ } else {
774
+ return `${this.toSource(argument)}${operator}`;
775
+ }
776
+ }
777
+ NewExpression(node) {
778
+ const {
779
+ callee,
780
+ arguments: args_
781
+ } = node;
782
+ const c = this.toSource(callee);
783
+ const args = this.mapToSource(args_).join(', ');
784
+ return `new ${c}(${args})`;
785
+ }
786
+ ClassDeclaration(node) {
787
+ const {
788
+ id,
789
+ superClass,
790
+ body,
791
+ trailingComments,
792
+ leadingComments
793
+ } = node;
794
+ const spaces = this.spaces;
795
+ let out = spaces + 'class ' + this.toSource(id);
796
+ if (superClass) {
797
+ out += ` extends ${this.toSource(superClass)}`;
798
+ }
799
+ out += ' {\n';
800
+ out += this.toSource(body);
801
+ out += spaces;
802
+ out += '\n}\n';
803
+ return out;
804
+ }
805
+ TemplateLiteral(node) {
806
+ const {
807
+ expressions,
808
+ quasis
809
+ } = node;
810
+ let out = '`';
811
+ for (var i = 0; i < quasis.length; i++) {
812
+ out += this.toSource(quasis[i]);
813
+ if (expressions[i]) {
814
+ out += '${' + this.toSource(expressions[i]) + '}';
815
+ }
816
+ }
817
+ out += '`';
818
+ return out;
819
+ }
820
+ TemplateElement(node) {
821
+ const {
822
+ value
823
+ } = node;
824
+ return value.raw;
825
+ }
826
+ ContinueStatement(node) {
827
+ const {
828
+ label
829
+ } = node;
830
+ let out = this.spaces + 'continue';
831
+ if (label) {
832
+ out += ' ' + this.toSource(label);
833
+ }
834
+ out += ';';
835
+ return out;
836
+ }
837
+ ClassBody(node) {
838
+ const {
839
+ body
840
+ } = node;
841
+ return this.mapToSource(body).join('\n');
842
+ }
843
+ ClassMethod(node) {
844
+ const {
845
+ static: static_,
846
+ key,
847
+ computed,
848
+ kind,
849
+ id,
850
+ generator,
851
+ async,
852
+ params,
853
+ body
854
+ } = node;
855
+ let out = this.spaces;
856
+ if (generator) {
857
+ out += '*';
858
+ }
859
+ if (id) {
860
+ console.warn('Stringifier#ClassMethod> unhandled id', node);
861
+ }
862
+ if (static_) {
863
+ out += 'static ';
864
+ }
865
+ if (async) {
866
+ out += 'async ';
867
+ }
868
+ if (kind === 'get') {
869
+ out += 'get ';
870
+ } else if (kind === 'set') {
871
+ out += 'set ';
872
+ } else if (kind === 'constructor' || kind === 'method') ; else {
873
+ console.warn("unhandled kind", kind, "for", node);
874
+ }
875
+ let methodName = this.toSource(key);
876
+ if (computed) {
877
+ methodName = `[${methodName}]`;
878
+ }
879
+ out += methodName;
880
+ out += `(${this.mapToSource(params).join(', ')})`;
881
+ out += this.toSource(body);
882
+ return out;
883
+ }
884
+ ExportAllDeclaration(node) {
885
+ return `export * from ${node.source.extra.raw};`;
886
+ }
887
+ ExportNamedDeclaration(node) {
888
+ const {
889
+ declaration,
890
+ source,
891
+ specifiers
892
+ } = node;
893
+ let out = this.spaces;
894
+ if (specifiers.length) {
895
+ out += 'export {\n';
896
+ out += this.mapToSource(specifiers).map(_ => ` ${this.spaces}${_}`).join(',\n');
897
+ out += '\n';
898
+ out += this.spaces;
899
+ out += '}';
900
+ if (source) {
901
+ out += " from " + this.toSource(source);
902
+ }
903
+ out += ";\n";
904
+ } else if (declaration) {
905
+ out += 'export ' + this.toSource(declaration);
906
+ } else {
907
+ console.warn("ExportNamedDeclaration> unhandled case for", node);
908
+ }
909
+ return out;
910
+ }
911
+ ExportDefaultDeclaration(node) {
912
+ const {
913
+ declaration
914
+ } = node;
915
+ const a = this.toSource(declaration);
916
+ return `export default ${a};`;
917
+ }
918
+ ExportSpecifier(node) {
919
+ const {
920
+ exported,
921
+ local
922
+ } = node;
923
+ const left = this.toSource(exported);
924
+ const right = this.toSource(local);
925
+ const {
926
+ spaces
927
+ } = this;
928
+ if (left === right) {
929
+ return `${spaces}${left}`;
930
+ }
931
+ return `${spaces}${right} as ${left}`;
932
+ }
933
+ Super(node) {
934
+ return 'super';
935
+ }
936
+ ForInStatement(node) {
937
+ const {
938
+ left,
939
+ right,
940
+ body
941
+ } = node;
942
+ const {
943
+ spaces
944
+ } = this;
945
+ const l = this.toSource(left);
946
+ const r = this.toSource(right);
947
+ const b = this.toSourceCurly(body);
948
+ return `${spaces}for (${l} in ${r})${b}`;
949
+ }
950
+ ThrowStatement(node) {
951
+ const {
952
+ argument
953
+ } = node;
954
+ const {
955
+ spaces
956
+ } = this;
957
+ const arg = this.toSource(argument);
958
+ return `${spaces}throw ${arg};`;
959
+ }
960
+ WhileStatement(node) {
961
+ const {
962
+ test,
963
+ body
964
+ } = node;
965
+ const {
966
+ spaces
967
+ } = this;
968
+ const t = this.toSource(test);
969
+ const b = this.toSourceCurly(body);
970
+ return `${spaces}while (${t})${b}`;
971
+ }
972
+ BreakStatement(node) {
973
+ const {
974
+ label
975
+ } = node;
976
+ let out = this.spaces + 'break';
977
+ if (label) {
978
+ out += ' ' + this.toSource(label);
979
+ }
980
+ out += ';';
981
+ return out;
982
+ }
983
+ ForOfStatement(node) {
984
+ const {
985
+ await: await_,
986
+ left,
987
+ right,
988
+ body
989
+ } = node;
990
+ const {
991
+ spaces
992
+ } = this;
993
+ const l = this.toSource(left);
994
+ const r = this.toSource(right);
995
+ const b = this.toSourceCurly(body);
996
+ const a = await_ ? 'await ' : '';
997
+ return `${spaces}for ${a}(${l} of ${r})${b}`;
998
+ }
999
+ ArrayPattern(node) {
1000
+ const {
1001
+ elements
1002
+ } = node;
1003
+ const e = this.mapToSource(elements).join(', ');
1004
+ return `[${e}]`;
1005
+ }
1006
+ SwitchStatement(node) {
1007
+ const {
1008
+ discriminant,
1009
+ cases
1010
+ } = node;
1011
+ const {
1012
+ spaces
1013
+ } = this;
1014
+ let out = '';
1015
+ out += spaces + `switch (${this.toSource(discriminant)}) {\n`;
1016
+ out += this.mapToSource(cases).join('\n') + '\n';
1017
+ out += spaces + '}';
1018
+ return out;
1019
+ }
1020
+ SwitchCase(node) {
1021
+ const {
1022
+ consequent,
1023
+ test
1024
+ } = node;
1025
+ const {
1026
+ spaces
1027
+ } = this;
1028
+ const c = this.mapToSource(consequent).join('\n');
1029
+ if (test) {
1030
+ const t = this.toSource(test);
1031
+ return `${spaces}case ${t}:\n${c}`;
1032
+ }
1033
+ return `${spaces}default:\n${c}`;
1034
+ }
1035
+ RegExpLiteral(node) {
1036
+ const {
1037
+ extra,
1038
+ value,
1039
+ pattern,
1040
+ flags
1041
+ } = node;
1042
+ return extra.raw;
1043
+ }
1044
+ SequenceExpression(node) {
1045
+ const {
1046
+ expressions
1047
+ } = node;
1048
+ return this.mapToSource(expressions).join(', ');
1049
+ }
1050
+ EmptyStatement(node) {
1051
+ return ';';
1052
+ }
1053
+ SpreadElement(node) {
1054
+ const {
1055
+ argument
1056
+ } = node;
1057
+ const a = this.toSource(argument);
1058
+ return `...${a}`;
1059
+ }
1060
+ ObjectMethod(node) {
1061
+ const {
1062
+ method,
1063
+ key,
1064
+ computed,
1065
+ kind,
1066
+ id,
1067
+ generator,
1068
+ async,
1069
+ params,
1070
+ body
1071
+ } = node;
1072
+ if (id !== null) {
1073
+ console.warn("ObjectMethod> id !== null is unhandled", node);
1074
+ debugger;
1075
+ }
1076
+ let out = this.spaces;
1077
+ if (generator) {
1078
+ out += '*';
1079
+ }
1080
+ if (id) {
1081
+ console.warn('Stringifier#ClassMethod> unhandled id', node);
1082
+ }
1083
+ if (async) {
1084
+ out += 'async ';
1085
+ }
1086
+ if (kind === 'get') {
1087
+ out += 'get ';
1088
+ } else if (kind === 'set') {
1089
+ out += 'set ';
1090
+ } else if (kind === 'method') ; else {
1091
+ console.warn("unhandled kind", kind, "for", node);
1092
+ }
1093
+ let methodName = this.toSource(key);
1094
+ if (computed) {
1095
+ methodName = `[${methodName}]`;
1096
+ }
1097
+ out += methodName;
1098
+ out += `(${this.mapToSource(params).join(', ')})`;
1099
+ out += this.toSource(body);
1100
+ return out;
1101
+ }
1102
+ ObjectPattern(node) {
1103
+ const {
1104
+ properties,
1105
+ extra
1106
+ } = node;
1107
+ let out = '{';
1108
+ if (properties.length) {
1109
+ out += '\n';
1110
+ out += this.mapToSource(properties).join(',\n');
1111
+ if (!!(extra != null && extra.trailingComma)) {
1112
+ out += ',';
1113
+ }
1114
+ out += '\n';
1115
+ out += this.spaces.slice(2);
1116
+ }
1117
+ out += '}';
1118
+ return out;
1119
+ }
1120
+ OptionalMemberExpression(node) {
1121
+ const {
1122
+ object,
1123
+ computed,
1124
+ property,
1125
+ optional
1126
+ } = node;
1127
+ const a = this.toSource(object);
1128
+ const b = this.toSource(property);
1129
+ if (!computed && !optional) {
1130
+ return `${a}.${b}`;
1131
+ } else if (!computed && optional) {
1132
+ return `${a}?.${b}`;
1133
+ } else if (computed && !optional) {
1134
+ return `${a}[${b}]`;
1135
+ }
1136
+ return `${a}?.[${b}]`;
1137
+ }
1138
+ OptionalCallExpression(node) {
1139
+ const {
1140
+ callee,
1141
+ optional,
1142
+ arguments: args
1143
+ } = node;
1144
+ const a = this.toSource(callee);
1145
+ const b = this.mapToSource(args);
1146
+ if (optional) {
1147
+ return `${a}?.(${b})`;
1148
+ }
1149
+ return `${a}(${b})`;
1150
+ }
1151
+ DoWhileStatement(node) {
1152
+ const {
1153
+ body,
1154
+ test,
1155
+ trailingComments
1156
+ } = node;
1157
+ const {
1158
+ spaces
1159
+ } = this;
1160
+ let out = spaces;
1161
+ out += "do ";
1162
+ out += this.toSourceCurly(body);
1163
+ out += ` while (${this.toSource(test)});`;
1164
+ return out;
1165
+ }
1166
+ TryStatement(node) {
1167
+ const {
1168
+ block,
1169
+ handler,
1170
+ finalizer
1171
+ } = node;
1172
+ let out = this.spaces;
1173
+ const b = this.toSource(block);
1174
+ out += `try ${b}`;
1175
+ if (handler) {
1176
+ out += this.toSource(handler);
1177
+ }
1178
+ if (finalizer) {
1179
+ out += 'finally' + this.toSource(finalizer);
1180
+ }
1181
+ return out;
1182
+ }
1183
+ CatchClause(node) {
1184
+ const {
1185
+ param,
1186
+ body
1187
+ } = node;
1188
+ const b = this.toSource(body);
1189
+ if (param) {
1190
+ const p = this.toSource(param);
1191
+ return ` catch (${p}) ${b}`;
1192
+ }
1193
+ return ` catch ${b}`;
1194
+ }
1195
+ RestElement(node) {
1196
+ const {
1197
+ argument
1198
+ } = node;
1199
+ return `...${this.toSource(argument)}`;
1200
+ }
1201
+ DebuggerStatement(node) {
1202
+ return `${this.spaces}debugger;`;
1203
+ }
1204
+ CommentBlock(node) {
1205
+ const {
1206
+ value
1207
+ } = node;
1208
+ const par = this.parents[this.parents.length - 3];
1209
+ const out = `${this.spaces.slice(2)}/*${value}*/`;
1210
+ if ((par == null ? void 0 : par.type) === 'BlockStatement' || (par == null ? void 0 : par.type) === 'Program') {
1211
+ return out + '\n';
1212
+ }
1213
+ return ' ' + out + ' ';
1214
+ }
1215
+ CommentLine(node) {
1216
+ const {
1217
+ value
1218
+ } = node;
1219
+ return `${this.spaces.slice(2)}//${value}\n`;
1220
+ }
1221
+ Import(node) {
1222
+ return 'import';
1223
+ }
1224
+ ImportDeclaration(node) {
1225
+ const {
1226
+ specifiers,
1227
+ source
1228
+ } = node;
1229
+ const a = this.mapToSource(specifiers).join(', ');
1230
+ const b = this.toSource(source);
1231
+ if (specifiers.length === 0) {
1232
+ return `import ${b}`;
1233
+ }
1234
+ if (specifiers[0].type !== 'ImportSpecifier') {
1235
+ return `import ${a} from ${b};`;
1236
+ }
1237
+ return `import {${a}} from ${b};`;
1238
+ }
1239
+ ImportSpecifier(node) {
1240
+ const {
1241
+ imported,
1242
+ local
1243
+ } = node;
1244
+ const a = this.toSource(imported);
1245
+ const b = this.toSource(local);
1246
+ if (a !== b) {
1247
+ return `${a} as ${b}`;
1248
+ }
1249
+ return a;
1250
+ }
1251
+ ImportDefaultSpecifier(node) {
1252
+ const {
1253
+ local
1254
+ } = node;
1255
+ return this.toSource(local);
1256
+ }
1257
+ ImportNamespaceSpecifier(node) {
1258
+ const {
1259
+ local
1260
+ } = node;
1261
+ return `* as ${this.toSource(local)}`;
1262
+ }
1263
+ File(node) {
1264
+ return this.toSource(node.program) + '\n';
1265
+ }
1266
+ Program(node) {
1267
+ const {
1268
+ sourceType,
1269
+ interpreter,
1270
+ body,
1271
+ directives
1272
+ } = node;
1273
+ let out = '';
1274
+ out += this.mapToSource(directives);
1275
+ out += this.mapToSource(body).join('\n');
1276
+ return out;
1277
+ }
1278
+ StringLiteral(node) {
1279
+ const {
1280
+ extra
1281
+ } = node;
1282
+ if (!extra) {
1283
+ debugger;
1284
+ return '';
1285
+ }
1286
+ if (typeof extra.raw !== 'string') {
1287
+ debugger;
1288
+ return '';
1289
+ }
1290
+ return extra.raw;
1291
+ }
1292
+ NumericLiteral(node) {
1293
+ return node.extra.raw;
1294
+ }
1295
+ AssignmentPattern(node) {
1296
+ const {
1297
+ left,
1298
+ right
1299
+ } = node;
1300
+ return `${this.toSource(left)} = ${this.toSource(right)}`;
1301
+ }
1302
+ NullLiteral(node) {
1303
+ return 'null';
1304
+ }
1305
+ TaggedTemplateExpression(node) {
1306
+ const {
1307
+ tag,
1308
+ quasi
1309
+ } = node;
1310
+ const t = this.toSource(tag);
1311
+ const q = this.toSource(quasi);
1312
+ return t + q;
1313
+ }
1314
+ YieldExpression(node) {
1315
+ const {
1316
+ delegate,
1317
+ argument
1318
+ } = node;
1319
+ let keyword = 'yield';
1320
+ if (delegate) {
1321
+ keyword += '*';
1322
+ }
1323
+ const a = this.toSource(argument);
1324
+ return `${keyword} ${a}`;
1325
+ }
1326
+ }
1327
+
1328
+ class Asserter extends Stringifier {
1329
+ constructor({
1330
+ forceCurly = true,
1331
+ validateDivision = true,
1332
+ expandType = expandTypeDepFree,
1333
+ filename
1334
+ } = {}) {
1335
+ super();
1336
+ this.stats = {
1337
+ 'FunctionDeclaration': {
1338
+ checked: 0,
1339
+ unchecked: 0
1340
+ },
1341
+ 'FunctionExpression': {
1342
+ checked: 0,
1343
+ unchecked: 0
1344
+ },
1345
+ 'ArrowFunctionExpression': {
1346
+ checked: 0,
1347
+ unchecked: 0
1348
+ },
1349
+ 'ClassMethod#constructor': {
1350
+ checked: 0,
1351
+ unchecked: 0
1352
+ },
1353
+ 'ClassMethod#method': {
1354
+ checked: 0,
1355
+ unchecked: 0
1356
+ },
1357
+ 'ClassMethod#set': {
1358
+ checked: 0,
1359
+ unchecked: 0
1360
+ },
1361
+ 'ClassMethod#get': {
1362
+ checked: 0,
1363
+ unchecked: 0
1364
+ }
1365
+ };
1366
+ this.typedefs = {};
1367
+ this.forceCurly = forceCurly;
1368
+ this.validateDivision = validateDivision;
1369
+ this.expandType = expandType;
1370
+ this.filename = filename;
1371
+ }
1372
+ ArrowFunctionExpression(node) {
1373
+ const {
1374
+ async,
1375
+ body,
1376
+ generator,
1377
+ params
1378
+ } = node;
1379
+ let out = '';
1380
+ if (async) {
1381
+ out += 'async ';
1382
+ }
1383
+ if (generator) {
1384
+ out += ' * ';
1385
+ }
1386
+ out += this.FunctionDeclarationParams(params);
1387
+ out += ' =>';
1388
+ if (body.type === 'BlockStatement') {
1389
+ out += this.toSource(body);
1390
+ } else {
1391
+ out += ' {\n';
1392
+ out += this.generateTypeChecks(node);
1393
+ out += this.spaces + 'return ' + this.toSource(body) + ';\n';
1394
+ out += '}';
1395
+ }
1396
+ return out;
1397
+ }
1398
+ ClassDeclaration(node) {
1399
+ const {
1400
+ id
1401
+ } = node;
1402
+ const id_ = this.toSource(id);
1403
+ let out = super.ClassDeclaration(node);
1404
+ out += `${this.spaces}registerClass(${id_});`;
1405
+ return out;
1406
+ }
1407
+ findParentOfType(node, type) {
1408
+ const currentIndex = this.parents.findLastIndex(_ => _ == node);
1409
+ return this.parents.findLast((_, i) => {
1410
+ if (i > currentIndex) {
1411
+ return false;
1412
+ }
1413
+ return _.type === type;
1414
+ });
1415
+ }
1416
+ findParentOfTypeWithPredicate(node, type, predicate) {
1417
+ const {
1418
+ parents
1419
+ } = this;
1420
+ let i = parents.findLastIndex(_ => _ == node);
1421
+ i--;
1422
+ while (i >= 0) {
1423
+ const parent = parents[i];
1424
+ if (predicate(parent)) {
1425
+ return;
1426
+ }
1427
+ if (parent.type === type) {
1428
+ return parent;
1429
+ }
1430
+ i--;
1431
+ }
1432
+ }
1433
+ warn(...args) {
1434
+ if (this.filename) {
1435
+ console.warn("[WARN]", this.filename);
1436
+ }
1437
+ console.warn(...args);
1438
+ }
1439
+ getJSDoc(node) {
1440
+ if (node.type === 'BlockStatement') {
1441
+ node = this.parent;
1442
+ }
1443
+ if (node.type === 'FunctionExpression') {
1444
+ if (node.leadingComments) {
1445
+ this.warn("Case of FunctionExpression containing its own leadingComments is not handled");
1446
+ return;
1447
+ }
1448
+ node = this.findParentOfType(node, 'ExpressionStatement');
1449
+ if (!node) {
1450
+ node = this.parents.findLast(_ => _.type == 'VariableDeclaration');
1451
+ if (!node) {
1452
+ return;
1453
+ }
1454
+ }
1455
+ }
1456
+ let {
1457
+ leadingComments
1458
+ } = node;
1459
+ if (!leadingComments) {
1460
+ if (node.type === 'FunctionDeclaration') {
1461
+ const exportNamedDeclaration = this.findParentOfType(node, 'ExportNamedDeclaration');
1462
+ leadingComments = exportNamedDeclaration == null ? void 0 : exportNamedDeclaration.leadingComments;
1463
+ }
1464
+ if (node.type === 'ArrowFunctionExpression') {
1465
+ var _tmp, _tmp2;
1466
+ let tmp = this.findParentOfType(node, 'VariableDeclaration');
1467
+ if (!((_tmp = tmp) != null && _tmp.leadingComments)) {
1468
+ function isFunc(node) {
1469
+ return node.type === 'ArrowFunctionExpression' || node.type === 'FunctionDeclaration';
1470
+ }
1471
+ tmp = this.findParentOfTypeWithPredicate(node, 'ExportNamedDeclaration', isFunc);
1472
+ }
1473
+ leadingComments = (_tmp2 = tmp) == null ? void 0 : _tmp2.leadingComments;
1474
+ }
1475
+ }
1476
+ if (leadingComments && leadingComments.length) {
1477
+ const lastComment = leadingComments[leadingComments.length - 1];
1478
+ if (lastComment.type == "CommentBlock") {
1479
+ if (lastComment.value.includes('@event')) {
1480
+ return;
1481
+ }
1482
+ if (node.type === 'ClassMethod' && node.kind === 'set') {
1483
+ const paramName = this.getNameOfParam(node.params[0]);
1484
+ if (node.params.length !== 1) {
1485
+ this.warn("getJSDoc> setters require exactly one argument");
1486
+ }
1487
+ return {
1488
+ [paramName]: parseJSDocSetter(lastComment.value, this.expandType)
1489
+ };
1490
+ }
1491
+ return parseJSDoc(lastComment.value, this.expandType);
1492
+ }
1493
+ }
1494
+ }
1495
+ getNameOfParam(param) {
1496
+ if (param.type === 'Identifier') {
1497
+ return param.name;
1498
+ } else if (param.type === 'AssignmentPattern') {
1499
+ if (param.left.type === 'Identifier') {
1500
+ return param.left.name;
1501
+ }
1502
+ }
1503
+ debugger;
1504
+ this.warn("unable to extra name from param in specified way - may contain too much information");
1505
+ return this.toSource(param);
1506
+ }
1507
+ statsReset() {
1508
+ Object.values(this.stats).forEach(statReset);
1509
+ }
1510
+ statsPrint() {
1511
+ console.table(this.stats);
1512
+ }
1513
+ getStatsForNode(node) {
1514
+ const {
1515
+ parentType,
1516
+ stats
1517
+ } = this;
1518
+ if (parentType == 'ClassMethod') {
1519
+ const kind = this.parent.kind;
1520
+ return stats[`ClassMethod#${kind}`];
1521
+ } else if (node.type === 'ArrowFunctionExpression') {
1522
+ return stats.ArrowFunctionExpression;
1523
+ }
1524
+ const stat = stats[parentType];
1525
+ if (!stat) {
1526
+ this.warn("getStatsForNode> dummy, but unhandled... fix for node type", node);
1527
+ return {
1528
+ checked: 0,
1529
+ unchecked: 0
1530
+ };
1531
+ }
1532
+ return stat;
1533
+ }
1534
+ nodeHasParamName(node, name) {
1535
+ if (node.type === 'BlockStatement') {
1536
+ node = this.parent;
1537
+ }
1538
+ const {
1539
+ params
1540
+ } = node;
1541
+ if (!params) {
1542
+ this.warn("nodeHasParamName> Expected params for", {
1543
+ node,
1544
+ name
1545
+ });
1546
+ return false;
1547
+ }
1548
+ return params.some(node => {
1549
+ const {
1550
+ type
1551
+ } = node;
1552
+ if (type === "AssignmentPattern") {
1553
+ const {
1554
+ left
1555
+ } = node;
1556
+ console.assert(left.type === 'Identifier' || left.type === 'ObjectPattern' || left.type === 'ArrayPattern' || left.type === 'AssignmentPattern', 'Expected Identifier or ObjectPattern');
1557
+ return left.name === name;
1558
+ } else if (type === 'Identifier') {
1559
+ return node.name === name;
1560
+ } else if (type === 'ArrayPattern' || type === 'ObjectPattern' || type === 'RestElement') {
1561
+ return false;
1562
+ } else {
1563
+ const _ = new Stringifier();
1564
+ const code = _.toSource(node);
1565
+ console.log("Unknown type to test params for", type, code);
1566
+ }
1567
+ return false;
1568
+ });
1569
+ }
1570
+ generateTypeChecks(node) {
1571
+ const {
1572
+ parentType
1573
+ } = this;
1574
+ if (node.type === 'BlockStatement' && parentType != 'FunctionDeclaration' && parentType != 'ClassMethod' && parentType != 'FunctionExpression') {
1575
+ return '';
1576
+ }
1577
+ const jsdoc = this.getJSDoc(node);
1578
+ const stat = this.getStatsForNode(node);
1579
+ if (!jsdoc) {
1580
+ stat.unchecked++;
1581
+ return '';
1582
+ }
1583
+ stat.checked++;
1584
+ let spaces = this.spaces;
1585
+ if (node.type !== 'ArrowFunctionExpression') {
1586
+ spaces += ' ';
1587
+ }
1588
+ let out = '';
1589
+ for (let name in jsdoc) {
1590
+ const type = jsdoc[name];
1591
+ const hasParam = this.nodeHasParamName(node, name);
1592
+ if (!hasParam) {
1593
+ let testNode = node;
1594
+ if (node.type === 'BlockStatement') {
1595
+ testNode = this.parent;
1596
+ }
1597
+ const paramIndex = Object.keys(jsdoc).findIndex(_ => _ === name);
1598
+ const param = testNode.params[paramIndex];
1599
+ if (param) {
1600
+ const isObjectPattern = param.type === 'ObjectPattern';
1601
+ const isArrayPattern = param.type === 'ArrayPattern';
1602
+ const isSupportedPattern = isObjectPattern || isArrayPattern;
1603
+ if (isSupportedPattern) {
1604
+ name = `arguments[${paramIndex}]`;
1605
+ } else if (param.type === 'AssignmentPattern') {
1606
+ const _loc = this.getName(node);
1607
+ if (param.left.type === 'ArrayPattern' && type.type === 'array') {
1608
+ for (const element of param.left.elements) {
1609
+ if (element.type !== 'Identifier') {
1610
+ this.warn('Only Identifier case handled right now');
1611
+ continue;
1612
+ }
1613
+ const _t = JSON.stringify(type.elementType, null, 2).replaceAll('\n', '\n' + spaces);
1614
+ out += `${spaces}if (!assertType(${element.name}, ${_t}, '${_loc}', '${name}')) {\n`;
1615
+ out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
1616
+ }
1617
+ continue;
1618
+ } else if (param.left.type === 'ObjectPattern' && type.type === 'object') {
1619
+ for (const property of param.left.properties) {
1620
+ if (property.key.type !== 'Identifier') {
1621
+ this.warn('ObjectPattern> Only Identifier case handled right now');
1622
+ continue;
1623
+ }
1624
+ const keyName = property.key.name;
1625
+ const subType = type.properties[keyName];
1626
+ if (!subType) {
1627
+ this.warn("missing subtype information in JSDoc");
1628
+ continue;
1629
+ }
1630
+ const _t2 = JSON.stringify(subType, null, 2).replaceAll('\n', '\n' + spaces);
1631
+ out += `${spaces}if (!assertType(${keyName}, ${_t2}, '${_loc}', '${name}')) {\n`;
1632
+ out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
1633
+ }
1634
+ continue;
1635
+ }
1636
+ this.warn(`generateTypeChecks> ${_loc}> todo implement`, `AssignmentPattern for parameter ${name}`);
1637
+ continue;
1638
+ }
1639
+ } else {
1640
+ const _loc2 = this.getName(node);
1641
+ this.warn(`generateTypeChecks> ${_loc2}> Missing param: ${name}`);
1642
+ continue;
1643
+ }
1644
+ }
1645
+ let t = JSON.stringify(type, null, 2).replaceAll('\n', '\n' + spaces);
1646
+ if (type === 'this') {
1647
+ const classDecl = this.findParentOfType(node, 'ClassDeclaration');
1648
+ if (!(classDecl != null && classDecl.id)) {
1649
+ this.warn('generateTypeChecks> !classDecl?.id');
1650
+ }
1651
+ t = '"' + this.toSource(classDecl.id) + '"';
1652
+ }
1653
+ const loc = this.getName(node);
1654
+ let prevCheck = '';
1655
+ if (loc === 'ContactPoint#constructor' || loc === 'ContactResult#constructor' || loc === 'SingleContactResult#constructor') {
1656
+ prevCheck = 'arguments.length !== 0 && ';
1657
+ }
1658
+ out += `${spaces}if (${prevCheck}!assertType(${name}, ${t}, '${loc}', '${name}')) {\n`;
1659
+ out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
1660
+ }
1661
+ return out;
1662
+ }
1663
+ getName(node) {
1664
+ const toSource = this.toSource.bind(this);
1665
+ if (node.type === 'BlockStatement') {
1666
+ node = this.parent;
1667
+ }
1668
+ const {
1669
+ type,
1670
+ key,
1671
+ id
1672
+ } = node;
1673
+ switch (type) {
1674
+ case 'FunctionDeclaration':
1675
+ return toSource(id);
1676
+ case "ClassMethod":
1677
+ const classDecl = this.parents.findLast(_ => _.type == 'ClassDeclaration');
1678
+ let out = '';
1679
+ if (classDecl) {
1680
+ out += toSource(classDecl.id) + '#';
1681
+ }
1682
+ out += toSource(key);
1683
+ return out;
1684
+ case 'FunctionExpression':
1685
+ if (id) {
1686
+ return toSource(id);
1687
+ }
1688
+ const expressionStatement = this.findParentOfType(node, 'ExpressionStatement');
1689
+ if (!expressionStatement) {
1690
+ return "unnamed function expression";
1691
+ }
1692
+ return toSource(expressionStatement.expression.left);
1693
+ case 'ArrowFunctionExpression':
1694
+ const parent = this.findParentOfType(node, 'VariableDeclarator');
1695
+ if (parent) {
1696
+ return toSource(parent.id);
1697
+ } else {
1698
+ return "getName> missing parent for " + node.type;
1699
+ }
1700
+ default:
1701
+ this.warn("getName> unhandled type", type, "for", node);
1702
+ return '/*MISSING*/';
1703
+ }
1704
+ }
1705
+ BinaryExpression(node) {
1706
+ if (!this.validateDivision) {
1707
+ return super.BinaryExpression(node);
1708
+ }
1709
+ const {
1710
+ left,
1711
+ operator,
1712
+ right
1713
+ } = node;
1714
+ const left_ = this.toSource(left);
1715
+ const right_ = this.toSource(right);
1716
+ if (operator === '/') {
1717
+ return `validateDivision(${left_}, ${right_})`;
1718
+ }
1719
+ return `${left_} ${operator} ${right_}`;
1720
+ }
1721
+ File(node) {
1722
+ const {
1723
+ errors,
1724
+ program,
1725
+ comments
1726
+ } = node;
1727
+ if (comments) {
1728
+ for (const comment of comments) {
1729
+ const warn = this.warn.bind(this);
1730
+ parseJSDocTypedef(this.typedefs, warn, comment, this.expandType);
1731
+ }
1732
+ }
1733
+ let out = '';
1734
+ for (const name in this.typedefs) {
1735
+ const typedef = this.typedefs[name];
1736
+ const json = JSON.stringify(typedef, null, 2);
1737
+ out += `registerTypedef('${name}', ${json});\n`;
1738
+ }
1739
+ const code = this.toSource(program) + '\n';
1740
+ out += code;
1741
+ return out;
1742
+ }
1743
+ }
1744
+
1745
+ function addTypeChecks(src, options) {
1746
+ try {
1747
+ const asserter = new Asserter(options);
1748
+ const ast = parse(src, {
1749
+ sourceType: 'module'
1750
+ });
1751
+ const out = asserter.toSource(ast);
1752
+ return out;
1753
+ } catch (e) {
1754
+ console.error(e);
1755
+ return `/*<addTypeChecks-error>*/${src}/*</addTypeChecks-error>*/`;
1756
+ }
1757
+ }
1758
+
1759
+ function ast2json(ast) {
1760
+ return JSON.stringify(ast, function (name, val) {
1761
+ if (name == "loc" || name == "start" || name == "end") {
1762
+ return undefined;
1763
+ }
1764
+ return val;
1765
+ }, 2);
1766
+ }
1767
+
1768
+ const drop = ['loc', 'start', 'end', 'leadingComments', 'trailingComments', 'innerComments', 'innerComments', 'comments'];
1769
+ function ast2jsonForComparison(ast) {
1770
+ return JSON.stringify(ast, function (name, val) {
1771
+ if (name === 'trailingComma' || name === 'parenStart') {
1772
+ return 'offset removed for better comparison';
1773
+ }
1774
+ if (drop.includes(name)) {
1775
+ return undefined;
1776
+ }
1777
+ return val;
1778
+ }, 2);
1779
+ }
1780
+
1781
+ function code2ast2code(code) {
1782
+ const stringifier = new Stringifier();
1783
+ const ast = parse(code, {
1784
+ sourceType: 'module'
1785
+ });
1786
+ if (!ast) {
1787
+ return;
1788
+ }
1789
+ const out = stringifier.toSource(ast);
1790
+ return out;
1791
+ }
1792
+
1793
+ function expandType(type) {
1794
+ const ast = parseType(type);
1795
+ return toSourceTS(ast);
1796
+ }
1797
+ function parseType(str) {
1798
+ if (str.startsWith('...')) {
1799
+ str = str.slice(3);
1800
+ str += '[]';
1801
+ }
1802
+ str = `type tmp = ${str};`;
1803
+ const ast = ts.createSourceFile('repl.ts', str, ts.ScriptTarget.Latest, true);
1804
+ return ast.statements[0].type;
1805
+ }
1806
+ function toSourceTS(node) {
1807
+ const {
1808
+ typeArguments,
1809
+ typeName
1810
+ } = node;
1811
+ const kind_ = ts.SyntaxKind[node.kind];
1812
+ const {
1813
+ AnyKeyword,
1814
+ ArrayType,
1815
+ BooleanKeyword,
1816
+ FunctionType,
1817
+ Identifier,
1818
+ IntersectionType,
1819
+ JSDocAllType,
1820
+ LastTypeNode,
1821
+ LiteralType,
1822
+ NullKeyword,
1823
+ NumberKeyword,
1824
+ NumericLiteral,
1825
+ ObjectKeyword,
1826
+ Parameter,
1827
+ ParenthesizedType,
1828
+ PropertySignature,
1829
+ StringKeyword,
1830
+ StringLiteral,
1831
+ ThisType,
1832
+ TupleType,
1833
+ TypeLiteral,
1834
+ TypeReference,
1835
+ UndefinedKeyword,
1836
+ UnionType,
1837
+ JSDocNullableType
1838
+ } = ts.SyntaxKind;
1839
+ switch (node.kind) {
1840
+ case FunctionType:
1841
+ const parameters = node.parameters.map(toSourceTS);
1842
+ return {
1843
+ type: 'function',
1844
+ parameters
1845
+ };
1846
+ case JSDocNullableType:
1847
+ const t = toSourceTS(node.type);
1848
+ return {
1849
+ type: 'union',
1850
+ members: [t, 'null']
1851
+ };
1852
+ case Parameter:
1853
+ const type = node.type ? toSourceTS(node.type) : 'any';
1854
+ const name = toSourceTS(node.name);
1855
+ const ret = {
1856
+ type,
1857
+ name
1858
+ };
1859
+ if (node.dotDotDotToken) {
1860
+ return {
1861
+ type: 'array',
1862
+ elementType: ret
1863
+ };
1864
+ }
1865
+ return ret;
1866
+ case TypeReference:
1867
+ if ((typeName.text === 'Object' || typeName.text === 'Record') && (typeArguments == null ? void 0 : typeArguments.length) === 2) {
1868
+ return {
1869
+ type: 'record',
1870
+ key: toSourceTS(typeArguments[0]),
1871
+ val: toSourceTS(typeArguments[1])
1872
+ };
1873
+ } else if (typeName.text === 'Object' && (!typeArguments || (typeArguments == null ? void 0 : typeArguments.length) === 0)) {
1874
+ return {
1875
+ type: 'object',
1876
+ properties: {}
1877
+ };
1878
+ } else if (typeName.text === 'Map' && (typeArguments == null ? void 0 : typeArguments.length) === 2) {
1879
+ return {
1880
+ type: 'map',
1881
+ key: toSourceTS(typeArguments[0]),
1882
+ val: toSourceTS(typeArguments[1])
1883
+ };
1884
+ } else if (typeName.text === 'Array' && (typeArguments == null ? void 0 : typeArguments.length) === 1) {
1885
+ const elementType = toSourceTS(typeArguments[0]);
1886
+ return {
1887
+ type: 'array',
1888
+ elementType
1889
+ };
1890
+ } else if (typeName.text === 'Set' && (typeArguments == null ? void 0 : typeArguments.length) === 1) {
1891
+ const elementType = toSourceTS(typeArguments[0]);
1892
+ return {
1893
+ type: 'set',
1894
+ elementType
1895
+ };
1896
+ } else if (typeName.text === 'Class' && (typeArguments == null ? void 0 : typeArguments.length) === 1) {
1897
+ return {
1898
+ type: 'class',
1899
+ elementType: toSourceTS(typeArguments[0])
1900
+ };
1901
+ } else {
1902
+ if (!typeArguments) {
1903
+ return typeName.getText();
1904
+ }
1905
+ console.warn('unhandled TypeReference', kind_, node);
1906
+ return {
1907
+ type: 'unhandled TypeReference'
1908
+ };
1909
+ }
1910
+ case StringKeyword:
1911
+ return node.getText();
1912
+ case NumberKeyword:
1913
+ return node.getText();
1914
+ case IntersectionType:
1915
+ return {
1916
+ type: 'intersection',
1917
+ members: node.types.map(toSourceTS)
1918
+ };
1919
+ case TupleType:
1920
+ return {
1921
+ type: 'tuple',
1922
+ elements: node.elements.map(toSourceTS)
1923
+ };
1924
+ case UnionType:
1925
+ return {
1926
+ type: 'union',
1927
+ members: node.types.map(toSourceTS)
1928
+ };
1929
+ case TypeLiteral:
1930
+ const properties = {};
1931
+ node.members.forEach(member => {
1932
+ const name = toSourceTS(member.name);
1933
+ const type = toSourceTS(member.type);
1934
+ properties[name] = type;
1935
+ });
1936
+ return {
1937
+ type: 'object',
1938
+ properties
1939
+ };
1940
+ case PropertySignature:
1941
+ console.warn('toSourceTS> should not happen, handled by TypeLiteral directly');
1942
+ return `${toSourceTS(node.name)}: ${toSourceTS(node.type)}`;
1943
+ case Identifier:
1944
+ return node.text;
1945
+ case ArrayType:
1946
+ return {
1947
+ type: 'array',
1948
+ elementType: toSourceTS(node.elementType)
1949
+ };
1950
+ case LiteralType:
1951
+ return toSourceTS(node.literal);
1952
+ case AnyKeyword:
1953
+ case BooleanKeyword:
1954
+ case JSDocAllType:
1955
+ case NullKeyword:
1956
+ case NumericLiteral:
1957
+ case StringLiteral:
1958
+ case ThisType:
1959
+ case UndefinedKeyword:
1960
+ return node.getText();
1961
+ case ObjectKeyword:
1962
+ return {
1963
+ type: 'object',
1964
+ properties: {}
1965
+ };
1966
+ case ParenthesizedType:
1967
+ return toSourceTS(node.type);
1968
+ case LastTypeNode:
1969
+ return toSourceTS(node.qualifier);
1970
+ default:
1971
+ console.warn('toSourceTS> unhandled kind - make sure to understand you cannot reverse TS enums');
1972
+ console.warn('if they contain range aliases, for example:');
1973
+ console.warn('ts.SyntaxKind.NumericLiteral === ts.SyntaxKind.FirstLiteralToken');
1974
+ console.warn('so this "kind" could be wrong, but requires handling anyway:', kind_, node);
1975
+ debugger;
1976
+ }
1977
+ }
1978
+
1979
+ export { Asserter, Stringifier, addTypeChecks, ast2json, ast2jsonForComparison, code2ast2code, expandType, expandTypeDepFree, extractCurlyContent, extractNameAndOptionality, parseJSDoc, parseJSDocSetter, parseJSDocTypedef, parseType, simplifyType, toSourceTS };