runtime-type-inspector 1.0.0 → 2.0.1

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/.eslintrc.js +480 -0
  2. package/README.md +12 -4
  3. package/jsconfig.json +10 -0
  4. package/package.json +32 -4
  5. package/plugin-parcel/index.mjs +4 -0
  6. package/plugin-rollup/index.mjs +78 -0
  7. package/plugin-webpack/index.mjs +4 -0
  8. package/rollup.config.mjs +183 -0
  9. package/src-runtime/assertType.mjs +54 -0
  10. package/src-runtime/createDiv.mjs +69 -0
  11. package/src-runtime/index.mjs +21 -0
  12. package/src-runtime/makeJSDoc.mjs +40 -0
  13. package/src-runtime/registerClass.mjs +11 -0
  14. package/src-runtime/registerTypedef.mjs +12 -0
  15. package/src-runtime/typecheckDiv.mjs +3 -0
  16. package/src-runtime/typecheckEvery.mjs +21 -0
  17. package/src-runtime/typecheckOptions.mjs +60 -0
  18. package/src-runtime/typecheckTable.mjs +14 -0
  19. package/src-runtime/typecheckWarn.mjs +23 -0
  20. package/src-runtime/validateArray.mjs +26 -0
  21. package/src-runtime/validateDivision.mjs +31 -0
  22. package/src-runtime/validateMap.mjs +36 -0
  23. package/src-runtime/validateNumber.mjs +29 -0
  24. package/src-runtime/validateObject.mjs +43 -0
  25. package/src-runtime/validateRecord.mjs +31 -0
  26. package/src-runtime/validateSet.mjs +26 -0
  27. package/src-runtime/validateTuple.mjs +28 -0
  28. package/src-runtime/validateType.mjs +214 -0
  29. package/src-runtime/validateTypedef.mjs +18 -0
  30. package/src-runtime/validateUnion.mjs +19 -0
  31. package/src-runtime/youCanAddABreakpointHere.mjs +11 -0
  32. package/src-transpiler/Stringifier.mjs +1268 -0
  33. package/src-transpiler/StringifierWithTypeAssertions.mjs +478 -0
  34. package/src-transpiler/addTypeChecks.mjs +20 -0
  35. package/src-transpiler/ast2json.mjs +13 -0
  36. package/src-transpiler/ast2jsonForComparison.mjs +28 -0
  37. package/src-transpiler/code2ast2code.mjs +16 -0
  38. package/src-transpiler/expandType.mjs +187 -0
  39. package/src-transpiler/expandTypeDepFree.mjs +122 -0
  40. package/src-transpiler/extractNameAndOptionality.mjs +23 -0
  41. package/src-transpiler/index.mjs +13 -0
  42. package/src-transpiler/parseJSDoc.mjs +69 -0
  43. package/src-transpiler/parseJSDocSetter.mjs +16 -0
  44. package/src-transpiler/parseJSDocTypedef.mjs +69 -0
  45. package/src-transpiler/simplifyType.mjs +31 -0
  46. package/src-transpiler/stat.mjs +13 -0
  47. package/ui/babel-core.mjs +5 -0
  48. package/ui/babel-helper-plugin-utils.mjs +7 -0
  49. package/ui/babel-parser.mjs +8 -0
  50. package/ui/babel-plugin-syntax-typescript.mjs +58 -0
  51. package/ui/importmap.js +38 -0
  52. package/ui/index.html +30 -0
  53. package/ui/index.mjs +379 -0
  54. package/src/index.mjs +0 -1
@@ -0,0 +1,1268 @@
1
+ /**
2
+ * @typedef {import("@babel/types").Node} Node
3
+ */
4
+ class Stringifier {
5
+ forceCurly = false;
6
+ /** @type {Node[]} */
7
+ parents = [];
8
+ /**
9
+ * @param {Node} node - The Babel AST node.
10
+ * @returns {string} Stringification of the node.
11
+ */
12
+ toSource(node) {
13
+ // handle this case only temporarily
14
+ if (node === null) {
15
+ // Contexts like:
16
+ // Object.assign(Channel3d.prototype, {
17
+ // setPosition: function /*null*/(position) {
18
+ //return '/*null*/';
19
+ return '';
20
+ }
21
+ if (node.type === 'File') {
22
+ this.parents.length = 0;
23
+ }
24
+ this.parents.push(node);
25
+ let out = '';
26
+ let comments = '';
27
+ if (node && node.leadingComments) {
28
+ comments += this.mapToSource(node.leadingComments).join('');
29
+ }
30
+ if (node?.extra?.parenthesized) {
31
+ out += `(${comments}${this.toSource_(node)})`;
32
+ } else {
33
+ out += comments + this.toSource_(node);
34
+ }
35
+ // leadingComments and trailingComments lead to duplicates, not always tho
36
+ //if (node && node.trailingComments) {
37
+ // out += this.mapToSource(node.trailingComments).join('\n') + '\n';
38
+ //}
39
+ this.parents.pop();
40
+ return out;
41
+ }
42
+ /**
43
+ * @param {Node} node - The Babel AST node.
44
+ * @returns {string} Stringification of the node.
45
+ */
46
+ toSource_(node) {
47
+ if (!node) {
48
+ return '';
49
+ }
50
+ const {type} = node;
51
+ if (type === undefined) {
52
+ console.log("toSource> node without type", node);
53
+ }
54
+ if (this[type]) {
55
+ return this[type](node);
56
+ }
57
+ console.log(node);
58
+ const notOfInterest = ["start", "end", "loc", "type"];
59
+ const ofInterest = Object.keys(node).filter(_ => !notOfInterest.includes(_));
60
+ const props = ofInterest.join(', ');
61
+ const fn = `${type}(node) {\n const {${props}} = node;\n return ;\n}`;
62
+ console.warn('TODO ADD METHOD:', fn);
63
+ return `rtiUnhandled("${node.type}");\n`;
64
+ }
65
+ /**
66
+ * Only add { and } when requested (e.g. for StringifierWithTypeAssertions).
67
+ * showAST("if (true) 2;") vs showAST("if (true) {2}")
68
+ * @param {Node} node - The Babel AST node.
69
+ * @returns {string} Stringification of the node.
70
+ */
71
+ toSourceCurly(node) {
72
+ if (!this.forceCurly) {
73
+ return this.toSource(node);
74
+ }
75
+ const {type} = node;
76
+ const needCurly = type != 'BlockStatement' && type != 'EmptyStatement';
77
+ const spaces = this.spaces;
78
+ let out = '';
79
+ if (needCurly) {
80
+ out += ' {\n';
81
+ //out += spaces + `/* toSourceCurly> needCurly=${needCurly} type=${type}
82
+ //parents=${parents.map(_=>_.type).join('->')}*/\n`;
83
+ }
84
+ out += this.toSource(node);
85
+ if (needCurly) {
86
+ out += '\n';
87
+ out += spaces;
88
+ out += '}';
89
+ }
90
+ return out;
91
+ }
92
+ get parent() {
93
+ return this.parents[this.parents.length - 2];
94
+ }
95
+ get parentType() {
96
+ return this.parent?.type;
97
+ }
98
+ get needSpaces() {
99
+ const t = this.parentType;
100
+ return t != "ForStatement" &&
101
+ t != "ForInStatement" &&
102
+ t != "ForOfStatement";
103
+ }
104
+ /**
105
+ * @param {Node[]} arr
106
+ * @returns {string[]}
107
+ */
108
+ mapToSource(arr) {
109
+ return arr.map(_ => this.toSource(_));
110
+ }
111
+ /**
112
+ * This method is implemented in StringifierWithTypeAssertions.mjs
113
+ * @param {Node} node - The Babel AST node.
114
+ * @returns {string}
115
+ */
116
+ generateTypeChecks(node) {
117
+ const {spaces} = this;
118
+ return `${spaces}/* Stub of Stringifier#generateTypeChecks({type=${node.type}}); */\n`;
119
+ }
120
+ /**
121
+ * Start from File->Program->... while ignoring BlockStatements aswell
122
+ * @returns {string} A string of two spaces per indentation.
123
+ */
124
+ get spaces() {
125
+ const {parents} = this;
126
+ // This needs a bit refactoring to fix spaces in all cases
127
+ if (false) {
128
+ let n = parents.filter(_ => _.type === 'IfStatement' || _.type === 'BlockStatementasd').length;
129
+ //n--;
130
+ if (n < 0) {
131
+ n = 0;
132
+ }
133
+ return ' '.repeat(n);
134
+ }
135
+ let n = parents.length;
136
+ if (parents[0]?.type == 'File') {
137
+ n--;
138
+ }
139
+ if (parents[1]?.type == 'Program') {
140
+ n--;
141
+ }
142
+ n -= parents.filter(
143
+ _ => false
144
+ || _.type === 'BlockStatement'
145
+ //|| _.type === 'VariableDeclaration'
146
+ || _.type === 'VariableDeclarator'
147
+ || _.type === 'ObjectProperty'
148
+ || _.type === 'ExportNamedDeclaration'
149
+ || _.type === 'NewExpression'
150
+ || _.type === 'AssignmentExpression'
151
+ //|| _.type === 'MemberExpression'
152
+ //|| _.type === 'ThisExpression'
153
+ || _.type === 'ArrayExpression'
154
+ //|| (_.type === 'ExpressionStatement' && _.expression.type === 'NewExpression')
155
+ //|| (_.type === 'ExpressionStatement' && _.expression.type === 'CallExpression')
156
+ || _.type === 'ClassBody' // ClassDeclaration is enough to increase indentation
157
+ //|| _.type === 'LabeledStatement'
158
+ //|| _.type === 'ExpressionStatement'
159
+ ).length;
160
+ n -= 1; // Do not count last frame we are in right now.
161
+ if (
162
+ parents.some(_ => _.type === 'CallExpression') &&
163
+ parents.some(_ => _.type === 'ObjectExpression')
164
+ ) {
165
+ n--;
166
+ }
167
+ if (n < 0) {
168
+ //console.warn("getSpaces> n < 0");
169
+ n = 0;
170
+ }
171
+ return ' '.repeat(n);
172
+ }
173
+ /**
174
+ * > await something();
175
+ *
176
+ * @param {import("@babel/types").AwaitExpression} node - The Babel AST node.
177
+ * @returns {string} Stringification of the node.
178
+ */
179
+ AwaitExpression(node) {
180
+ const {argument} = node;
181
+ return `await ${this.toSource(argument)}`;
182
+ }
183
+ /**
184
+ * > asd;
185
+ * > asd = 1;
186
+ * > static asd;
187
+ * > static asd = 1;
188
+ *
189
+ * @param {import("@babel/types").ClassProperty} node - The Babel AST node.
190
+ * @returns {string} Stringification of the node.
191
+ */
192
+ ClassProperty(node) {
193
+ const {key, computed, value, leadingComments} = node;
194
+ const static_ = node.static; // JS keyword is problematic in object destructuring
195
+ const a = this.toSource(key);
196
+ const b = this.toSource(value);
197
+ let out = this.spaces;
198
+ if (static_) {
199
+ out += 'static ';
200
+ }
201
+ if (computed) {
202
+ out += `[${a}]`;
203
+ } else {
204
+ out += a;
205
+ }
206
+ if (b) {
207
+ out += ` = ${b}`;
208
+ }
209
+ out += ';';
210
+ return out;
211
+ }
212
+ /**
213
+ * @param {Node[]} params
214
+ * @returns {string} Stringification of the params.
215
+ */
216
+ FunctionDeclarationParams(params) {
217
+ return '(' + this.mapToSource(params).join(', ') + ')';
218
+ }
219
+ /**
220
+ * @param {import("@babel/types").FunctionDeclaration} node - The Babel AST node.
221
+ * @returns {string} Stringification of the node.
222
+ */
223
+ FunctionDeclaration(node) {
224
+ const {async, body, generator, id, leadingComments, params} = node;
225
+ let out = '';
226
+ if (this.parentType !== 'ExportNamedDeclaration') {
227
+ out += this.spaces;
228
+ }
229
+ if (async) {
230
+ out += 'async ';
231
+ }
232
+ const asterix = generator ? '*' : '';
233
+ out += 'function' + asterix + ' ' + this.toSource(id) + this.FunctionDeclarationParams(params);
234
+ out += this.toSource(body);
235
+ return out;
236
+ }
237
+ /**
238
+ * @param {import("@babel/types").FunctionExpression} node - The Babel AST node.
239
+ * @returns {string} Stringification of the node.
240
+ */
241
+ FunctionExpression(node) {
242
+ // Leading comments for asd=function(){} are in ExpressionStatement
243
+ const {async, body, generator, id/*, leadingComments*/, params/*, extra*/} = node;
244
+ let out = '';
245
+ if (async) {
246
+ out += 'async ';
247
+ }
248
+ const star = generator ? '*' : '';
249
+ out += 'function' + star + ' ' + this.toSource(id) + this.FunctionDeclarationParams(params);
250
+ out += this.toSource(body);
251
+ return out;
252
+ }
253
+ /**
254
+ * @param {import("@babel/types").ArrowFunctionExpression} node - The Babel AST node.
255
+ * @returns {string} Stringification of the node.
256
+ */
257
+ ArrowFunctionExpression(node) {
258
+ const {async, body, generator, params/*, extra*/} = node;
259
+ let out = '';
260
+ if (async) {
261
+ out += 'async ';
262
+ }
263
+ if (generator) {
264
+ out += ' * ';
265
+ }
266
+ out += this.FunctionDeclarationParams(params);
267
+ out += ' => ';
268
+ out += this.toSource(body);
269
+ return out;
270
+ }
271
+ /**
272
+ * @param {import("@babel/types").BigIntLiteral} node - The Babel AST node.
273
+ * @returns {string} Stringification of the node.
274
+ */
275
+ BigIntLiteral(node) {
276
+ const {extra, value} = node;
277
+ return extra.raw;
278
+ }
279
+ /**
280
+ * @param {import("@babel/types").BlockStatement} node - The Babel AST node.
281
+ * @returns {string} Stringification of the node.
282
+ */
283
+ BlockStatement(node) {
284
+ const {body, directives} = node;
285
+ const spaces = this.spaces;
286
+ let out = '';
287
+ out += ' {\n';
288
+ // Handle Directive/DirectiveLiteral like 'use strict';
289
+ if (directives && directives.length) {
290
+ out += this.mapToSource(directives).join('\n') + '\n';
291
+ }
292
+ out += this.generateTypeChecks(node);
293
+ out += this.mapToSource(body).join('\n') + '\n';
294
+ out += spaces;
295
+ out += '}';
296
+ return out;
297
+ }
298
+ /**
299
+ * @param {import("@babel/types").ClassExpression} node - The Babel AST node.
300
+ * @returns {string} Stringification of the node.
301
+ */
302
+ ClassExpression(node) {
303
+ const {id, superClass, body} = node;
304
+ let out = 'class ';
305
+ if (id !== null) {
306
+ // Babel: strange API, either null or undefined... pick a type, maybe oversight/bug
307
+ out += this.toSource(id) + ' ';
308
+ }
309
+ if (superClass !== null) {
310
+ const s = this.toSource(superClass);
311
+ out += `extends ${s} `;
312
+ }
313
+ const c = this.toSource(body);
314
+ out += `{\n${c}\n}`;
315
+ return out;
316
+ }
317
+ /**
318
+ * > 'use strict';
319
+ *
320
+ * @param {import("@babel/types").Directive} node - The Babel AST node.
321
+ * @returns {string} Stringification of the node.
322
+ */
323
+ Directive(node) {
324
+ const {value} = node;
325
+ return this.toSource(value);
326
+ }
327
+ /**
328
+ * > 'use strict';
329
+ *
330
+ * @param {import("@babel/types").DirectiveLiteral} node - The Babel AST node.
331
+ * @returns {string} Stringification of the node.
332
+ */
333
+ DirectiveLiteral(node) {
334
+ const {extra, value} = node;
335
+ const {spaces} = this;
336
+ return `${spaces}${extra.raw};`;
337
+ }
338
+ /**
339
+ * @param {import("@babel/types").ReturnStatement} node - The Babel AST node.
340
+ * @returns {string} Stringification of the node.
341
+ */
342
+ ReturnStatement(node) {
343
+ const {argument} = node;
344
+ const {spaces} = this;
345
+ if (!argument) {
346
+ return spaces + 'return;';
347
+ }
348
+ return spaces + 'return ' + this.toSource(argument) + ';';
349
+ }
350
+ /**
351
+ * @param {import("@babel/types").Identifier} node - The Babel AST node.
352
+ * @returns {string} Stringification of the node.
353
+ */
354
+ Identifier(node) {
355
+ return node.name;
356
+ }
357
+ /**
358
+ * @param {import("@babel/types").IfStatement} node - The Babel AST node.
359
+ * @returns {string} Stringification of the node.
360
+ */
361
+ IfStatement(node) {
362
+ const {alternate, consequent, test} = node;
363
+ const spaces = this.spaces;
364
+ let out = '';
365
+ //if (this.parentType !== "IfStatement")
366
+ {
367
+ out += spaces;
368
+ }
369
+ out += `if (${this.toSource(test)})`;
370
+ out += this.toSourceCurly(consequent);
371
+ if (alternate) {
372
+ out += ` else${this.toSourceCurly(alternate)}`;
373
+ }
374
+ return out;
375
+ }
376
+ /**
377
+ * @param {import("@babel/types").LabeledStatement} node - The Babel AST node.
378
+ * @returns {string} Stringification of the node.
379
+ */
380
+ LabeledStatement(node) {
381
+ const {body, label} = node;
382
+ const {spaces} = this;
383
+ let out = '';
384
+ out += spaces + this.toSource(label);
385
+ out += ': \n';
386
+ out += spaces + this.toSource(body);
387
+ return out;
388
+ }
389
+ /**
390
+ * @example
391
+ * ts = require("typescript");
392
+ * ts.createSourceFile("repl.ts", "a = 1", ts.ScriptTarget.Latest);
393
+ * ts.createSourceFile("repl.ts", "!!(a = 1 + 2)", ts.ScriptTarget.Latest);
394
+ * showAST('!!(a = 1)');
395
+ * @param {import("@babel/types").UnaryExpression} node - The Babel AST node.
396
+ * @returns {string} Stringification of the node.
397
+ */
398
+ UnaryExpression(node) {
399
+ let out = '';
400
+ const {argument, operator, prefix} = node;
401
+ if (!prefix) {
402
+ console.warn("Stringifier#UnaryExpression> never considered !prefix", node);
403
+ }
404
+ // Add a space for: typeof/delete/void
405
+ const c = operator.charCodeAt(0);
406
+ let op = operator;
407
+ if (c >= 97 && c <= 122) {
408
+ op += ' ';
409
+ }
410
+ out += op;
411
+ out += this.toSource(argument);
412
+ return out;
413
+ }
414
+ /**
415
+ * @param {import("@babel/types").MemberExpression} node - The Babel AST node.
416
+ * @returns {string} Stringification of the node.
417
+ */
418
+ MemberExpression(node) {
419
+ const {computed, object, property} = node;
420
+ if (computed) {
421
+ return `${this.toSource(object)}[${this.toSource(property)}]`;
422
+ }
423
+ return `${this.toSource(object)}.${this.toSource(property)}`;
424
+ }
425
+ /**
426
+ * @param {import("@babel/types").MetaProperty} node - The Babel AST node.
427
+ * @returns {string} Stringification of the node.
428
+ */
429
+ MetaProperty(node) {
430
+ const {meta, property} = node;
431
+ const lhs = this.toSource(meta);
432
+ const rhs = this.toSource(property);
433
+ return `${lhs}.${rhs}`;
434
+ }
435
+ /**
436
+ * @param {import("@babel/types").ExpressionStatement} node - The Babel AST node.
437
+ * @returns {string} Stringification of the node.
438
+ */
439
+ ExpressionStatement(node) {
440
+ const {expression} = node;
441
+ /**
442
+ * Not just a fall-through, adds a semicolon when it has semantic meaning.
443
+ * E.g. invalid:
444
+ * (function() {})()
445
+ * (function() {})()
446
+ */
447
+ return this.spaces + this.toSource(expression) + ';';
448
+ }
449
+ /**
450
+ * @param {import("@babel/types").CallExpression} node - The Babel AST node.
451
+ * @returns {string} Stringification of the node.
452
+ */
453
+ CallExpression(node) {
454
+ const {callee, arguments: args, extra} = node;
455
+ let out = this.toSource(callee);
456
+ out += "(";
457
+ out += this.mapToSource(args).join(', ');
458
+ if (!!extra?.trailingComma) {
459
+ out += ',';
460
+ }
461
+ out += ")";
462
+ return out;
463
+ }
464
+ /**
465
+ * We replicate the exact AST for validation:
466
+ * x = 1;
467
+ * y = {x,}
468
+ * z = {y};
469
+ * @param {import("@babel/types").ObjectExpression} node - The Babel AST node.
470
+ * @returns {string} Stringification of the node.
471
+ */
472
+ ObjectExpression(node) {
473
+ const {properties, extra} = node;
474
+ let out = '{';
475
+ if (properties.length) {
476
+ const props = this.mapToSource(properties).join(',\n');
477
+ out += '\n';
478
+ out += props;
479
+ if (extra?.trailingComma) {
480
+ out += ',';
481
+ }
482
+ out += '\n';
483
+ out += this.spaces.slice(2);
484
+ }
485
+ out += '}';
486
+ return out;
487
+ }
488
+ /**
489
+ * @param {import("@babel/types").ObjectProperty} node - The Babel AST node.
490
+ * @returns {string} Stringification of the node.
491
+ */
492
+ ObjectProperty(node) {
493
+ const {computed, key, method, shorthand, value} = node;
494
+ if (method) {
495
+ console.warn("ObjectProperty> unhandled method property:", {method, shorthand});
496
+ }
497
+ const spaces = this.spaces;
498
+ let left = this.toSource(key);
499
+ const right = this.toSource(value);
500
+ let out = spaces;
501
+ if (computed) {
502
+ left = `[${left}]`;
503
+ }
504
+ if (!shorthand) {
505
+ out += left + ': ';
506
+ }
507
+ out += right;
508
+ return out;
509
+ }
510
+ /**
511
+ * @param {import("@babel/types").BooleanLiteral} node - The Babel AST node.
512
+ * @returns {string} Stringification of the node.
513
+ */
514
+ BooleanLiteral(node) {
515
+ return node.value.toString();
516
+ }
517
+ /**
518
+ * @param {import("@babel/types").AssignmentExpression} node - The Babel AST node.
519
+ * @returns {string} Stringification of the node.
520
+ */
521
+ AssignmentExpression(node) {
522
+ const {left, operator, right} = node;
523
+ const left_ = this.toSource(left);
524
+ const right_ = this.toSource(right);
525
+ // operator is for example: = |= &=
526
+ return `${left_} ${operator} ${right_}`;
527
+ }
528
+ /**
529
+ * @param {import("@babel/types").BinaryExpression} node - The Babel AST node.
530
+ * @returns {string} Stringification of the node.
531
+ */
532
+ BinaryExpression(node) {
533
+ const {left, operator, right} = node;
534
+ const left_ = this.toSource(left);
535
+ const right_ = this.toSource(right);
536
+ return `${left_} ${operator} ${right_}`;
537
+ }
538
+ /**
539
+ * @param {import("@babel/types").ThisExpression} node - The Babel AST node.
540
+ * @returns {string} Stringification of the node.
541
+ */
542
+ ThisExpression(node) {
543
+ return 'this';
544
+ }
545
+ /**
546
+ * @param {import("@babel/types").ArrayExpression} node - The Babel AST node.
547
+ * @returns {string} Stringification of the node.
548
+ */
549
+ ArrayExpression(node) {
550
+ const {elements, extra} = node;
551
+ const e = !!extra?.trailingComma ? ',' : '';
552
+ return '[' + this.mapToSource(elements).join(', ') + e + ']';
553
+ }
554
+ /**
555
+ * @param {import("@babel/types").VariableDeclaration} node - The Babel AST node.
556
+ * @returns {string} Stringification of the node.
557
+ */
558
+ VariableDeclaration(node) {
559
+ const {declarations, kind} = node;
560
+ let spaces = '';
561
+ let semicolon = '';
562
+ if (this.needSpaces) {
563
+ semicolon = ';';
564
+ spaces = this.spaces;
565
+ }
566
+ return `${spaces}${kind} ${this.mapToSource(declarations).join(', ')}${semicolon}`;
567
+ }
568
+ /**
569
+ * @param {import("@babel/types").VariableDeclarator} node - The Babel AST node.
570
+ * @returns {string} Stringification of the node.
571
+ */
572
+ VariableDeclarator(node) {
573
+ const {id, init} = node;
574
+ if (init) {
575
+ return this.toSource(id) + ' = ' + this.toSource(init);
576
+ }
577
+ return this.toSource(id);
578
+ }
579
+ /**
580
+ * @param {import("@babel/types").ConditionalExpression} node - The Babel AST node.
581
+ * @returns {string} Stringification of the node.
582
+ */
583
+ ConditionalExpression(node) {
584
+ const {alternate, consequent, test} = node;
585
+ return `${this.toSource(test)} ? ${this.toSource(consequent)} : ${this.toSource(alternate)}`;
586
+ }
587
+ /**
588
+ * if (...)
589
+ *
590
+ * @param {import("@babel/types").LogicalExpression} node - The Babel AST node.
591
+ * @returns {string} Stringification of the node.
592
+ */
593
+ LogicalExpression(node) {
594
+ const {left, operator, right} = node;
595
+ const l = this.toSource(left);
596
+ const r = this.toSource(right);
597
+ if (l === '') {
598
+ console.warn("LogicalExpression> unhandled empty left", node);
599
+ }
600
+ if (r === '') {
601
+ console.warn("LogicalExpression> unhandled empty right", node);
602
+ }
603
+ return `${l} ${operator} ${r}`;
604
+ }
605
+ /**
606
+ * TODO TEST: can init be undefined in for(;;)
607
+ *
608
+ * @param {import("@babel/types").ForStatement} node - The Babel AST node.
609
+ * @returns {string} Stringification of the node.
610
+ */
611
+ ForStatement(node) {
612
+ const {init, test, update, body} = node;
613
+ const spaces = this.spaces;
614
+ const i = this.toSource(init);
615
+ const t = this.toSource(test);
616
+ const u = this.toSource(update);
617
+ const b = this.toSourceCurly(body);
618
+ return `${spaces}for (${i}; ${t}; ${u})${b}`;
619
+ }
620
+ /**
621
+ * showAST("++i")
622
+ *
623
+ * @param {import("@babel/types").UpdateExpression} node - The Babel AST node.
624
+ * @returns {string} Stringification of the node.
625
+ */
626
+ UpdateExpression(node) {
627
+ const {operator, prefix, argument} = node;
628
+ if (prefix) {
629
+ return `${operator}${this.toSource(argument)}`;
630
+ } else {
631
+ return `${this.toSource(argument)}${operator}`;
632
+ }
633
+ }
634
+ /**
635
+ * @param {import("@babel/types").NewExpression} node - The Babel AST node.
636
+ * @returns {string} Stringification of the node.
637
+ */
638
+ NewExpression(node) {
639
+ const {callee, arguments: args_} = node;
640
+ const c = this.toSource(callee);
641
+ const args = this.mapToSource(args_).join(', ');
642
+ return `new ${c}(${args})`;
643
+ }
644
+ /**
645
+ * @param {import("@babel/types").ClassDeclaration} node - The Babel AST node.
646
+ * @returns {string} Stringification of the node.
647
+ */
648
+ ClassDeclaration(node) {
649
+ const {id, superClass, body, trailingComments, leadingComments} = node;
650
+ const spaces = this.spaces;
651
+ let out = spaces + 'class ' + this.toSource(id);
652
+ if (superClass) {
653
+ out += ` extends ${this.toSource(superClass)}`
654
+ }
655
+ out += ' {\n';
656
+ out += this.toSource(body);
657
+ out += spaces;
658
+ out += '\n}\n';
659
+ return out;
660
+ }
661
+ /**
662
+ * @example
663
+ * console.log(ast2json(parseSync("`${1} b ${2+3}c`").program.body[0]));
664
+ * @param {import("@babel/types").TemplateLiteral} node - The Babel AST node.
665
+ * @returns {string} Stringification of the node.
666
+ */
667
+ TemplateLiteral(node) {
668
+ const {expressions, quasis} = node;
669
+ let out = '`';
670
+ for (var i=0; i<quasis.length; i++) {
671
+ out += this.toSource(quasis[i]);
672
+ if (expressions[i]) {
673
+ out += '${' + this.toSource(expressions[i]) + '}';
674
+ }
675
+ }
676
+ out += '`';
677
+ return out ;
678
+ }
679
+ /**
680
+ * @param {import("@babel/types").TemplateElement} node - The Babel AST node.
681
+ * @returns {string} Stringification of the node.
682
+ */
683
+ TemplateElement(node) {
684
+ const {value} = node;
685
+ return value.raw;
686
+ }
687
+ /**
688
+ * @param {import("@babel/types").ContinueStatement} node - The Babel AST node.
689
+ * @returns {string} Stringification of the node.
690
+ */
691
+ ContinueStatement(node) {
692
+ const {label} = node;
693
+ let out = this.spaces + 'continue';
694
+ if (label) {
695
+ out += ' ' + this.toSource(label);
696
+ }
697
+ out += ';';
698
+ return out;
699
+ }
700
+ /**
701
+ * @param {import("@babel/types").ClassBody} node - The Babel AST node.
702
+ * @returns {string} Stringification of the node.
703
+ */
704
+ ClassBody(node) {
705
+ const {body} = node;
706
+ return this.mapToSource(body).join('\n');
707
+ }
708
+ /**
709
+ * @param {import("@babel/types").ClassMethod} node - The Babel AST node.
710
+ * @returns {string} Stringification of the node.
711
+ */
712
+ ClassMethod(node) {
713
+ const {static: static_, key, computed, kind, id, generator, async, params, body} = node;
714
+ let out = this.spaces;
715
+ if (generator) {
716
+ out += '*';
717
+ }
718
+ if (id) {
719
+ console.warn('Stringifier#ClassMethod> unhandled id', node);
720
+ }
721
+ if (static_) {
722
+ out += 'static ';
723
+ }
724
+ if (async) {
725
+ out += 'async ';
726
+ }
727
+ if (kind === 'get') {
728
+ out += 'get ';
729
+ } else if (kind === 'set') {
730
+ out += 'set ';
731
+ } else if (kind === 'constructor' || kind === 'method') {
732
+ // Nothing yet.
733
+ } else {
734
+ console.warn("unhandled kind", kind, "for", node);
735
+ }
736
+ let methodName = this.toSource(key);
737
+ if (computed) {
738
+ methodName = `[${methodName}]`;
739
+ }
740
+ out += methodName;
741
+ out += `(${this.mapToSource(params).join(', ')})`;
742
+ out += this.toSource(body);
743
+ return out;
744
+ }
745
+ /**
746
+ * @param {import("@babel/types").ExportAllDeclaration} node - The Babel AST node.
747
+ * @returns {string} Stringification of the node.
748
+ */
749
+ ExportAllDeclaration(node) {
750
+ return `export * from ${node.source.extra.raw};`;
751
+ }
752
+ /**
753
+ * @param {import("@babel/types").ExportNamedDeclaration} node - The Babel AST node.
754
+ * @returns {string} Stringification of the node.
755
+ */
756
+ ExportNamedDeclaration(node) {
757
+ const {declaration, source, specifiers} = node;
758
+ let out = this.spaces;
759
+ if (specifiers.length) {
760
+ if (!source) {
761
+ //debugger;
762
+ }
763
+ out += 'export {\n';
764
+ // todo: fix spacing system
765
+ out += this.mapToSource(specifiers).map(_ => ` ${this.spaces}${_}`).join(',\n');
766
+ out += '\n';
767
+ out += this.spaces;
768
+ out += '}';
769
+ if (source) {
770
+ out += " from " + this.toSource(source);
771
+ }
772
+ out += ";\n";
773
+ } else if (declaration) {
774
+ out += 'export ' + this.toSource(declaration);
775
+ } else {
776
+ console.warn("ExportNamedDeclaration> unhandled case for", node);
777
+ }
778
+ return out;
779
+ }
780
+ /**
781
+ * @param {import("@babel/types").ExportDefaultDeclaration} node - The Babel AST node.
782
+ * @returns {string} Stringification of the node.
783
+ */
784
+ ExportDefaultDeclaration(node) {
785
+ const {declaration} = node;
786
+ const a = this.toSource(declaration);
787
+ return `export default ${a};`;
788
+ }
789
+ /**
790
+ * @param {import("@babel/types").ExportSpecifier} node - The Babel AST node.
791
+ * @returns {string} Stringification of the node.
792
+ */
793
+ ExportSpecifier(node) {
794
+ const {exported, local} = node;
795
+ const left = this.toSource(exported);
796
+ const right = this.toSource(local);
797
+ const {spaces} = this;
798
+ if (left === right) {
799
+ return `${spaces}${left}`;
800
+ }
801
+ // For example:
802
+ // PostEffect: PostEffect$1\n
803
+ // createMesh: createMesh$1\n
804
+ return `${spaces}${right} as ${left}`;
805
+ }
806
+ /**
807
+ * @param {import("@babel/types").Super} node - The Babel AST node.
808
+ * @returns {string} Stringification of the node.
809
+ */
810
+ Super(node) {
811
+ return 'super';
812
+ }
813
+ /**
814
+ * @param {import("@babel/types").ForInStatement} node - The Babel AST node.
815
+ * @returns {string} Stringification of the node.
816
+ */
817
+ ForInStatement(node) {
818
+ const {left, right, body} = node;
819
+ const {spaces} = this;
820
+ const l = this.toSource(left);
821
+ const r = this.toSource(right);
822
+ const b = this.toSourceCurly(body);
823
+ return `${spaces}for (${l} in ${r})${b}`;
824
+ }
825
+ /**
826
+ * @param {import("@babel/types").ThrowStatement} node - The Babel AST node.
827
+ * @returns {string} Stringification of the node.
828
+ */
829
+ ThrowStatement(node) {
830
+ const {argument} = node;
831
+ const {spaces} = this;
832
+ const arg = this.toSource(argument);
833
+ return `${spaces}throw ${arg};`;
834
+ }
835
+ /**
836
+ * @param {import("@babel/types").WhileStatement} node - The Babel AST node.
837
+ * @returns {string} Stringification of the node.
838
+ */
839
+ WhileStatement(node) {
840
+ const {test, body} = node;
841
+ const {spaces} = this;
842
+ const t = this.toSource(test);
843
+ const b = this.toSourceCurly(body);
844
+ return `${spaces}while (${t})${b}`;
845
+ }
846
+ /**
847
+ * @param {import("@babel/types").BreakStatement} node - The Babel AST node.
848
+ * @returns {string} Stringification of the node.
849
+ */
850
+ BreakStatement(node) {
851
+ const {label} = node;
852
+ let out = this.spaces + 'break';
853
+ if (label) {
854
+ out += ' ' + this.toSource(label);
855
+ }
856
+ out += ';';
857
+ return out;
858
+ }
859
+ /**
860
+ * @param {import("@babel/types").ForOfStatement} node - The Babel AST node.
861
+ * @returns {string} Stringification of the node.
862
+ */
863
+ ForOfStatement(node) {
864
+ const {await: await_, left, right, body} = node;
865
+ const {spaces} = this;
866
+ const l = this.toSource(left);
867
+ const r = this.toSource(right);
868
+ const b = this.toSourceCurly(body);
869
+ const a = await_ ? 'await ' : '';
870
+ return `${spaces}for ${a}(${l} of ${r})${b}`;
871
+ }
872
+ /**
873
+ * for (const [a, b] in c)
874
+ * --> [a, b] is the array pattern
875
+ *
876
+ * @param {import("@babel/types").ArrayPattern} node - The Babel AST node.
877
+ * @returns {string} Stringification of the node.
878
+ */
879
+ ArrayPattern(node) {
880
+ const {elements} = node;
881
+ const e = this.mapToSource(elements).join(', ');
882
+ return `[${e}]`;
883
+ }
884
+ /**
885
+ * @param {import("@babel/types").SwitchStatement} node - The Babel AST node.
886
+ * @returns {string} Stringification of the node.
887
+ */
888
+ SwitchStatement(node) {
889
+ const {discriminant, cases} = node;
890
+ const {spaces} = this;
891
+ let out = '';
892
+ out += spaces + `switch (${this.toSource(discriminant)}) {\n`;
893
+ out += this.mapToSource(cases).join('\n') + '\n';
894
+ out += spaces + '}';
895
+ return out;
896
+ }
897
+ /**
898
+ * @param {import("@babel/types").SwitchCase} node - The Babel AST node.
899
+ * @returns {string} Stringification of the node.
900
+ */
901
+ SwitchCase(node) {
902
+ const {consequent, test} = node;
903
+ const {spaces} = this;
904
+ const c = this.mapToSource(consequent).join('\n');
905
+ if (test) {
906
+ const t = this.toSource(test);
907
+ return `${spaces}case ${t}:\n${c}`;
908
+ }
909
+ return `${spaces}default:\n${c}`;
910
+ }
911
+ /**
912
+ * @param {import("@babel/types").RegExpLiteral} node - The Babel AST node.
913
+ * @returns {string} Stringification of the node.
914
+ */
915
+ RegExpLiteral(node) {
916
+ // parseSync("/test/gm")
917
+ // todo figure out why it always exposes node.value === undefined... oversight in Babel?
918
+ const {extra, value, pattern, flags} = node;
919
+ return extra.raw;
920
+ }
921
+ /**
922
+ * for (var i=0, n=arr.length; i<n; i++)
923
+ * sequence expression: var i=0, n=arr.length
924
+ *
925
+ * @param {import("@babel/types").SequenceExpression} node - The Babel AST node.
926
+ * @returns {string} Stringification of the node.
927
+ */
928
+ SequenceExpression(node) {
929
+ const {expressions} = node;
930
+ return this.mapToSource(expressions).join(', ');
931
+ }
932
+ /**
933
+ * showAST("if (true);");
934
+ *
935
+ * @param {import("@babel/types").EmptyStatement} node - The Babel AST node.
936
+ * @returns {string} Stringification of the node.
937
+ */
938
+ EmptyStatement(node) {
939
+ return ';';
940
+ }
941
+ /**
942
+ * @param {import("@babel/types").SpreadElement} node - The Babel AST node.
943
+ * @returns {string} Stringification of the node.
944
+ */
945
+ SpreadElement(node) {
946
+ const {argument} = node;
947
+ const a = this.toSource(argument);
948
+ return `...${a}`;
949
+ }
950
+ /**
951
+ * @param {import("@babel/types").ObjectMethod} node - The Babel AST node.
952
+ * @returns {string} Stringification of the node.
953
+ */
954
+ ObjectMethod(node) {
955
+ // @todo PR in Babel why method/id is a key in node... (seems like a bug/oversight)
956
+ // method === true just indicates kind === 'method'
957
+ const {method, key, computed, kind, id, generator, async, params, body} = node;
958
+ if (id !== null) {
959
+ console.warn("ObjectMethod> id !== null is unhandled", node);
960
+ debugger;
961
+ }
962
+ // if (method) {
963
+ // console.warn("ObjectMethod> node was a method", node);
964
+ // debugger;
965
+ // }
966
+ let out = this.spaces;
967
+ if (generator) {
968
+ out += '*';
969
+ }
970
+ if (id) {
971
+ console.warn('Stringifier#ClassMethod> unhandled id', node);
972
+ }
973
+ if (async) {
974
+ out += 'async ';
975
+ }
976
+ if (kind === 'get') {
977
+ out += 'get ';
978
+ } else if (kind === 'set') {
979
+ out += 'set ';
980
+ } else if (kind === 'method') {
981
+ // Nothing yet.
982
+ } else {
983
+ console.warn("unhandled kind", kind, "for", node);
984
+ }
985
+ let methodName = this.toSource(key);
986
+ if (computed) {
987
+ methodName = `[${methodName}]`;
988
+ }
989
+ out += methodName;
990
+ out += `(${this.mapToSource(params).join(', ')})`;
991
+ out += this.toSource(body);
992
+ return out;
993
+ }
994
+ /**
995
+ * E.g. function testComma({x,y,z,}) {}
996
+ * @param {import("@babel/types").ObjectPattern} node - The Babel AST node.
997
+ * @returns {string} Stringification of the node.
998
+ */
999
+ ObjectPattern(node) {
1000
+ const {properties, extra} = node;
1001
+ let out = '{';
1002
+ if (properties.length) {
1003
+ out += '\n';
1004
+ out += this.mapToSource(properties).join(',\n');
1005
+ if (!!extra?.trailingComma) {
1006
+ out += ',';
1007
+ }
1008
+ out += '\n';
1009
+ out += this.spaces.slice(2);
1010
+ }
1011
+ out += '}';
1012
+ return out;
1013
+ }
1014
+ /**
1015
+ * > x?.y
1016
+ * > x?.y.z
1017
+ * > x[y?.z]
1018
+ * > x?.[y?.z]
1019
+ * > b?.file?.variants[variant]
1020
+ *
1021
+ * @param {import("@babel/types").OptionalMemberExpression} node - The Babel AST node.
1022
+ * @returns {string} Stringification of the node.
1023
+ */
1024
+ OptionalMemberExpression(node) {
1025
+ const {object, computed, property, optional} = node;
1026
+ const a = this.toSource(object);
1027
+ const b = this.toSource(property);
1028
+ // Basically four cases: computed=true/false optional=true/false, 00, 01, 10, 11
1029
+ if (!computed && !optional) {
1030
+ return `${a}.${b}`;
1031
+ } else if (!computed && optional) {
1032
+ return `${a}?.${b}`;
1033
+ } else if (computed && !optional) {
1034
+ return `${a}[${b}]`;
1035
+ }
1036
+ // Can only be case 4 now (computed && optional):
1037
+ return `${a}?.[${b}]`;
1038
+ }
1039
+ /**
1040
+ * > version?.indexOf('$');
1041
+ * > version?.indexOf?.('$');
1042
+ * > this.passEncoder?.pushDebugGroup(name);
1043
+ *
1044
+ * @param {import("@babel/types").OptionalCallExpression} node - The Babel AST node.
1045
+ * @returns {string} Stringification of the node.
1046
+ */
1047
+ OptionalCallExpression(node) {
1048
+ const {callee, optional, arguments: args} = node;
1049
+ const a = this.toSource(callee);
1050
+ const b = this.mapToSource(args);
1051
+ if (optional) {
1052
+ return `${a}?.(${b})`;
1053
+ }
1054
+ return `${a}(${b})`;
1055
+ }
1056
+ /**
1057
+ * @param {import("@babel/types").DoWhileStatement} node - The Babel AST node.
1058
+ * @returns {string} Stringification of the node.
1059
+ */
1060
+ DoWhileStatement(node) {
1061
+ const {body, test, trailingComments} = node;
1062
+ const {spaces} = this;
1063
+ let out = spaces;
1064
+ out += "do ";
1065
+ out += this.toSourceCurly(body);
1066
+ out += ` while (${this.toSource(test)});`;
1067
+ return out;
1068
+ }
1069
+ /**
1070
+ * @param {import("@babel/types").TryStatement} node - The Babel AST node.
1071
+ * @returns {string} Stringification of the node.
1072
+ */
1073
+ TryStatement(node) {
1074
+ const {block, handler, finalizer} = node;
1075
+ let out = this.spaces;
1076
+ const b = this.toSource(block);
1077
+ out += `try ${b}`;
1078
+ if (handler) {
1079
+ out += this.toSource(handler);
1080
+ }
1081
+ if (finalizer) {
1082
+ out += 'finally' + this.toSource(finalizer);
1083
+ }
1084
+ return out;
1085
+ }
1086
+ /**
1087
+ * @param {import("@babel/types").CatchClause} node - The Babel AST node.
1088
+ * @returns {string} Stringification of the node.
1089
+ */
1090
+ CatchClause(node) {
1091
+ const {param, body} = node;
1092
+ const b = this.toSource(body);
1093
+ if (param) {
1094
+ const p = this.toSource(param);
1095
+ return ` catch (${p}) ${b}`;
1096
+ }
1097
+ // Example: try { 1n / 0 } catch {}
1098
+ return ` catch ${b}`;
1099
+ }
1100
+ /**
1101
+ * @param {import("@babel/types").RestElement} node - The Babel AST node.
1102
+ * @returns {string} Stringification of the node.
1103
+ */
1104
+ RestElement(node) {
1105
+ const {argument} = node;
1106
+ return `...${this.toSource(argument)}`;
1107
+ }
1108
+ /**
1109
+ * @param {import("@babel/types").DebuggerStatement} node - The Babel AST node.
1110
+ * @returns {string} Stringification of the node.
1111
+ */
1112
+ DebuggerStatement(node) {
1113
+ return `${this.spaces}debugger;`;
1114
+ }
1115
+ /**
1116
+ * @param {import("@babel/types").CommentBlock} node - The Babel AST node.
1117
+ * @returns {string} Stringification of the node.
1118
+ */
1119
+ CommentBlock(node) {
1120
+ const {value} = node;
1121
+ const par = this.parents[this.parents.length - 3];
1122
+ const out = `${this.spaces.slice(2)}/*${value}*/`;
1123
+ if (par?.type === 'BlockStatement' || par?.type === 'Program') {
1124
+ return out + '\n';
1125
+ }
1126
+ return ' ' + out + ' ';
1127
+ }
1128
+ /**
1129
+ * @param {import("@babel/types").CommentLine} node - The Babel AST node.
1130
+ * @returns {string} Stringification of the node.
1131
+ */
1132
+ CommentLine(node) {
1133
+ const {value} = node;
1134
+ return `${this.spaces.slice(2)}//${value}\n`;
1135
+ }
1136
+ /**
1137
+ * @param {import("@babel/types").ImportDeclaration} node - The Babel AST node.
1138
+ * @returns {string} Stringification of the node.
1139
+ */
1140
+ ImportDeclaration(node) {
1141
+ const {specifiers, source} = node;
1142
+ // ImportNamespaceSpecifier: import * as a from "b";
1143
+ // ImportDefaultSpecifier : import a from "b";
1144
+ // ImportSpecifier : import { a } from "b";
1145
+ const a = this.mapToSource(specifiers).join(', ');
1146
+ const b = this.toSource(source);
1147
+ if (specifiers.length === 0) {
1148
+ return `import ${b}`;
1149
+ }
1150
+ if (specifiers[0].type !== 'ImportSpecifier') {
1151
+ return `import ${a} from ${b};`;
1152
+ }
1153
+ return `import {${a}} from ${b};`;
1154
+ }
1155
+ /**
1156
+ * @param {import("@babel/types").ImportSpecifier} node - The Babel AST node.
1157
+ * @returns {string} Stringification of the node.
1158
+ */
1159
+ ImportSpecifier(node) {
1160
+ const {imported, local} = node;
1161
+ const a = this.toSource(imported);
1162
+ const b = this.toSource(local);
1163
+ if (a !== b) {
1164
+ return `${a} as ${b}`;
1165
+ }
1166
+ return a;
1167
+ }
1168
+ /**
1169
+ * @param {import("@babel/types").ImportDefaultSpecifier} node - The Babel AST node.
1170
+ * @returns {string} Stringification of the node.
1171
+ */
1172
+ ImportDefaultSpecifier(node) {
1173
+ const {local} = node;
1174
+ return this.toSource(local);
1175
+ }
1176
+ /**
1177
+ * @param {import("@babel/types").ImportNamespaceSpecifier} node - The Babel AST node.
1178
+ * @returns {string} Stringification of the node.
1179
+ */
1180
+ ImportNamespaceSpecifier(node) {
1181
+ const {local} = node;
1182
+ return `* as ${this.toSource(local)}`;
1183
+ }
1184
+ /**
1185
+ * @param {import("@babel/types").File} node - The Babel AST node.
1186
+ * @returns {string} Stringification of the node.
1187
+ */
1188
+ File(node) {
1189
+ return this.toSource(node.program) + '\n';
1190
+ }
1191
+ /**
1192
+ * @param {import("@babel/types").Program} node - The Babel AST node.
1193
+ * @returns {string} Stringification of the node.
1194
+ */
1195
+ Program(node) {
1196
+ const {sourceType, interpreter, body, directives} = node;
1197
+ let out = '';
1198
+ // @todo I would like to keep comments above and below,
1199
+ // but below one is currently dropped (does't matter for AST)
1200
+ // See: test/typechecking/directive.mjs
1201
+ out += this.mapToSource(directives);
1202
+ out += this.mapToSource(body).join('\n');
1203
+ return out;
1204
+ }
1205
+ /**
1206
+ * @param {import("@babel/types").StringLiteral} node - The Babel AST node.
1207
+ * @returns {string} Stringification of the node.
1208
+ */
1209
+ StringLiteral(node) {
1210
+ const {extra} = node;
1211
+ // Never experienced this so far, but types are types...
1212
+ if (!extra) {
1213
+ debugger;
1214
+ return '';
1215
+ }
1216
+ if (typeof extra.raw !== 'string') {
1217
+ debugger;
1218
+ return '';
1219
+ }
1220
+ return extra.raw;
1221
+ }
1222
+ /**
1223
+ * @param {import("@babel/types").NumericLiteral} node - The Babel AST node.
1224
+ * @returns {string} Stringification of the node.
1225
+ */
1226
+ NumericLiteral(node) {
1227
+ return node.extra.raw;
1228
+ }
1229
+ /**
1230
+ * @param {import("@babel/types").AssignmentPattern} node - The Babel AST node.
1231
+ * @returns {string} Stringification of the node.
1232
+ */
1233
+ AssignmentPattern(node) {
1234
+ const {left, right} = node;
1235
+ return `${this.toSource(left)} = ${this.toSource(right)}`;
1236
+ }
1237
+ /**
1238
+ * @param {import("@babel/types").NullLiteral} node - The Babel AST node.
1239
+ * @returns {string} Stringification of the node.
1240
+ */
1241
+ NullLiteral(node) {
1242
+ return 'null';
1243
+ }
1244
+ /**
1245
+ * @param {import("@babel/types").TaggedTemplateExpression} node - The Babel AST node.
1246
+ * @returns {string} Stringification of the node.
1247
+ */
1248
+ TaggedTemplateExpression(node) {
1249
+ const {tag, quasi} = node;
1250
+ const t = this.toSource(tag);
1251
+ const q = this.toSource(quasi);
1252
+ return t + q;
1253
+ }
1254
+ /**
1255
+ * @param {import("@babel/types").YieldExpression} node - The Babel AST node.
1256
+ * @returns {string} Stringification of the node.
1257
+ */
1258
+ YieldExpression(node) {
1259
+ const {delegate, argument} = node;
1260
+ let keyword = 'yield';
1261
+ if (delegate) {
1262
+ keyword += '*';
1263
+ }
1264
+ const a = this.toSource(argument);
1265
+ return `${keyword} ${a}`;
1266
+ }
1267
+ }
1268
+ export {Stringifier};