@runtime-type-inspector/transpiler 2.2.2 → 2.2.4

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 (4) hide show
  1. package/index.cjs +1068 -35
  2. package/index.mjs +1063 -33
  3. package/package.json +3 -3
  4. package/types.d.ts +0 -970
package/index.cjs CHANGED
@@ -258,11 +258,47 @@
258
258
  return typeof key === "symbol" ? key : String(key);
259
259
  }
260
260
 
261
+ /**
262
+ * @todo expandTypeDepFree doesn't support "complicated" types.
263
+ * For actual builds, we use expandType() anyway (which is based on TypeScript).
264
+ * But since TypeScript is a huge dependency, I'm looking into BabelFlow/BabelTypescript parser.
265
+ * Comparing AST's like this usually helps to find bugs or potential issues,
266
+ * while we can benchmark for best performance too.
267
+ * @example
268
+ * const tooComplex = 'Array<string|{chunks?: undefined|Array<{language: string|null, timestamp: Array<number|null>, text: string}>}>';
269
+ * console.log(expandTypeDepFree(tooComplex));
270
+ */
271
+ /**
272
+ * @typedef {object} ExpandTypeReturnValue
273
+ * @property {'array' | 'union' | 'record' | 'tuple' | 'object' | 'promise' | 'typeof'} type - The type.
274
+ * @property {object | string} [elementType] - For Array.
275
+ * @property {object | string} [key] - For Record<key, val>
276
+ * @property {object | string} [val] - For Record<key, val>
277
+ * @property {(object | string)[]} [members] - For unions.
278
+ * @property {object | string} [properties] - For objects.
279
+ * @property {(object | string)[]} [elements] - For tuples.
280
+ * @property {object | string} [argument] - For typeof.
281
+ */
282
+ /**
283
+ * 'DepFree' refers to the fact that this function has no dependencies,
284
+ * while `expandType` depends on TypeScript itself for maximum compatibility.
285
+ * @example
286
+ * expandTypeDepFree('(123) '); // Outputs: '123'
287
+ * expandTypeDepFree('Array<number> '); // Outputs: { type: 'array', elementType: 'number' }
288
+ * expandTypeDepFree('Array<(123) > '); // Outputs: { type: 'array', elementType: '123' }
289
+ * expandTypeDepFree(' ( ( 123 ) ) '); // Outputs: '123'
290
+ * expandTypeDepFree(' (string ) |(number ) '); // Outputs: { type: 'union', members: ['string', 'number'] }
291
+ * expandTypeDepFree(' (( Object ) ) '); // Outputs: { type: 'object', properties: {} }
292
+ * @param {string} type - The input type to expand.
293
+ * @returns {string | ExpandTypeReturnValue} Object containing parsed information from type string.
294
+ */
261
295
  function expandTypeDepFree(type) {
262
296
  type = type.trim();
297
+ // '(123)' -> '123'
263
298
  while (!type.includes('|') && type[0] === '(' && type[type.length - 1] === ')') {
264
299
  type = type.slice(1, -1).trim();
265
300
  }
301
+ // (1) Rest parameters like ...string
266
302
  if (type[0] === '.' && type[1] === '.' && type[2] === '.') {
267
303
  var elementType = type.slice(3);
268
304
  return {
@@ -270,6 +306,8 @@
270
306
  elementType: elementType
271
307
  };
272
308
  }
309
+ // (2)
310
+ // Array<...>
273
311
  if (type.startsWith("Array<") && type.endsWith('>')) {
274
312
  var typeSlice = type.slice(6, -1);
275
313
  var _elementType = expandTypeDepFree(typeSlice);
@@ -278,6 +316,7 @@
278
316
  elementType: _elementType
279
317
  };
280
318
  }
319
+ // Promise<...>
281
320
  if (type.startsWith("Promise<") && type.endsWith('>')) {
282
321
  var _typeSlice = type.slice(8, -1);
283
322
  var _elementType2 = expandTypeDepFree(_typeSlice);
@@ -286,6 +325,7 @@
286
325
  elementType: _elementType2
287
326
  };
288
327
  }
328
+ // (3) Object<...> or Record<...>
289
329
  if ((type.startsWith("Object<") || type.startsWith("Record<")) && type.endsWith('>')) {
290
330
  var recordSlice = type.slice(7, -1);
291
331
  var firstComma = recordSlice.indexOf(',');
@@ -300,8 +340,9 @@
300
340
  val: expandTypeDepFree(val)
301
341
  };
302
342
  }
343
+ // (4) {...}
303
344
  if (type[0] === '{' && type[type.length - 1] === '}') {
304
- var propertiesArray = type.slice(1, -1).split(',');
345
+ var propertiesArray = type.slice(1, -1).split(','); // ['entity: Entity', ' app: AppBase']
305
346
  var properties = {};
306
347
  propertiesArray.forEach(function (_) {
307
348
  var _$split$map = _.split(":").map(function (_) {
@@ -321,6 +362,7 @@
321
362
  properties: properties
322
363
  };
323
364
  }
365
+ // (5) expand unions
324
366
  var members = type.split("|");
325
367
  if (members.length >= 2) {
326
368
  members.forEach(function (_, i) {
@@ -331,6 +373,8 @@
331
373
  members: members.map(expandTypeDepFree)
332
374
  };
333
375
  }
376
+ // (6) expand [] Arrays
377
+ // Test arrays: new pc.Mat3().set([1, 2, 3, "asd"])
334
378
  if (type.endsWith("[]")) {
335
379
  var _typeSlice2 = type.slice(0, -2);
336
380
  return {
@@ -338,13 +382,15 @@
338
382
  elementType: expandTypeDepFree(_typeSlice2)
339
383
  };
340
384
  }
385
+ // (7) expand tuples
341
386
  if (type[0] === '[' && type[type.length - 1] === ']') {
342
- var elements = type.slice(1, -1).split(',');
387
+ var elements = type.slice(1, -1).split(','); // ['null', ' Texture', ' Texture', ' Texture', ' Texture', ' Texture', ' Texture']
343
388
  return {
344
389
  type: 'tuple',
345
390
  elements: elements.map(expandTypeDepFree)
346
391
  };
347
392
  }
393
+ // (8) expand typeof expressions
348
394
  if (type.startsWith('typeof ')) {
349
395
  var argument = expandTypeDepFree(type.substring(7));
350
396
  return {
@@ -361,6 +407,14 @@
361
407
  return type;
362
408
  }
363
409
 
410
+ /** @typedef {import('@babel/types').Node} Node */
411
+ /** @typedef {import('@babel/types').Function} Function */
412
+ /**
413
+ * Checks if the provided node is a function-like structure.
414
+ *
415
+ * @param {Node} node - The Babel AST node to be tested.
416
+ * @returns {node is Function} - `true` if the node is a function-like structure, otherwise `false`.
417
+ */
364
418
  function nodeIsFunction(node) {
365
419
  switch (node.type) {
366
420
  case 'ArrowFunctionExpression':
@@ -374,12 +428,23 @@
374
428
  return false;
375
429
  }
376
430
 
431
+ /**
432
+ * @typedef DocType
433
+ * @property {boolean} optional - Type is optional.
434
+ */
435
+ /**
436
+ * @param {string | DocType} type - The type.
437
+ * @param {boolean} optional - Optionality
438
+ * @returns {string | DocType} The simplified type.
439
+ */
377
440
  function simplifyType(type, optional) {
441
+ // If it's already an object, just set optionality.
378
442
  if (type instanceof Object) {
379
443
  type.optional = optional;
380
444
  } else if (typeof type === 'string') {
381
445
  type = type.trim();
382
446
  if (type !== 'object' && type !== 'object[]' && type !== 'union' && !optional) {
447
+ // console.log("simplify", type);
383
448
  return type;
384
449
  }
385
450
  type = {
@@ -392,46 +457,68 @@
392
457
  }
393
458
  if (type.type === 'object' && type.properties && Object.keys(type.properties).length === 0) {
394
459
  delete type.properties;
460
+ // console.log("delete empty", type);
395
461
  }
462
+
396
463
  return type;
397
464
  }
398
465
 
466
+ /**
467
+ * Parses JSDoc comments to extract parameter type information.
468
+ *
469
+ * @param {string} src - The JSDoc comment string to parse.
470
+ * @param {Function} [expandType] - An optional function to process the types found in the JSDoc.
471
+ * @returns {Record<string, any> | undefined} An object mapping parameter names to their parsed types, or undefined if no parameters are found.
472
+ */
399
473
  function parseJSDoc(src) {
400
474
  var expandType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : expandTypeDepFree;
475
+ // Parse something like: @param {Object} [kwargs={}] Optional arguments.
401
476
  var regex = /@param \{(.*?)\} ([\[\]a-zA-Z0-9_$=\{\}\.'" ]+)/g;
402
477
  var matches = _toConsumableArray(src.matchAll(regex));
478
+ /** @type {Record<string, any>} */
403
479
  var params = Object.create(null);
404
480
  matches.forEach(function (_) {
405
481
  var type = expandType(_[1].trim());
406
482
  var name = _[2].trim();
407
483
  var optional = false;
484
+ // Examples:
485
+ // name: [kwargs={}] The configuration parameters.
486
+ // name: [d = 1.0] Sample spacing
408
487
  if (name[0] === '[') {
488
+ // Possible improvement: counting opening/closing brackets for perfect match
409
489
  var closer = name.lastIndexOf(']');
490
+ // Afterwards name will be: d = 1.0
410
491
  name = name.substring(1, closer);
492
+ // mark it for the type:
411
493
  optional = true;
412
494
  }
495
+ // Strip the rest (either leftover of optional value or description)
413
496
  name = name.split(' ')[0].split('=')[0].trim();
414
497
  var simplifiedType = simplifyType(type, optional);
415
498
  var parts = name.split(".");
416
499
  if (parts.length === 3) {
417
- var parts0 = parts[0];
418
- var parts1 = parts[1];
419
- var parts2 = parts[2];
500
+ // Something like: @param {number[]} settings.render.skyboxRotation - Rotation of skybox.
501
+ var parts0 = parts[0]; // settings
502
+ var parts1 = parts[1]; // render
503
+ var parts2 = parts[2]; // skyboxRotation
420
504
  var toptype = params[parts0];
421
505
  toptype.properties[parts1].properties = toptype.properties[parts1].properties || {};
422
506
  toptype.properties[parts1].properties[parts2] = simplifiedType;
423
507
  } else if (parts.length === 2) {
424
- var _parts = parts[0];
425
- var _parts2 = parts[1];
508
+ // Something like: @param {number} description[].components
509
+ var _parts = parts[0]; // description[]
510
+ var _parts2 = parts[1]; // components
426
511
  if (_parts.endsWith('[]')) {
427
- _parts = _parts.slice(0, -2);
512
+ _parts = _parts.slice(0, -2); // description[] -> description
428
513
  }
514
+
429
515
  var _toptype = params[_parts];
430
516
  if ((_toptype === null || _toptype === void 0 ? void 0 : _toptype.type) === "union") {
431
517
  var typeObject = _toptype.members.find(function (_) {
432
518
  return (_ === null || _ === void 0 ? void 0 : _.type) === 'object';
433
519
  });
434
520
  typeObject.properties[_parts2] = simplifiedType;
521
+ //typeObject.properties = simplifiedType; // todo add test case
435
522
  } else if ((_toptype === null || _toptype === void 0 ? void 0 : _toptype.type) === "array") {
436
523
  _toptype.elementType.properties[_parts2] = simplifiedType;
437
524
  } else if ((_toptype === null || _toptype === void 0 ? void 0 : _toptype.type) === "object") {
@@ -456,6 +543,12 @@
456
543
  return params;
457
544
  }
458
545
 
546
+ /**
547
+ * @param {string} src - JSDoc comment of the setter.
548
+ * @param {Function} expandType - The expandType function.
549
+ * @returns {string | DocType | undefined} The parsed and possibly expanded type from
550
+ * the JSDoc comment, or undefined if parsing fails to find `@type`.
551
+ */
459
552
  function parseJSDocSetter(src) {
460
553
  var expandType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : expandTypeDepFree;
461
554
  var regex = /@type \{(.*?)\}/g;
@@ -463,23 +556,49 @@
463
556
  if (matches.length === 1) {
464
557
  var match = matches[0];
465
558
  var type = expandType(match[1]);
466
- var simplifiedType = simplifyType(type, false);
559
+ var simplifiedType = simplifyType(type, /* optional */false);
467
560
  return simplifiedType;
468
561
  }
469
562
  }
470
563
 
564
+ /**
565
+ * Extracts the parameter name and its optionality from a JSDoc parameter string.
566
+ *
567
+ * This function takes a rest parameter string from a JSDoc comment, trims it, and determines the parameter's
568
+ * name and whether it is optional. The optionality is inferred based on the presence of square brackets around
569
+ * the parameter name.
570
+ *
571
+ * @param {string} rest - The rest part of a JSDoc parameter string to parse.
572
+ * @returns {[string, boolean]} A tuple where the first element is the name of the parameter,
573
+ * and the second element is a boolean indicating if the parameter is optional.
574
+ */
471
575
  function extractNameAndOptionality(rest) {
472
576
  rest = rest.trim();
473
577
  var optional = false;
578
+ // Examples:
579
+ // name: [kwargs={}] The configuration parameters.
580
+ // name: [d = 1.0] Sample spacing
474
581
  if (rest[0] === '[') {
582
+ // Possible improvement: counting opening/closing brackets for perfect match
475
583
  var closer = rest.lastIndexOf(']');
584
+ // Afterwards name will be: d = 1.0
476
585
  rest = rest.substring(1, closer);
586
+ // mark it for the type:
477
587
  optional = true;
478
588
  }
589
+ // Strip the rest (either leftover of optional value or description)
479
590
  var name = rest.split(' ')[0].split('=')[0].trim();
480
591
  return [name, optional];
481
592
  }
482
593
 
594
+ /**
595
+ * Extracts the content of a string that is delimited by curly braces.
596
+ * @example
597
+ * extractCurlyContent('{ {inner} }'); // Returns: {content: ' {inner} ', nextIndex: 11}
598
+ * @param {string} line - The string to extract from.
599
+ * @returns {{content: string, nextIndex: number}} An object containing the extracted content,
600
+ * and the index of the character immediately following the closing curly brace.
601
+ */
483
602
  function extractCurlyContent(line) {
484
603
  var firstCurly = line.indexOf('{');
485
604
  var k = firstCurly + 1;
@@ -501,6 +620,17 @@
501
620
  nextIndex: k + 1
502
621
  };
503
622
  }
623
+ /**
624
+ * Parses JSDoc comments to extract and expand typedefs and their associated properties.
625
+ *
626
+ * It iterates through the lines of a `CommentBlock` from the Babel AST, looking for `@typedef` and `@property`
627
+ * annotations. When it finds a typedef, it stores it in the `typedefs` record. When it finds a property,
628
+ * it adds it to the last found typedef if it is an object type.
629
+ * @param {Record<string, object>} typedefs - An object to store typedefs, mapping type names to their expanded definitions.
630
+ * @param {Console["warn"]} warn - A warn function used for emitting warnings about non-extensible types.
631
+ * @param {import("@babel/types").Comment} comment - A comment extracted from Babel's AST, expected to be a CommentBlock containing type definitions.
632
+ * @param {Function} expandType - A function that takes a type expression as a string and returns a structured representation of the type.
633
+ */
504
634
  function parseJSDocTypedef(typedefs, warn, comment, expandType) {
505
635
  var type = comment.type,
506
636
  value = comment.value;
@@ -523,13 +653,16 @@
523
653
  def = _extractCurlyContent.content,
524
654
  nextIndex = _extractCurlyContent.nextIndex;
525
655
  var name = line.substring(nextIndex).trim();
656
+ // Drop description
526
657
  name = name.split(' ')[0];
527
658
  lastTypedef = expandType(def);
659
+ // Ignore @typedef's that only refer to themselves in another file (see typedef-overwrite test)
528
660
  if (lastTypedef !== name) {
529
661
  typedefs[name] = lastTypedef;
530
662
  }
531
663
  } else if (line.startsWith('@property')) {
532
664
  var _lastTypedef;
665
+ // class @property
533
666
  if (!lastTypedef) {
534
667
  continue;
535
668
  }
@@ -542,6 +675,7 @@
542
675
  _extractNameAndOption2 = _slicedToArray(_extractNameAndOption, 2),
543
676
  _name = _extractNameAndOption2[0],
544
677
  optional = _extractNameAndOption2[1];
678
+ // console.log({name, optional, propType});
545
679
  var finalType = simplifyType(propType, optional);
546
680
  if (((_lastTypedef = lastTypedef) === null || _lastTypedef === void 0 ? void 0 : _lastTypedef.type) === 'object') {
547
681
  lastTypedef.properties[_name] = finalType;
@@ -560,23 +694,46 @@
560
694
  }
561
695
  }
562
696
 
697
+ /**
698
+ * @typedef Stat
699
+ * @property {number} checked - How often assertions were added to this kind of node.
700
+ * @property {number} unchecked - How often no assertions were added to this kind of node.
701
+ */
702
+ /**
703
+ * @param {Stat} stat - the Stat.
704
+ */
563
705
  function statReset(stat) {
564
706
  stat.checked = 0;
565
707
  stat.unchecked = 0;
566
708
  }
567
709
 
710
+ /**
711
+ * @example
712
+ * trimEndSpaces('test \n '); // Returns: 'test \n'
713
+ * @param {string} str - The input string.
714
+ * @returns {string} Output string without spaces at the end.
715
+ */
568
716
  function trimEndSpaces(str) {
569
717
  var i = str.length - 1;
718
+ // decrement index while character is a space
570
719
  while (str[i] === ' ') {
571
720
  i--;
572
721
  }
722
+ // return string from 0 to non-space character
573
723
  return str.slice(0, i + 1);
574
724
  }
575
725
 
576
- var Stringifier = function () {
726
+ /**
727
+ * @typedef {import("@babel/types").Node} Node
728
+ */
729
+ /**
730
+ * Class for converting AST into string.
731
+ */
732
+ var Stringifier = /*#__PURE__*/function () {
577
733
  function Stringifier() {
578
734
  _classCallCheck(this, Stringifier);
579
735
  _defineProperty(this, "forceCurly", false);
736
+ /** @type {Node[]} */
580
737
  _defineProperty(this, "parents", []);
581
738
  _defineProperty(this, "lastCommentBlockIndex", -1);
582
739
  _defineProperty(this, "lastCommentLineIndex", -1);
@@ -584,9 +741,19 @@
584
741
  }
585
742
  _createClass(Stringifier, [{
586
743
  key: "toSource",
587
- value: function toSource(node) {
744
+ value:
745
+ /**
746
+ * @param {Node} node - The Babel AST node.
747
+ * @returns {string} Stringification of the node.
748
+ */
749
+ function toSource(node) {
588
750
  var _node$extra;
751
+ // handle this case only temporarily
589
752
  if (node === null) {
753
+ // Contexts like:
754
+ // Object.assign(Channel3d.prototype, {
755
+ // setPosition: function /*null*/(position) {
756
+ //return '/*null*/';
590
757
  return '';
591
758
  }
592
759
  var leadingComments = node.leadingComments,
@@ -598,6 +765,7 @@
598
765
  var out = '';
599
766
  var comments = '';
600
767
  if (leadingComments) {
768
+ // comments += this.mapToSource(leadingComments).join('');
601
769
  comments = this.leadingCommentsToSource(leadingComments);
602
770
  }
603
771
  if (node !== null && node !== void 0 && (_node$extra = node.extra) !== null && _node$extra !== void 0 && _node$extra.parenthesized) {
@@ -608,9 +776,17 @@
608
776
  if (trailingComments) {
609
777
  out += this.trailingCommentsToSource(trailingComments);
610
778
  }
779
+ // leadingComments and trailingComments lead to duplicates, not always tho
780
+ //if (node && node.trailingComments) {
781
+ // out += this.mapToSource(node.trailingComments).join('\n') + '\n';
782
+ //}
611
783
  this.parents.pop();
612
784
  return out;
613
785
  }
786
+ /**
787
+ * @param {Node} node - The Babel AST node.
788
+ * @returns {string} Stringification of the node.
789
+ */
614
790
  }, {
615
791
  key: "toSource_",
616
792
  value: function toSource_(node) {
@@ -637,21 +813,30 @@
637
813
  }, {
638
814
  key: "parentProvidesSpaces",
639
815
  value: function parentProvidesSpaces(reverseIndex) {
816
+ // May look like: .../ArrayExpression/StringLiteral/CommentLine
640
817
  var parents = this.parents;
641
818
  var parent = parents[parents.length - reverseIndex];
819
+ // console.log("Got parent", parent.type);
642
820
  return (parent === null || parent === void 0 ? void 0 : parent.type) === 'ArrayExpression';
643
821
  }
644
822
  }, {
645
823
  key: "CommentBlock",
646
- value: function CommentBlock(node) {
824
+ value:
825
+ /**
826
+ * @param {import("@babel/types").CommentBlock} node - The Babel AST node.
827
+ * @returns {string} Stringification of the node.
828
+ */
829
+ function CommentBlock(node) {
647
830
  var loc = node.loc;
648
831
  var value = node.value;
649
832
  if (this.lastCommentBlockIndex === loc.start.index) {
833
+ // console.log("CommentBlock> ignore double");
650
834
  return '';
651
835
  }
652
836
  this.lastCommentBlockIndex = loc.start.index;
653
837
  var spaces = this.spaces;
654
838
  var out = '';
839
+ /** @todo add option for number-of-spaces */
655
840
  var dedicatedLine = spaces.length === loc.start.column;
656
841
  if (dedicatedLine) {
657
842
  out += spaces;
@@ -659,6 +844,7 @@
659
844
  var multiLine = loc.start.line !== loc.end.line;
660
845
  if (multiLine) {
661
846
  var _this$parents$at;
847
+ // console.log(this.parents.at(-2)?.type === 'AssignmentExpression');
662
848
  if (((_this$parents$at = this.parents.at(-2)) === null || _this$parents$at === void 0 ? void 0 : _this$parents$at.type) === 'AssignmentExpression') {
663
849
  spaces += ' ';
664
850
  }
@@ -666,9 +852,13 @@
666
852
  }
667
853
  out += '/*';
668
854
  if (value.includes('\n')) {
855
+ // A bit tricky to handle multiline comments,
856
+ // we have to remove the given indentation level.
669
857
  value = trimEndSpaces(value.replace(/^\s*\*/gm, '*')).split('\n').filter(function (_) {
670
858
  return _.length;
671
- }).map(function (line, i) {
859
+ }) // skip empty lines
860
+ // Skip spaces in first line for /**
861
+ .map(function (line, i) {
672
862
  return (i ? spaces + ' ' : '') + line;
673
863
  }).join('\n');
674
864
  out += "".concat(value, "\n").concat(spaces, " */");
@@ -684,10 +874,16 @@
684
874
  }
685
875
  }, {
686
876
  key: "CommentLine",
687
- value: function CommentLine(node) {
877
+ value:
878
+ /**
879
+ * @param {import("@babel/types").CommentLine} node - The Babel AST node.
880
+ * @returns {string} Stringification of the node.
881
+ */
882
+ function CommentLine(node) {
688
883
  var value = node.value,
689
884
  loc = node.loc;
690
885
  if (this.lastCommentLineIndex === loc.start.index) {
886
+ // console.log("CommentLine> ignore double");
691
887
  return '';
692
888
  }
693
889
  this.lastCommentLineIndex = loc.start.index;
@@ -712,6 +908,8 @@
712
908
  var out = leadingComments.map(function (_) {
713
909
  return _this.commentToSource(_, 'leading');
714
910
  }).join('');
911
+ // The comments "took" the spaces, which e.g. ArrayExpression added,
912
+ // so we have to add them back now for parents that provide spaces.
715
913
  if (this.parentProvidesSpaces(2)) {
716
914
  out += this.spaces;
717
915
  }
@@ -729,6 +927,7 @@
729
927
  if (trailingComment.type === 'CommentBlock') {
730
928
  var loc = trailingComment.loc;
731
929
  var dedicatedLine = this.spaces.length === loc.start.column;
930
+ // out += ` /*dedicatedLine=${dedicatedLine}*/ `;
732
931
  if (dedicatedLine) {
733
932
  out += '\n';
734
933
  } else {
@@ -744,10 +943,16 @@
744
943
  }
745
944
  return out;
746
945
  }
946
+ /**
947
+ * @param {*} comment - The comment "node" (not a real Babel Node node though, hence this special treatment)
948
+ * @param {'leading'|'trailing'} pos - The position, either 'leading' or 'trailing'.
949
+ * @returns {string} The comment "node" as a string.
950
+ */
747
951
  }, {
748
952
  key: "commentToSource",
749
953
  value: function commentToSource(comment, pos) {
750
954
  if (comment.type === 'CommentBlock') {
955
+ //if (pos === 'leading') {}
751
956
  return this.CommentBlock(comment);
752
957
  } else if (comment.type === 'CommentLine') {
753
958
  return this.CommentLine(comment);
@@ -756,6 +961,12 @@
756
961
  debugger;
757
962
  return '';
758
963
  }
964
+ /**
965
+ * Only add { and } when requested (e.g. for Asserter).
966
+ * showAST("if (true) 2;") vs showAST("if (true) {2}")
967
+ * @param {Node} node - The Babel AST node.
968
+ * @returns {string} Stringification of the node.
969
+ */
759
970
  }, {
760
971
  key: "toSourceCurly",
761
972
  value: function toSourceCurly(node) {
@@ -768,7 +979,10 @@
768
979
  var out = '';
769
980
  if (needCurly) {
770
981
  out += ' {\n';
982
+ //out += spaces + `/* toSourceCurly> needCurly=${needCurly} type=${type}
983
+ //parents=${parents.map(_=>_.type).join('->')}*/\n`;
771
984
  }
985
+
772
986
  out += this.toSource(node);
773
987
  if (needCurly) {
774
988
  out += '\n';
@@ -794,6 +1008,10 @@
794
1008
  var t = this.parentType;
795
1009
  return t !== "ForStatement" && t !== "ForInStatement" && t !== "ForOfStatement";
796
1010
  }
1011
+ /**
1012
+ * @param {Node[]} arr - Array of nodes to convert.
1013
+ * @returns {string[]} Array of strings for each node.
1014
+ */
797
1015
  }, {
798
1016
  key: "mapToSource",
799
1017
  value: function mapToSource(arr) {
@@ -802,6 +1020,16 @@
802
1020
  return _this2.toSource(_);
803
1021
  });
804
1022
  }
1023
+ /**
1024
+ * Generates a string representing type checks for a given Babel AST node.
1025
+ *
1026
+ * Note: This method serves as a stub and should be overridden in subclasses.
1027
+ * The actual implementation is expected to be provided in Asserter.mjs, where
1028
+ * it would create runtime type assertions based on the AST node provided.
1029
+ *
1030
+ * @param {Node} node - The Babel AST node for which to generate type checks.
1031
+ * @returns {string} A placeholder string, as this stub implementation does nothing; expected to be overridden.
1032
+ */
805
1033
  }, {
806
1034
  key: "generateTypeChecks",
807
1035
  value: function generateTypeChecks(node) {
@@ -809,7 +1037,11 @@
809
1037
  }
810
1038
  }, {
811
1039
  key: "spaces",
812
- get: function get() {
1040
+ get:
1041
+ /**
1042
+ * @type {string} A string of two spaces per indentation.
1043
+ */
1044
+ function get() {
813
1045
  return ' '.repeat(this.numSpaces);
814
1046
  }
815
1047
  }, {
@@ -823,18 +1055,32 @@
823
1055
  }).join('/');
824
1056
  return "".concat(spaces, "// got ").concat(n, " spaces for ").concat(path, "\n");
825
1057
  }
1058
+ /**
1059
+ * > await something();
1060
+ *
1061
+ * @param {import("@babel/types").AwaitExpression} node - The Babel AST node.
1062
+ * @returns {string} Stringification of the node.
1063
+ */
826
1064
  }, {
827
1065
  key: "AwaitExpression",
828
1066
  value: function AwaitExpression(node) {
829
1067
  var argument = node.argument;
830
1068
  return "await ".concat(this.toSource(argument));
831
1069
  }
1070
+ /**
1071
+ * @param {import("@babel/types").ClassBody} node - The Babel AST node.
1072
+ * @returns {string} Stringification of the node.
1073
+ */
832
1074
  }, {
833
1075
  key: "ClassBody",
834
1076
  value: function ClassBody(node) {
835
1077
  var body = node.body;
836
1078
  return this.mapToSource(body).join('\n');
837
1079
  }
1080
+ /**
1081
+ * @param {import("@babel/types").ClassMethod} node - The Babel AST node.
1082
+ * @returns {string} Stringification of the node.
1083
+ */
838
1084
  }, {
839
1085
  key: "ClassMethod",
840
1086
  value: function ClassMethod(node) {
@@ -876,6 +1122,10 @@
876
1122
  out += this.toSource(body);
877
1123
  return out;
878
1124
  }
1125
+ /**
1126
+ * @param {import("@babel/types").ClassExpression} node - The Babel AST node.
1127
+ * @returns {string} Stringification of the node.
1128
+ */
879
1129
  }, {
880
1130
  key: "ClassExpression",
881
1131
  value: function ClassExpression(node) {
@@ -884,6 +1134,7 @@
884
1134
  body = node.body;
885
1135
  var out = 'class ';
886
1136
  if (id !== null) {
1137
+ // Babel: strange API, either null or undefined... pick a type, maybe oversight/bug
887
1138
  out += this.toSource(id) + ' ';
888
1139
  }
889
1140
  if (superClass !== null) {
@@ -894,6 +1145,10 @@
894
1145
  out += "{\n".concat(c, "\n}");
895
1146
  return out;
896
1147
  }
1148
+ /**
1149
+ * @param {import("@babel/types").ClassDeclaration} node - The Babel AST node.
1150
+ * @returns {string} Stringification of the node.
1151
+ */
897
1152
  }, {
898
1153
  key: "ClassDeclaration",
899
1154
  value: function ClassDeclaration(node) {
@@ -915,6 +1170,10 @@
915
1170
  out += '\n}\n';
916
1171
  return out;
917
1172
  }
1173
+ /**
1174
+ * @param {import("@babel/types").ClassPrivateMethod} node - The Babel AST node.
1175
+ * @returns {string} Stringification of the node.
1176
+ */
918
1177
  }, {
919
1178
  key: "ClassPrivateMethod",
920
1179
  value: function ClassPrivateMethod(node) {
@@ -951,6 +1210,15 @@
951
1210
  out += this.toSource(body);
952
1211
  return out;
953
1212
  }
1213
+ /**
1214
+ * > asd;
1215
+ * > asd = 1;
1216
+ * > static asd;
1217
+ * > static asd = 1;
1218
+ *
1219
+ * @param {import("@babel/types").ClassProperty} node - The Babel AST node.
1220
+ * @returns {string} Stringification of the node.
1221
+ */
954
1222
  }, {
955
1223
  key: "ClassProperty",
956
1224
  value: function ClassProperty(node) {
@@ -958,7 +1226,7 @@
958
1226
  computed = node.computed,
959
1227
  value = node.value;
960
1228
  node.leadingComments;
961
- var static_ = node.static;
1229
+ var static_ = node.static; // JS keyword is problematic in object destructuring
962
1230
  var a = this.toSource(key);
963
1231
  var b = this.toSource(value);
964
1232
  var out = this.spaces;
@@ -976,6 +1244,10 @@
976
1244
  out += ';';
977
1245
  return out;
978
1246
  }
1247
+ /**
1248
+ * @param {import("@babel/types").ClassPrivateProperty} node - The Babel AST node.
1249
+ * @returns {string} Stringification of the node.
1250
+ */
979
1251
  }, {
980
1252
  key: "ClassPrivateProperty",
981
1253
  value: function ClassPrivateProperty(node) {
@@ -993,6 +1265,10 @@
993
1265
  out += ';';
994
1266
  return out;
995
1267
  }
1268
+ /**
1269
+ * @param {import("@babel/types").ContinueStatement} node - The Babel AST node.
1270
+ * @returns {string} Stringification of the node.
1271
+ */
996
1272
  }, {
997
1273
  key: "ContinueStatement",
998
1274
  value: function ContinueStatement(node) {
@@ -1004,11 +1280,24 @@
1004
1280
  out += ';';
1005
1281
  return out;
1006
1282
  }
1283
+ /**
1284
+ * Converts an array of Babel AST nodes representing function parameters into a comma-separated string.
1285
+ *
1286
+ * Each parameter node is converted to its source representation and combined into a single
1287
+ * string suitable for inserting into a function declaration's parentheses.
1288
+ *
1289
+ * @param {Node[]} params - An array of Babel AST nodes representing the function parameters to be stringified.
1290
+ * @returns {string} A string representing the serialized parameters, enclosed in parentheses.
1291
+ */
1007
1292
  }, {
1008
1293
  key: "FunctionDeclarationParams",
1009
1294
  value: function FunctionDeclarationParams(params) {
1010
1295
  return '(' + this.mapToSource(params).join(', ') + ')';
1011
1296
  }
1297
+ /**
1298
+ * @param {import("@babel/types").FunctionDeclaration} node - The Babel AST node.
1299
+ * @returns {string} Stringification of the node.
1300
+ */
1012
1301
  }, {
1013
1302
  key: "FunctionDeclaration",
1014
1303
  value: function FunctionDeclaration(node) {
@@ -1030,9 +1319,14 @@
1030
1319
  out += this.toSource(body);
1031
1320
  return out;
1032
1321
  }
1322
+ /**
1323
+ * @param {import("@babel/types").FunctionExpression} node - The Babel AST node.
1324
+ * @returns {string} Stringification of the node.
1325
+ */
1033
1326
  }, {
1034
1327
  key: "FunctionExpression",
1035
1328
  value: function FunctionExpression(node) {
1329
+ // Leading comments for asd=function(){} are in ExpressionStatement
1036
1330
  var async = node.async,
1037
1331
  body = node.body,
1038
1332
  generator = node.generator,
@@ -1056,6 +1350,10 @@
1056
1350
  }
1057
1351
  return out;
1058
1352
  }
1353
+ /**
1354
+ * @param {import("@babel/types").ArrowFunctionExpression} node - The Babel AST node.
1355
+ * @returns {string} Stringification of the node.
1356
+ */
1059
1357
  }, {
1060
1358
  key: "ArrowFunctionExpression",
1061
1359
  value: function ArrowFunctionExpression(node) {
@@ -1075,6 +1373,10 @@
1075
1373
  out += this.toSource(body);
1076
1374
  return out;
1077
1375
  }
1376
+ /**
1377
+ * @param {import("@babel/types").BigIntLiteral} node - The Babel AST node.
1378
+ * @returns {string} Stringification of the node.
1379
+ */
1078
1380
  }, {
1079
1381
  key: "BigIntLiteral",
1080
1382
  value: function BigIntLiteral(node) {
@@ -1082,6 +1384,10 @@
1082
1384
  node.value;
1083
1385
  return extra.raw;
1084
1386
  }
1387
+ /**
1388
+ * @param {import("@babel/types").BlockStatement} node - The Babel AST node.
1389
+ * @returns {string} Stringification of the node.
1390
+ */
1085
1391
  }, {
1086
1392
  key: "BlockStatement",
1087
1393
  value: function BlockStatement(node) {
@@ -1091,6 +1397,7 @@
1091
1397
  var out = '';
1092
1398
  out += ' {';
1093
1399
  this.numSpaces++;
1400
+ // Handle Directive/DirectiveLiteral like 'use strict';
1094
1401
  if (directives && directives.length) {
1095
1402
  out += '\n';
1096
1403
  out += this.mapToSource(directives).join('\n') + '\n';
@@ -1098,8 +1405,10 @@
1098
1405
  out += this.generateTypeChecks(node);
1099
1406
  if (body.length) {
1100
1407
  if (out.length === 2) {
1408
+ // 2 is ' {'
1101
1409
  out += '\n';
1102
1410
  }
1411
+ // out += '/*'+out.length+'*/';
1103
1412
  out += this.mapToSource(body).join('\n') + '\n';
1104
1413
  out += spaces;
1105
1414
  }
@@ -1107,12 +1416,24 @@
1107
1416
  out += '}';
1108
1417
  return out;
1109
1418
  }
1419
+ /**
1420
+ * > 'use strict';
1421
+ *
1422
+ * @param {import("@babel/types").Directive} node - The Babel AST node.
1423
+ * @returns {string} Stringification of the node.
1424
+ */
1110
1425
  }, {
1111
1426
  key: "Directive",
1112
1427
  value: function Directive(node) {
1113
1428
  var value = node.value;
1114
1429
  return this.toSource(value);
1115
1430
  }
1431
+ /**
1432
+ * > 'use strict';
1433
+ *
1434
+ * @param {import("@babel/types").DirectiveLiteral} node - The Babel AST node.
1435
+ * @returns {string} Stringification of the node.
1436
+ */
1116
1437
  }, {
1117
1438
  key: "DirectiveLiteral",
1118
1439
  value: function DirectiveLiteral(node) {
@@ -1121,6 +1442,10 @@
1121
1442
  var spaces = this.spaces;
1122
1443
  return "".concat(spaces).concat(extra.raw, ";");
1123
1444
  }
1445
+ /**
1446
+ * @param {import("@babel/types").ReturnStatement} node - The Babel AST node.
1447
+ * @returns {string} Stringification of the node.
1448
+ */
1124
1449
  }, {
1125
1450
  key: "ReturnStatement",
1126
1451
  value: function ReturnStatement(node) {
@@ -1131,11 +1456,19 @@
1131
1456
  }
1132
1457
  return spaces + 'return ' + this.toSource(argument) + ';';
1133
1458
  }
1459
+ /**
1460
+ * @param {import("@babel/types").Identifier} node - The Babel AST node.
1461
+ * @returns {string} Stringification of the node.
1462
+ */
1134
1463
  }, {
1135
1464
  key: "Identifier",
1136
1465
  value: function Identifier(node) {
1137
1466
  return node.name;
1138
1467
  }
1468
+ /**
1469
+ * @param {import("@babel/types").IfStatement} node - The Babel AST node.
1470
+ * @returns {string} Stringification of the node.
1471
+ */
1139
1472
  }, {
1140
1473
  key: "IfStatement",
1141
1474
  value: function IfStatement(node) {
@@ -1144,7 +1477,10 @@
1144
1477
  test = node.test;
1145
1478
  var spaces = this.spaces;
1146
1479
  var out = '';
1480
+ //if (this.parentType !== "IfStatement")
1481
+ //{
1147
1482
  out += spaces;
1483
+ //}
1148
1484
  out += "if (".concat(this.toSource(test), ")");
1149
1485
  out += this.toSourceCurly(consequent);
1150
1486
  if (alternate) {
@@ -1152,6 +1488,10 @@
1152
1488
  }
1153
1489
  return out;
1154
1490
  }
1491
+ /**
1492
+ * @param {import("@babel/types").LabeledStatement} node - The Babel AST node.
1493
+ * @returns {string} Stringification of the node.
1494
+ */
1155
1495
  }, {
1156
1496
  key: "LabeledStatement",
1157
1497
  value: function LabeledStatement(node) {
@@ -1164,6 +1504,15 @@
1164
1504
  out += spaces + this.toSource(body);
1165
1505
  return out;
1166
1506
  }
1507
+ /**
1508
+ * @example
1509
+ * ts = require("typescript");
1510
+ * ts.createSourceFile("repl.ts", "a = 1", ts.ScriptTarget.Latest);
1511
+ * ts.createSourceFile("repl.ts", "!!(a = 1 + 2)", ts.ScriptTarget.Latest);
1512
+ * showAST('!!(a = 1)');
1513
+ * @param {import("@babel/types").UnaryExpression} node - The Babel AST node.
1514
+ * @returns {string} Stringification of the node.
1515
+ */
1167
1516
  }, {
1168
1517
  key: "UnaryExpression",
1169
1518
  value: function UnaryExpression(node) {
@@ -1174,6 +1523,7 @@
1174
1523
  if (!prefix) {
1175
1524
  console.warn("Stringifier#UnaryExpression> never considered !prefix", node);
1176
1525
  }
1526
+ // Add a space for: typeof/delete/void
1177
1527
  var c = operator.charCodeAt(0);
1178
1528
  var op = operator;
1179
1529
  if (c >= 97 && c <= 122) {
@@ -1183,6 +1533,10 @@
1183
1533
  out += this.toSource(argument);
1184
1534
  return out;
1185
1535
  }
1536
+ /**
1537
+ * @param {import("@babel/types").MemberExpression} node - The Babel AST node.
1538
+ * @returns {string} Stringification of the node.
1539
+ */
1186
1540
  }, {
1187
1541
  key: "MemberExpression",
1188
1542
  value: function MemberExpression(node) {
@@ -1194,6 +1548,10 @@
1194
1548
  }
1195
1549
  return "".concat(this.toSource(object), ".").concat(this.toSource(property));
1196
1550
  }
1551
+ /**
1552
+ * @param {import("@babel/types").MetaProperty} node - The Babel AST node.
1553
+ * @returns {string} Stringification of the node.
1554
+ */
1197
1555
  }, {
1198
1556
  key: "MetaProperty",
1199
1557
  value: function MetaProperty(node) {
@@ -1203,12 +1561,26 @@
1203
1561
  var rhs = this.toSource(property);
1204
1562
  return "".concat(lhs, ".").concat(rhs);
1205
1563
  }
1564
+ /**
1565
+ * @param {import("@babel/types").ExpressionStatement} node - The Babel AST node.
1566
+ * @returns {string} Stringification of the node.
1567
+ */
1206
1568
  }, {
1207
1569
  key: "ExpressionStatement",
1208
1570
  value: function ExpressionStatement(node) {
1209
1571
  var expression = node.expression;
1572
+ /**
1573
+ * Not just a fall-through, adds a semicolon when it has semantic meaning.
1574
+ * E.g. invalid:
1575
+ * (function() {})()
1576
+ * (function() {})()
1577
+ */
1210
1578
  return this.spaces + this.toSource(expression) + ';';
1211
1579
  }
1580
+ /**
1581
+ * @param {import("@babel/types").CallExpression} node - The Babel AST node.
1582
+ * @returns {string} Stringification of the node.
1583
+ */
1212
1584
  }, {
1213
1585
  key: "CallExpression",
1214
1586
  value: function CallExpression(node) {
@@ -1224,6 +1596,14 @@
1224
1596
  out += ")";
1225
1597
  return out;
1226
1598
  }
1599
+ /**
1600
+ * We replicate the exact AST for validation:
1601
+ * x = 1;
1602
+ * y = {x,}
1603
+ * z = {y};
1604
+ * @param {import("@babel/types").ObjectExpression} node - The Babel AST node.
1605
+ * @returns {string} Stringification of the node.
1606
+ */
1227
1607
  }, {
1228
1608
  key: "ObjectExpression",
1229
1609
  value: function ObjectExpression(node) {
@@ -1245,6 +1625,10 @@
1245
1625
  out += '}';
1246
1626
  return out;
1247
1627
  }
1628
+ /**
1629
+ * @param {import("@babel/types").ObjectProperty} node - The Babel AST node.
1630
+ * @returns {string} Stringification of the node.
1631
+ */
1248
1632
  }, {
1249
1633
  key: "ObjectProperty",
1250
1634
  value: function ObjectProperty(node) {
@@ -1272,11 +1656,19 @@
1272
1656
  out += right;
1273
1657
  return out;
1274
1658
  }
1659
+ /**
1660
+ * @param {import("@babel/types").BooleanLiteral} node - The Babel AST node.
1661
+ * @returns {string} Stringification of the node.
1662
+ */
1275
1663
  }, {
1276
1664
  key: "BooleanLiteral",
1277
1665
  value: function BooleanLiteral(node) {
1278
1666
  return node.value.toString();
1279
1667
  }
1668
+ /**
1669
+ * @param {import("@babel/types").AssignmentExpression} node - The Babel AST node.
1670
+ * @returns {string} Stringification of the node.
1671
+ */
1280
1672
  }, {
1281
1673
  key: "AssignmentExpression",
1282
1674
  value: function AssignmentExpression(node) {
@@ -1285,8 +1677,13 @@
1285
1677
  right = node.right;
1286
1678
  var left_ = this.toSource(left);
1287
1679
  var right_ = this.toSource(right);
1680
+ // operator is for example: = |= &=
1288
1681
  return "".concat(left_, " ").concat(operator, " ").concat(right_);
1289
1682
  }
1683
+ /**
1684
+ * @param {import("@babel/types").BinaryExpression} node - The Babel AST node.
1685
+ * @returns {string} Stringification of the node.
1686
+ */
1290
1687
  }, {
1291
1688
  key: "BinaryExpression",
1292
1689
  value: function BinaryExpression(node) {
@@ -1297,11 +1694,19 @@
1297
1694
  var right_ = this.toSource(right);
1298
1695
  return "".concat(left_, " ").concat(operator, " ").concat(right_);
1299
1696
  }
1697
+ /**
1698
+ * @param {import("@babel/types").ThisExpression} node - The Babel AST node.
1699
+ * @returns {string} Stringification of the node.
1700
+ */
1300
1701
  }, {
1301
1702
  key: "ThisExpression",
1302
1703
  value: function ThisExpression(node) {
1303
1704
  return 'this';
1304
1705
  }
1706
+ /**
1707
+ * @param {import("@babel/types").ArrayExpression} node - The Babel AST node.
1708
+ * @returns {string} Stringification of the node.
1709
+ */
1305
1710
  }, {
1306
1711
  key: "ArrayExpression",
1307
1712
  value: function ArrayExpression(node) {
@@ -1324,6 +1729,10 @@
1324
1729
  out += '\n' + this.spaces + ']';
1325
1730
  return out;
1326
1731
  }
1732
+ /**
1733
+ * @param {import("@babel/types").VariableDeclaration} node - The Babel AST node.
1734
+ * @returns {string} Stringification of the node.
1735
+ */
1327
1736
  }, {
1328
1737
  key: "VariableDeclaration",
1329
1738
  value: function VariableDeclaration(node) {
@@ -1337,6 +1746,10 @@
1337
1746
  }
1338
1747
  return "".concat(spaces).concat(kind, " ").concat(this.mapToSource(declarations).join(', ')).concat(semicolon);
1339
1748
  }
1749
+ /**
1750
+ * @param {import("@babel/types").VariableDeclarator} node - The Babel AST node.
1751
+ * @returns {string} Stringification of the node.
1752
+ */
1340
1753
  }, {
1341
1754
  key: "VariableDeclarator",
1342
1755
  value: function VariableDeclarator(node) {
@@ -1347,6 +1760,10 @@
1347
1760
  }
1348
1761
  return this.toSource(id);
1349
1762
  }
1763
+ /**
1764
+ * @param {import("@babel/types").ConditionalExpression} node - The Babel AST node.
1765
+ * @returns {string} Stringification of the node.
1766
+ */
1350
1767
  }, {
1351
1768
  key: "ConditionalExpression",
1352
1769
  value: function ConditionalExpression(node) {
@@ -1355,6 +1772,12 @@
1355
1772
  test = node.test;
1356
1773
  return "".concat(this.toSource(test), " ? ").concat(this.toSource(consequent), " : ").concat(this.toSource(alternate));
1357
1774
  }
1775
+ /**
1776
+ * if (...)
1777
+ *
1778
+ * @param {import("@babel/types").LogicalExpression} node - The Babel AST node.
1779
+ * @returns {string} Stringification of the node.
1780
+ */
1358
1781
  }, {
1359
1782
  key: "LogicalExpression",
1360
1783
  value: function LogicalExpression(node) {
@@ -1371,6 +1794,12 @@
1371
1794
  }
1372
1795
  return "".concat(l, " ").concat(operator, " ").concat(r);
1373
1796
  }
1797
+ /**
1798
+ * TODO TEST: can init be undefined in for(;;)
1799
+ *
1800
+ * @param {import("@babel/types").ForStatement} node - The Babel AST node.
1801
+ * @returns {string} Stringification of the node.
1802
+ */
1374
1803
  }, {
1375
1804
  key: "ForStatement",
1376
1805
  value: function ForStatement(node) {
@@ -1385,6 +1814,12 @@
1385
1814
  var b = this.toSourceCurly(body);
1386
1815
  return "".concat(spaces, "for (").concat(i, "; ").concat(t, "; ").concat(u, ")").concat(b);
1387
1816
  }
1817
+ /**
1818
+ * showAST("++i")
1819
+ *
1820
+ * @param {import("@babel/types").UpdateExpression} node - The Babel AST node.
1821
+ * @returns {string} Stringification of the node.
1822
+ */
1388
1823
  }, {
1389
1824
  key: "UpdateExpression",
1390
1825
  value: function UpdateExpression(node) {
@@ -1396,6 +1831,10 @@
1396
1831
  }
1397
1832
  return "".concat(this.toSource(argument)).concat(operator);
1398
1833
  }
1834
+ /**
1835
+ * @param {import("@babel/types").NewExpression} node - The Babel AST node.
1836
+ * @returns {string} Stringification of the node.
1837
+ */
1399
1838
  }, {
1400
1839
  key: "NewExpression",
1401
1840
  value: function NewExpression(node) {
@@ -1405,6 +1844,12 @@
1405
1844
  var args = this.mapToSource(args_).join(', ');
1406
1845
  return "new ".concat(c, "(").concat(args, ")");
1407
1846
  }
1847
+ /**
1848
+ * @example
1849
+ * console.log(ast2json(parseSync("`${1} b ${2+3}c`").program.body[0]));
1850
+ * @param {import("@babel/types").TemplateLiteral} node - The Babel AST node.
1851
+ * @returns {string} Stringification of the node.
1852
+ */
1408
1853
  }, {
1409
1854
  key: "TemplateLiteral",
1410
1855
  value: function TemplateLiteral(node) {
@@ -1420,12 +1865,20 @@
1420
1865
  out += '`';
1421
1866
  return out;
1422
1867
  }
1868
+ /**
1869
+ * @param {import("@babel/types").TemplateElement} node - The Babel AST node.
1870
+ * @returns {string} Stringification of the node.
1871
+ */
1423
1872
  }, {
1424
1873
  key: "TemplateElement",
1425
1874
  value: function TemplateElement(node) {
1426
1875
  var value = node.value;
1427
1876
  return value.raw;
1428
1877
  }
1878
+ /**
1879
+ * @param {import("@babel/types").ParenthesizedExpression} node - The Babel AST node.
1880
+ * @returns {string} Stringification of the node.
1881
+ */
1429
1882
  }, {
1430
1883
  key: "ParenthesizedExpression",
1431
1884
  value: function ParenthesizedExpression(node) {
@@ -1442,23 +1895,39 @@
1442
1895
  out += '\n' + this.spaces + ')';
1443
1896
  return out;
1444
1897
  }
1898
+ /**
1899
+ * @param {import("@babel/types").PrivateName} node - The Babel AST node.
1900
+ * @returns {string} Stringification of the node.
1901
+ */
1445
1902
  }, {
1446
1903
  key: "PrivateName",
1447
1904
  value: function PrivateName(node) {
1448
1905
  var id = node.id;
1449
1906
  return "#".concat(this.toSource(id));
1450
1907
  }
1908
+ /**
1909
+ * @param {import("@babel/types").ExportAllDeclaration} node - The Babel AST node.
1910
+ * @returns {string} Stringification of the node.
1911
+ */
1451
1912
  }, {
1452
1913
  key: "ExportAllDeclaration",
1453
1914
  value: function ExportAllDeclaration(node) {
1454
1915
  return "export * from ".concat(node.source.extra.raw, ";");
1455
1916
  }
1917
+ /**
1918
+ * @param {import("@babel/types").ExportNamespaceSpecifier} node - The Babel AST node.
1919
+ * @returns {string} Stringification of the node.
1920
+ */
1456
1921
  }, {
1457
1922
  key: "ExportNamespaceSpecifier",
1458
1923
  value: function ExportNamespaceSpecifier(node) {
1459
1924
  var exported = node.exported;
1460
1925
  return '* as ' + this.toSource(exported);
1461
1926
  }
1927
+ /**
1928
+ * @param {import("@babel/types").ExportNamedDeclaration} node - The Babel AST node.
1929
+ * @returns {string} Stringification of the node.
1930
+ */
1462
1931
  }, {
1463
1932
  key: "ExportNamedDeclaration",
1464
1933
  value: function ExportNamedDeclaration(node) {
@@ -1486,6 +1955,7 @@
1486
1955
  out += '}';
1487
1956
  } else {
1488
1957
  out += 'export {\n';
1958
+ // todo: fix spacing system
1489
1959
  out += this.mapToSource(specifiers).map(function (_) {
1490
1960
  return " ".concat(_this3.spaces).concat(_);
1491
1961
  }).join(',\n');
@@ -1505,6 +1975,10 @@
1505
1975
  }
1506
1976
  return out;
1507
1977
  }
1978
+ /**
1979
+ * @param {import("@babel/types").ExportDefaultDeclaration} node - The Babel AST node.
1980
+ * @returns {string} Stringification of the node.
1981
+ */
1508
1982
  }, {
1509
1983
  key: "ExportDefaultDeclaration",
1510
1984
  value: function ExportDefaultDeclaration(node) {
@@ -1512,6 +1986,10 @@
1512
1986
  var a = this.toSource(declaration);
1513
1987
  return "export default ".concat(a, ";");
1514
1988
  }
1989
+ /**
1990
+ * @param {import("@babel/types").ExportSpecifier} node - The Babel AST node.
1991
+ * @returns {string} Stringification of the node.
1992
+ */
1515
1993
  }, {
1516
1994
  key: "ExportSpecifier",
1517
1995
  value: function ExportSpecifier(node) {
@@ -1523,13 +2001,24 @@
1523
2001
  if (left === right) {
1524
2002
  return "".concat(spaces).concat(left);
1525
2003
  }
2004
+ // For example:
2005
+ // PostEffect: PostEffect$1\n
2006
+ // createMesh: createMesh$1\n
1526
2007
  return "".concat(spaces).concat(right, " as ").concat(left);
1527
2008
  }
2009
+ /**
2010
+ * @param {import("@babel/types").Super} node - The Babel AST node.
2011
+ * @returns {string} Stringification of the node.
2012
+ */
1528
2013
  }, {
1529
2014
  key: "Super",
1530
2015
  value: function Super(node) {
1531
2016
  return 'super';
1532
2017
  }
2018
+ /**
2019
+ * @param {import("@babel/types").ForInStatement} node - The Babel AST node.
2020
+ * @returns {string} Stringification of the node.
2021
+ */
1533
2022
  }, {
1534
2023
  key: "ForInStatement",
1535
2024
  value: function ForInStatement(node) {
@@ -1542,6 +2031,10 @@
1542
2031
  var b = this.toSourceCurly(body);
1543
2032
  return "".concat(spaces, "for (").concat(l, " in ").concat(r, ")").concat(b);
1544
2033
  }
2034
+ /**
2035
+ * @param {import("@babel/types").ThrowStatement} node - The Babel AST node.
2036
+ * @returns {string} Stringification of the node.
2037
+ */
1545
2038
  }, {
1546
2039
  key: "ThrowStatement",
1547
2040
  value: function ThrowStatement(node) {
@@ -1550,6 +2043,10 @@
1550
2043
  var arg = this.toSource(argument);
1551
2044
  return "".concat(spaces, "throw ").concat(arg, ";");
1552
2045
  }
2046
+ /**
2047
+ * @param {import("@babel/types").WhileStatement} node - The Babel AST node.
2048
+ * @returns {string} Stringification of the node.
2049
+ */
1553
2050
  }, {
1554
2051
  key: "WhileStatement",
1555
2052
  value: function WhileStatement(node) {
@@ -1560,6 +2057,10 @@
1560
2057
  var b = this.toSourceCurly(body);
1561
2058
  return "".concat(spaces, "while (").concat(t, ")").concat(b);
1562
2059
  }
2060
+ /**
2061
+ * @param {import("@babel/types").BreakStatement} node - The Babel AST node.
2062
+ * @returns {string} Stringification of the node.
2063
+ */
1563
2064
  }, {
1564
2065
  key: "BreakStatement",
1565
2066
  value: function BreakStatement(node) {
@@ -1571,6 +2072,10 @@
1571
2072
  out += ';';
1572
2073
  return out;
1573
2074
  }
2075
+ /**
2076
+ * @param {import("@babel/types").ForOfStatement} node - The Babel AST node.
2077
+ * @returns {string} Stringification of the node.
2078
+ */
1574
2079
  }, {
1575
2080
  key: "ForOfStatement",
1576
2081
  value: function ForOfStatement(node) {
@@ -1585,6 +2090,13 @@
1585
2090
  var a = await_ ? 'await ' : '';
1586
2091
  return "".concat(spaces, "for ").concat(a, "(").concat(l, " of ").concat(r, ")").concat(b);
1587
2092
  }
2093
+ /**
2094
+ * for (const [a, b] in c)
2095
+ * --> [a, b] is the array pattern
2096
+ *
2097
+ * @param {import("@babel/types").ArrayPattern} node - The Babel AST node.
2098
+ * @returns {string} Stringification of the node.
2099
+ */
1588
2100
  }, {
1589
2101
  key: "ArrayPattern",
1590
2102
  value: function ArrayPattern(node) {
@@ -1592,6 +2104,10 @@
1592
2104
  var e = this.mapToSource(elements).join(', ');
1593
2105
  return "[".concat(e, "]");
1594
2106
  }
2107
+ /**
2108
+ * @param {import("@babel/types").SwitchStatement} node - The Babel AST node.
2109
+ * @returns {string} Stringification of the node.
2110
+ */
1595
2111
  }, {
1596
2112
  key: "SwitchStatement",
1597
2113
  value: function SwitchStatement(node) {
@@ -1604,6 +2120,10 @@
1604
2120
  out += spaces + '}';
1605
2121
  return out;
1606
2122
  }
2123
+ /**
2124
+ * @param {import("@babel/types").SwitchCase} node - The Babel AST node.
2125
+ * @returns {string} Stringification of the node.
2126
+ */
1607
2127
  }, {
1608
2128
  key: "SwitchCase",
1609
2129
  value: function SwitchCase(node) {
@@ -1617,26 +2137,49 @@
1617
2137
  }
1618
2138
  return "".concat(spaces, "default:\n").concat(c);
1619
2139
  }
2140
+ /**
2141
+ * @param {import("@babel/types").RegExpLiteral} node - The Babel AST node.
2142
+ * @returns {string} Stringification of the node.
2143
+ */
1620
2144
  }, {
1621
2145
  key: "RegExpLiteral",
1622
2146
  value: function RegExpLiteral(node) {
2147
+ // parseSync("/test/gm")
2148
+ // todo figure out why it always exposes node.value === undefined... oversight in Babel?
1623
2149
  var extra = node.extra;
1624
2150
  node.value;
1625
2151
  node.pattern;
1626
2152
  node.flags;
1627
2153
  return extra.raw;
1628
2154
  }
2155
+ /**
2156
+ * for (var i=0, n=arr.length; i<n; i++)
2157
+ * sequence expression: var i=0, n=arr.length
2158
+ *
2159
+ * @param {import("@babel/types").SequenceExpression} node - The Babel AST node.
2160
+ * @returns {string} Stringification of the node.
2161
+ */
1629
2162
  }, {
1630
2163
  key: "SequenceExpression",
1631
2164
  value: function SequenceExpression(node) {
1632
2165
  var expressions = node.expressions;
1633
2166
  return this.mapToSource(expressions).join(', ');
1634
2167
  }
2168
+ /**
2169
+ * showAST("if (true);");
2170
+ *
2171
+ * @param {import("@babel/types").EmptyStatement} node - The Babel AST node.
2172
+ * @returns {string} Stringification of the node.
2173
+ */
1635
2174
  }, {
1636
2175
  key: "EmptyStatement",
1637
2176
  value: function EmptyStatement(node) {
1638
2177
  return ';';
1639
2178
  }
2179
+ /**
2180
+ * @param {import("@babel/types").SpreadElement} node - The Babel AST node.
2181
+ * @returns {string} Stringification of the node.
2182
+ */
1640
2183
  }, {
1641
2184
  key: "SpreadElement",
1642
2185
  value: function SpreadElement(node) {
@@ -1644,9 +2187,15 @@
1644
2187
  var a = this.toSource(argument);
1645
2188
  return "...".concat(a);
1646
2189
  }
2190
+ /**
2191
+ * @param {import("@babel/types").ObjectMethod} node - The Babel AST node.
2192
+ * @returns {string} Stringification of the node.
2193
+ */
1647
2194
  }, {
1648
2195
  key: "ObjectMethod",
1649
2196
  value: function ObjectMethod(node) {
2197
+ // @todo PR in Babel why method/id is a key in node... (seems like a bug/oversight)
2198
+ // method === true just indicates kind === 'method'
1650
2199
  node.method;
1651
2200
  var key = node.key,
1652
2201
  computed = node.computed,
@@ -1660,6 +2209,10 @@
1660
2209
  console.warn("ObjectMethod> id !== null is unhandled", node);
1661
2210
  debugger;
1662
2211
  }
2212
+ // if (method) {
2213
+ // console.warn("ObjectMethod> node was a method", node);
2214
+ // debugger;
2215
+ // }
1663
2216
  var out = this.spaces;
1664
2217
  if (generator) {
1665
2218
  out += '*';
@@ -1686,6 +2239,11 @@
1686
2239
  out += this.toSource(body);
1687
2240
  return out;
1688
2241
  }
2242
+ /**
2243
+ * E.g. function testComma({x,y,z,}) {}
2244
+ * @param {import("@babel/types").ObjectPattern} node - The Babel AST node.
2245
+ * @returns {string} Stringification of the node.
2246
+ */
1689
2247
  }, {
1690
2248
  key: "ObjectPattern",
1691
2249
  value: function ObjectPattern(node) {
@@ -1706,6 +2264,16 @@
1706
2264
  out += '}';
1707
2265
  return out;
1708
2266
  }
2267
+ /**
2268
+ * > x?.y
2269
+ * > x?.y.z
2270
+ * > x[y?.z]
2271
+ * > x?.[y?.z]
2272
+ * > b?.file?.variants[variant]
2273
+ *
2274
+ * @param {import("@babel/types").OptionalMemberExpression} node - The Babel AST node.
2275
+ * @returns {string} Stringification of the node.
2276
+ */
1709
2277
  }, {
1710
2278
  key: "OptionalMemberExpression",
1711
2279
  value: function OptionalMemberExpression(node) {
@@ -1715,6 +2283,7 @@
1715
2283
  optional = node.optional;
1716
2284
  var a = this.toSource(object);
1717
2285
  var b = this.toSource(property);
2286
+ // Basically four cases: computed=true/false optional=true/false, 00, 01, 10, 11
1718
2287
  if (!computed && !optional) {
1719
2288
  return "".concat(a, ".").concat(b);
1720
2289
  } else if (!computed && optional) {
@@ -1722,8 +2291,17 @@
1722
2291
  } else if (computed && !optional) {
1723
2292
  return "".concat(a, "[").concat(b, "]");
1724
2293
  }
2294
+ // Can only be case 4 now (computed && optional):
1725
2295
  return "".concat(a, "?.[").concat(b, "]");
1726
2296
  }
2297
+ /**
2298
+ * > version?.indexOf('$');
2299
+ * > version?.indexOf?.('$');
2300
+ * > this.passEncoder?.pushDebugGroup(name);
2301
+ *
2302
+ * @param {import("@babel/types").OptionalCallExpression} node - The Babel AST node.
2303
+ * @returns {string} Stringification of the node.
2304
+ */
1727
2305
  }, {
1728
2306
  key: "OptionalCallExpression",
1729
2307
  value: function OptionalCallExpression(node) {
@@ -1737,6 +2315,10 @@
1737
2315
  }
1738
2316
  return "".concat(a, "(").concat(b, ")");
1739
2317
  }
2318
+ /**
2319
+ * @param {import("@babel/types").DoWhileStatement} node - The Babel AST node.
2320
+ * @returns {string} Stringification of the node.
2321
+ */
1740
2322
  }, {
1741
2323
  key: "DoWhileStatement",
1742
2324
  value: function DoWhileStatement(node) {
@@ -1750,6 +2332,10 @@
1750
2332
  out += " while (".concat(this.toSource(test), ");");
1751
2333
  return out;
1752
2334
  }
2335
+ /**
2336
+ * @param {import("@babel/types").TryStatement} node - The Babel AST node.
2337
+ * @returns {string} Stringification of the node.
2338
+ */
1753
2339
  }, {
1754
2340
  key: "TryStatement",
1755
2341
  value: function TryStatement(node) {
@@ -1767,6 +2353,10 @@
1767
2353
  }
1768
2354
  return out;
1769
2355
  }
2356
+ /**
2357
+ * @param {import("@babel/types").CatchClause} node - The Babel AST node.
2358
+ * @returns {string} Stringification of the node.
2359
+ */
1770
2360
  }, {
1771
2361
  key: "CatchClause",
1772
2362
  value: function CatchClause(node) {
@@ -1777,29 +2367,49 @@
1777
2367
  var p = this.toSource(param);
1778
2368
  return " catch (".concat(p, ") ").concat(b);
1779
2369
  }
2370
+ // Example: try { 1n / 0 } catch {}
1780
2371
  return " catch ".concat(b);
1781
2372
  }
2373
+ /**
2374
+ * @param {import("@babel/types").RestElement} node - The Babel AST node.
2375
+ * @returns {string} Stringification of the node.
2376
+ */
1782
2377
  }, {
1783
2378
  key: "RestElement",
1784
2379
  value: function RestElement(node) {
1785
2380
  var argument = node.argument;
1786
2381
  return "...".concat(this.toSource(argument));
1787
2382
  }
2383
+ /**
2384
+ * @param {import("@babel/types").DebuggerStatement} node - The Babel AST node.
2385
+ * @returns {string} Stringification of the node.
2386
+ */
1788
2387
  }, {
1789
2388
  key: "DebuggerStatement",
1790
2389
  value: function DebuggerStatement(node) {
1791
2390
  return "".concat(this.spaces, "debugger;");
1792
2391
  }
2392
+ /**
2393
+ * @param {import("@babel/types").Import} node - The Babel AST node.
2394
+ * @returns {string} Stringification of the node.
2395
+ */
1793
2396
  }, {
1794
2397
  key: "Import",
1795
2398
  value: function Import(node) {
1796
2399
  return 'import';
1797
2400
  }
2401
+ /**
2402
+ * @param {import("@babel/types").ImportDeclaration} node - The Babel AST node.
2403
+ * @returns {string} Stringification of the node.
2404
+ */
1798
2405
  }, {
1799
2406
  key: "ImportDeclaration",
1800
2407
  value: function ImportDeclaration(node) {
1801
2408
  var specifiers = node.specifiers,
1802
2409
  source = node.source;
2410
+ // ImportNamespaceSpecifier: import * as a from "b";
2411
+ // ImportDefaultSpecifier : import a from "b";
2412
+ // ImportSpecifier : import { a } from "b";
1803
2413
  var a = this.mapToSource(specifiers).join(', ');
1804
2414
  var b = this.toSource(source);
1805
2415
  if (specifiers.length === 0) {
@@ -1810,6 +2420,10 @@
1810
2420
  }
1811
2421
  return "import {".concat(a, "} from ").concat(b, ";");
1812
2422
  }
2423
+ /**
2424
+ * @param {import("@babel/types").ImportSpecifier} node - The Babel AST node.
2425
+ * @returns {string} Stringification of the node.
2426
+ */
1813
2427
  }, {
1814
2428
  key: "ImportSpecifier",
1815
2429
  value: function ImportSpecifier(node) {
@@ -1822,37 +2436,61 @@
1822
2436
  }
1823
2437
  return a;
1824
2438
  }
2439
+ /**
2440
+ * @param {import("@babel/types").ImportDefaultSpecifier} node - The Babel AST node.
2441
+ * @returns {string} Stringification of the node.
2442
+ */
1825
2443
  }, {
1826
2444
  key: "ImportDefaultSpecifier",
1827
2445
  value: function ImportDefaultSpecifier(node) {
1828
2446
  var local = node.local;
1829
2447
  return this.toSource(local);
1830
2448
  }
2449
+ /**
2450
+ * @param {import("@babel/types").ImportNamespaceSpecifier} node - The Babel AST node.
2451
+ * @returns {string} Stringification of the node.
2452
+ */
1831
2453
  }, {
1832
2454
  key: "ImportNamespaceSpecifier",
1833
2455
  value: function ImportNamespaceSpecifier(node) {
1834
2456
  var local = node.local;
1835
2457
  return "* as ".concat(this.toSource(local));
1836
2458
  }
2459
+ /**
2460
+ * @param {import("@babel/types").File} node - The Babel AST node.
2461
+ * @returns {string} Stringification of the node.
2462
+ */
1837
2463
  }, {
1838
2464
  key: "File",
1839
2465
  value: function File(node) {
1840
2466
  return this.toSource(node.program) + '\n';
1841
2467
  }
2468
+ /**
2469
+ * @param {import("@babel/types").Program} node - The Babel AST node.
2470
+ * @returns {string} Stringification of the node.
2471
+ */
1842
2472
  }, {
1843
2473
  key: "Program",
1844
2474
  value: function Program(node) {
1845
2475
  var body = node.body,
1846
2476
  directives = node.directives;
1847
2477
  var out = '';
2478
+ // @todo I would like to keep comments above and below,
2479
+ // but below one is currently dropped (does't matter for AST)
2480
+ // See: test/typechecking/directive.mjs
1848
2481
  out += this.mapToSource(directives);
1849
2482
  out += this.mapToSource(body).join('\n');
1850
2483
  return out;
1851
2484
  }
2485
+ /**
2486
+ * @param {import("@babel/types").StringLiteral} node - The Babel AST node.
2487
+ * @returns {string} Stringification of the node.
2488
+ */
1852
2489
  }, {
1853
2490
  key: "StringLiteral",
1854
2491
  value: function StringLiteral(node) {
1855
2492
  var extra = node.extra;
2493
+ // Never experienced this so far, but types are types...
1856
2494
  if (!extra) {
1857
2495
  debugger;
1858
2496
  return '';
@@ -1863,11 +2501,19 @@
1863
2501
  }
1864
2502
  return extra.raw;
1865
2503
  }
2504
+ /**
2505
+ * @param {import("@babel/types").NumericLiteral} node - The Babel AST node.
2506
+ * @returns {string} Stringification of the node.
2507
+ */
1866
2508
  }, {
1867
2509
  key: "NumericLiteral",
1868
2510
  value: function NumericLiteral(node) {
1869
2511
  return node.extra.raw;
1870
2512
  }
2513
+ /**
2514
+ * @param {import("@babel/types").AssignmentPattern} node - The Babel AST node.
2515
+ * @returns {string} Stringification of the node.
2516
+ */
1871
2517
  }, {
1872
2518
  key: "AssignmentPattern",
1873
2519
  value: function AssignmentPattern(node) {
@@ -1875,11 +2521,19 @@
1875
2521
  right = node.right;
1876
2522
  return "".concat(this.toSource(left), " = ").concat(this.toSource(right));
1877
2523
  }
2524
+ /**
2525
+ * @param {import("@babel/types").NullLiteral} node - The Babel AST node.
2526
+ * @returns {string} Stringification of the node.
2527
+ */
1878
2528
  }, {
1879
2529
  key: "NullLiteral",
1880
2530
  value: function NullLiteral(node) {
1881
2531
  return 'null';
1882
2532
  }
2533
+ /**
2534
+ * @param {import("@babel/types").TaggedTemplateExpression} node - The Babel AST node.
2535
+ * @returns {string} Stringification of the node.
2536
+ */
1883
2537
  }, {
1884
2538
  key: "TaggedTemplateExpression",
1885
2539
  value: function TaggedTemplateExpression(node) {
@@ -1889,6 +2543,10 @@
1889
2543
  var q = this.toSource(quasi);
1890
2544
  return t + q;
1891
2545
  }
2546
+ /**
2547
+ * @param {import("@babel/types").YieldExpression} node - The Babel AST node.
2548
+ * @returns {string} Stringification of the node.
2549
+ */
1892
2550
  }, {
1893
2551
  key: "YieldExpression",
1894
2552
  value: function YieldExpression(node) {
@@ -1905,9 +2563,25 @@
1905
2563
  return Stringifier;
1906
2564
  }();
1907
2565
 
1908
- var Asserter = function (_Stringifier) {
2566
+ /** @typedef {import('@babel/types').Node } Node */
2567
+ /** @typedef {import("@babel/types").ClassMethod } ClassMethod */
2568
+ /** @typedef {import("@babel/types").ClassPrivateMethod} ClassPrivateMethod */
2569
+ /** @typedef {import('./stat.mjs').Stat } Stat */
2570
+ /**
2571
+ * @typedef {object} Options
2572
+ * @property {boolean} [forceCurly] - Determines whether curly braces are enforced in Stringifier.
2573
+ * @property {boolean} [validateDivision] - Indicates whether division operations should be validated.
2574
+ * @property {Function} [expandType] - A function that expands shorthand types into full descriptions.
2575
+ * @property {string} [filename] - The name of a file to which the instance pertains.
2576
+ * @property {boolean} [addHeader] - Whether to add import declarations headers. Defaults to true.
2577
+ * @property {string[]} [ignoreLocations] - Ignore these locations because they are known false-positives.
2578
+ */
2579
+ var Asserter = /*#__PURE__*/function (_Stringifier) {
1909
2580
  _inherits(Asserter, _Stringifier);
1910
2581
  var _super = _createSuper(Asserter);
2582
+ /**
2583
+ * @param {Options} [options] - The options.
2584
+ */
1911
2585
  function Asserter() {
1912
2586
  var _this;
1913
2587
  var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
@@ -1919,9 +2593,12 @@
1919
2593
  expandType = _ref$expandType === void 0 ? expandTypeDepFree : _ref$expandType,
1920
2594
  filename = _ref.filename,
1921
2595
  _ref$addHeader = _ref.addHeader,
1922
- addHeader = _ref$addHeader === void 0 ? true : _ref$addHeader;
2596
+ addHeader = _ref$addHeader === void 0 ? true : _ref$addHeader,
2597
+ _ref$ignoreLocations = _ref.ignoreLocations,
2598
+ ignoreLocations = _ref$ignoreLocations === void 0 ? [] : _ref$ignoreLocations;
1923
2599
  _classCallCheck(this, Asserter);
1924
2600
  _this = _super.call(this);
2601
+ /** @type {Record<string, Stat>} */
1925
2602
  _defineProperty(_assertThisInitialized(_this), "stats", {
1926
2603
  'ArrowFunctionExpression': {
1927
2604
  checked: 0,
@@ -1968,17 +2645,28 @@
1968
2645
  unchecked: 0
1969
2646
  }
1970
2647
  });
2648
+ /** @type {Record<string, object>} */
1971
2649
  _defineProperty(_assertThisInitialized(_this), "typedefs", {});
1972
2650
  _this.forceCurly = forceCurly;
1973
2651
  _this.validateDivision = validateDivision;
2652
+ // @todo collect every type + manually validate as test set
2653
+ // + implement expandType using Babel Flow type parser aswell
1974
2654
  _this.expandType = expandType;
1975
2655
  _this.filename = filename;
1976
2656
  _this.addHeader = addHeader;
2657
+ _this.ignoreLocations = ignoreLocations;
1977
2658
  return _this;
1978
2659
  }
1979
2660
  _createClass(Asserter, [{
1980
2661
  key: "ArrowFunctionExpression",
1981
- value: function ArrowFunctionExpression(node) {
2662
+ value:
2663
+ /**
2664
+ * We expand type-asserted ArrowFunctionExpressions in order to add type assertions.
2665
+ * @override
2666
+ * @param {import("@babel/types").ArrowFunctionExpression} node - The Babel AST node.
2667
+ * @returns {string} Stringification of the node.
2668
+ */
2669
+ function ArrowFunctionExpression(node) {
1982
2670
  var async = node.async,
1983
2671
  body = node.body,
1984
2672
  generator = node.generator,
@@ -2002,6 +2690,11 @@
2002
2690
  }
2003
2691
  return out;
2004
2692
  }
2693
+ /**
2694
+ * @override
2695
+ * @param {import("@babel/types").ClassDeclaration} node - The Babel AST node.
2696
+ * @returns {string} Stringification of the node.
2697
+ */
2005
2698
  }, {
2006
2699
  key: "ClassDeclaration",
2007
2700
  value: function ClassDeclaration(node) {
@@ -2011,6 +2704,14 @@
2011
2704
  out += "".concat(this.spaces, "registerClass(").concat(id_, ");");
2012
2705
  return out;
2013
2706
  }
2707
+ /**
2708
+ * Finds the closest ancestor of the given node that matches the specified type.
2709
+ *
2710
+ * @param {Node} node - The starting node to search from.
2711
+ * @param {T} type - Type name of the node to search for.
2712
+ * @template {Node['type']} T
2713
+ * @returns {Extract<Node, {type: T}>|undefined} The first ancestor node of the specified type, or undefined if none is found.
2714
+ */
2014
2715
  }, {
2015
2716
  key: "findParentOfType",
2016
2717
  value: function findParentOfType(node, type) {
@@ -2024,6 +2725,13 @@
2024
2725
  return _.type === type;
2025
2726
  });
2026
2727
  }
2728
+ /**
2729
+ * Alternatively "import * as rti from ..." would also prevent "Unused external imports" warning...
2730
+ * or keeping log of every single call during RTI parsing.
2731
+ * @todo
2732
+ * Once we went over every node, we can see if we really require registerTypef, registerClass etc.
2733
+ * @returns {string} The import declaration header for importing RTI.
2734
+ */
2027
2735
  }, {
2028
2736
  key: "getHeader",
2029
2737
  value: function getHeader() {
@@ -2035,9 +2743,19 @@
2035
2743
  header += ", validateDivision";
2036
2744
  }
2037
2745
  header += ", registerTypedef, registerClass} from '@runtime-type-inspector/runtime';\n";
2746
+ // Prevent tree-shaking in UMD build so we can always "add a breakpoint here".
2038
2747
  header += "export * from '@runtime-type-inspector/runtime';\n";
2039
2748
  return header;
2040
2749
  }
2750
+ /**
2751
+ * Retrieves the node associated with the leading comments for an arrow function expression.
2752
+ *
2753
+ * This method travels up the syntax tree from the given node to find a parent node with leading comments.
2754
+ * This search is bounded by function boundaries or a 'CallExpression' node, as per the logic defined within the loop.
2755
+ * @param {Node} node - The node representing the arrow function expression for which to find the leading comments node.
2756
+ * @returns {Node|undefined} The node that contains the leading comments, or `undefined`
2757
+ * if none is found before reaching a different function or 'CallExpression'.
2758
+ */
2041
2759
  }, {
2042
2760
  key: "getLeadingCommentsNodeForArrowFunctionExpression",
2043
2761
  value: function getLeadingCommentsNodeForArrowFunctionExpression(node) {
@@ -2049,9 +2767,16 @@
2049
2767
  if (parent.leadingComments) {
2050
2768
  return parent;
2051
2769
  }
2770
+ // Skip now, if we find another function first,
2771
+ // there is no JSDoc for our function anymore.
2772
+ // Not interested in our start node if it didn't
2773
+ // contain leadingComments.
2052
2774
  i--;
2053
2775
  while (i >= 0) {
2054
2776
  parent = parents[i];
2777
+ //if (parent.type === 'CallExpression') {
2778
+ // break;
2779
+ //}
2055
2780
  if (nodeIsFunction(parent)) {
2056
2781
  break;
2057
2782
  }
@@ -2061,6 +2786,10 @@
2061
2786
  i--;
2062
2787
  }
2063
2788
  }
2789
+ /**
2790
+ * Emits a warning message to the console, optionally prefixed with the instance's filename.
2791
+ * @param {...any} args - A list of arguments to be passed to the console.warn function.
2792
+ */
2064
2793
  }, {
2065
2794
  key: "warn",
2066
2795
  value: function warn() {
@@ -2081,9 +2810,16 @@
2081
2810
  if (parent.leadingComments) {
2082
2811
  return parent;
2083
2812
  }
2813
+ // Skip now, if we find another function first,
2814
+ // there is no JSDoc for our function anymore.
2815
+ // Not interested in our start node if it didn't
2816
+ // contain leadingComments.
2084
2817
  i--;
2085
2818
  while (i >= 0) {
2086
2819
  parent = parents[i];
2820
+ //if (parent.type === 'CallExpression') {
2821
+ // break;
2822
+ //}
2087
2823
  if (nodeIsFunction(parent)) {
2088
2824
  break;
2089
2825
  }
@@ -2092,7 +2828,26 @@
2092
2828
  }
2093
2829
  i--;
2094
2830
  }
2095
- }
2831
+ /** @todo convert all files in test/typechecking/*.mjs into full unit tests */
2832
+ // Old way:
2833
+ // if (node.leadingComments) {
2834
+ // return node.leadingComments;
2835
+ // }
2836
+ // node = this.findParentOfType(node, 'ExpressionStatement');
2837
+ // if (!node) {
2838
+ // /**
2839
+ // * @todo Need more refactoring, see missing type-assertions in test/typechecking/good-old-es5.mjs
2840
+ // */
2841
+ // node = this.parents.findLast(_ => _.type === 'VariableDeclaration');
2842
+ // if (!node) {
2843
+ // return;
2844
+ // }
2845
+ // }
2846
+ }
2847
+ /**
2848
+ * @param {Node} node - The Babel AST node.
2849
+ * @returns {undefined | {}} The return value of `parseJSDoc`.
2850
+ */
2096
2851
  }, {
2097
2852
  key: "getJSDoc",
2098
2853
  value: function getJSDoc(node) {
@@ -2101,10 +2856,12 @@
2101
2856
  }
2102
2857
  var _node = node,
2103
2858
  leadingComments = _node.leadingComments;
2859
+ // Receive the leadingComments from the ExpressionStatement, not the FunctionExpression itself.
2104
2860
  if (node.type === 'FunctionExpression') {
2105
2861
  var tmp = this.getLeadingCommentsNodeForFunctionExpression(node);
2106
2862
  leadingComments = tmp === null || tmp === void 0 ? void 0 : tmp.leadingComments;
2107
2863
  }
2864
+ // Receive the leadingComments from ExportNamedDeclaration, if FunctionDeclaration has none
2108
2865
  if (!leadingComments) {
2109
2866
  if (node.type === 'FunctionDeclaration') {
2110
2867
  var exportNamedDeclaration = this.findParentOfType(node, 'ExportNamedDeclaration');
@@ -2135,6 +2892,15 @@
2135
2892
  }
2136
2893
  }
2137
2894
  }
2895
+ /**
2896
+ * Retrieves the name of a parameter from a Babel AST node.
2897
+ *
2898
+ * This function expects a node representing a function parameter and attempts to extract
2899
+ * the parameter's name directly or from an AssignmentPattern.
2900
+ *
2901
+ * @param {Node} param - The AST node representing the function parameter from which to extract the name.
2902
+ * @returns {string} The name of the parameter as a string, or the parameter's source code if the extraction fails.
2903
+ */
2138
2904
  }, {
2139
2905
  key: "getNameOfParam",
2140
2906
  value: function getNameOfParam(param) {
@@ -2159,17 +2925,27 @@
2159
2925
  value: function statsPrint() {
2160
2926
  console.table(this.stats);
2161
2927
  }
2928
+ /**
2929
+ * Retrieves statistical information for a given Babel AST node of this instance.
2930
+ *
2931
+ * @param {Node} node - The Babel AST node for which the statistical data is retrieved.
2932
+ * @returns {Stat} An object containing the statistical data for the specified node. If the
2933
+ * node type is unhandled, defaults to returning a dummy object with 'checked' and 'unchecked'
2934
+ * properties both set to 0.
2935
+ */
2162
2936
  }, {
2163
2937
  key: "getStatsForNode",
2164
2938
  value: function getStatsForNode(node) {
2165
2939
  var stats = this.stats;
2166
2940
  var type = nodeIsFunction(node) ? node.type : this.parentType;
2167
2941
  if (type === 'ClassMethod') {
2168
- var parent = this.parent;
2942
+ var parent = /** @type {ClassMethod} */
2943
+ this.parent;
2169
2944
  var kind = parent.kind;
2170
2945
  return stats["ClassMethod#".concat(kind)];
2171
2946
  } else if (type === 'ClassPrivateMethod') {
2172
- var _parent = this.parent;
2947
+ var _parent = /** @type {ClassPrivateMethod} */
2948
+ this.parent;
2173
2949
  var _kind = _parent.kind;
2174
2950
  return stats["ClassPrivateMethod#".concat(_kind)];
2175
2951
  }
@@ -2183,6 +2959,17 @@
2183
2959
  }
2184
2960
  return stat;
2185
2961
  }
2962
+ /**
2963
+ * Checks if a provided Babel AST node has a parameter with the given name.
2964
+ *
2965
+ * This function will look at the node's parameters if available and determine whether
2966
+ * one of them matches the provided name. Supports various parameter types such as Identifiers
2967
+ * and AssignmentPatterns.
2968
+ *
2969
+ * @param {Node} node - The Babel AST node to inspect. If it's a BlockStatement, the parent node is used instead.
2970
+ * @param {string} name - The name of the parameter to look for within the node's parameters.
2971
+ * @returns {boolean} True if the node has a parameter with the given name; false otherwise.
2972
+ */
2186
2973
  }, {
2187
2974
  key: "nodeHasParamName",
2188
2975
  value: function nodeHasParamName(node, name) {
@@ -2215,6 +3002,18 @@
2215
3002
  return false;
2216
3003
  });
2217
3004
  }
3005
+ /**
3006
+ * Generates a string containing type checks for a given Babel AST node based on associated JSDoc information.
3007
+ *
3008
+ * This function analyzes the node and its JSDoc annotations to construct runtime type
3009
+ * check expressions. It handles various parameter patterns and outputs code that performs
3010
+ * actual type assertions. If a node does not correspond to any known or supported pattern,
3011
+ * it returns an empty string.
3012
+ *
3013
+ * @override
3014
+ * @param {Node} node - The Babel AST node for which to generate type checks.
3015
+ * @returns {string} A string of code with type check assertions, based on the JSDoc comments associated with the given node.
3016
+ */
2218
3017
  }, {
2219
3018
  key: "generateTypeChecks",
2220
3019
  value: function generateTypeChecks(node) {
@@ -2224,6 +3023,7 @@
2224
3023
  return '';
2225
3024
  }
2226
3025
  var jsdoc = this.getJSDoc(node);
3026
+ // return '// ' + JSON.stringify(jsdoc) + '\n';
2227
3027
  var stat = this.getStatsForNode(node);
2228
3028
  if (!jsdoc) {
2229
3029
  stat.unchecked++;
@@ -2233,6 +3033,12 @@
2233
3033
  var spaces = this.spaces;
2234
3034
  var out = '';
2235
3035
  var first = true;
3036
+ var loc = this.getName(node);
3037
+ if (this.ignoreLocations.includes(loc)) {
3038
+ return '// IGNORE RTI TYPE VALIDATIONS, KNOWN ISSUES\n';
3039
+ }
3040
+ //out += `${spaces}/*${spaces} node.type=${node.type}\n${spaces}
3041
+ // ${JSON.stringify(jsdoc)}\n${parent}\n${spaces}*/\n`;
2236
3042
  var _loop = function _loop(name) {
2237
3043
  var type = jsdoc[name];
2238
3044
  var hasParam = _this2.nodeHasParamName(node, name);
@@ -2249,11 +3055,24 @@
2249
3055
  var isObjectPattern = param.type === 'ObjectPattern';
2250
3056
  var isArrayPattern = param.type === 'ArrayPattern';
2251
3057
  var isSupportedPattern = isObjectPattern || isArrayPattern;
3058
+ // There are four kinds of patterns:
3059
+ // ObjectPattern:
3060
+ // function test({x = 123}) {return x;} test({x: 456});
3061
+ // ArrayPattern:
3062
+ // function test([x = 123]) {return x;}; test([456]);
3063
+ // AssignmentPattern made up of ObjectPattern:
3064
+ // function test({x = 123} = {}) {return x;} test();
3065
+ // AssignmentPattern made up of ArrayPattern:
3066
+ // function test([x = 123] = []) {return x;} test();
2252
3067
  if (isSupportedPattern) {
3068
+ // The name doesn't matter any longer, because any pattern inherently
3069
+ // drops the identifier from the AST. But we can access it
3070
+ // via arguments[paramIndex] anyway.
2253
3071
  name = "arguments[".concat(paramIndex, "]");
2254
3072
  } else if (param.type === 'AssignmentPattern') {
2255
3073
  var _loc = _this2.getName(node);
2256
3074
  if (param.left.type === 'ArrayPattern' && type.type === 'array') {
3075
+ // Add a type assertion for each element of the ArrayPattern
2257
3076
  var _iterator = _createForOfIteratorHelper(param.left.elements),
2258
3077
  _step;
2259
3078
  try {
@@ -2272,8 +3091,9 @@
2272
3091
  } finally {
2273
3092
  _iterator.f();
2274
3093
  }
2275
- return 0;
3094
+ return 0; // continue
2276
3095
  } else if (param.left.type === 'ObjectPattern' && type.type === 'object') {
3096
+ // Add a type assertion for each property of the ObjectPattern
2277
3097
  var _iterator2 = _createForOfIteratorHelper(param.left.properties),
2278
3098
  _step2;
2279
3099
  try {
@@ -2302,15 +3122,15 @@
2302
3122
  } finally {
2303
3123
  _iterator2.f();
2304
3124
  }
2305
- return 0;
3125
+ return 0; // continue
2306
3126
  }
2307
3127
  _this2.warn("generateTypeChecks> ".concat(_loc, "> todo implement"), "AssignmentPattern for parameter ".concat(name));
2308
- return 0;
3128
+ return 0; // continue
2309
3129
  }
2310
3130
  } else {
2311
3131
  var _loc2 = _this2.getName(node);
2312
3132
  _this2.warn("generateTypeChecks> ".concat(_loc2, "> Missing param: ").concat(name));
2313
- return 0;
3133
+ return 0; // continue
2314
3134
  }
2315
3135
  }
2316
3136
  var t = JSON.stringify(type, null, 2).replaceAll('\n', '\n' + spaces);
@@ -2323,6 +3143,8 @@
2323
3143
  }
2324
3144
  var loc = _this2.getName(node);
2325
3145
  var prevCheck = '';
3146
+ // JSDoc doesn't support multiple function signatures yet, but this is
3147
+ // exactly what we would need to deal with ObjectPool'ing
2326
3148
  if (loc === 'ContactPoint#constructor' || loc === 'ContactResult#constructor' || loc === 'SingleContactResult#constructor') {
2327
3149
  prevCheck = 'arguments.length !== 0 && ';
2328
3150
  }
@@ -2340,15 +3162,25 @@
2340
3162
  }
2341
3163
  return out;
2342
3164
  }
3165
+ /**
3166
+ * @param {Node} node - The Babel AST node.
3167
+ * @returns {string} Best possible human-readable name of given node.
3168
+ */
2343
3169
  }, {
2344
3170
  key: "getNameForFunctionExpression",
2345
3171
  value: function getNameForFunctionExpression(node) {
2346
3172
  var objectProperty = this.findParentOfType(node, 'ObjectProperty');
2347
3173
  if (objectProperty) {
3174
+ // See good-old-es5.mjs example for a test case
3175
+ // TODO: Make an even better name based on Object.assign(ScopeSpace.prototype
3176
+ // Ideally we would figure out the name: ScopeSpace#resolve
3177
+ // Currently we only find "resolve" (still better than 'unnamed function expression'...)
2348
3178
  return this.toSource(objectProperty.key);
2349
3179
  }
2350
3180
  var expressionStatement = this.findParentOfType(node, 'ExpressionStatement');
2351
3181
  if (expressionStatement) {
3182
+ // There are many kinds of expressions
3183
+ // type Expression = ArrayExpression | AssignmentExpression | BinaryExpression | CallExpression | ...
2352
3184
  var left = expressionStatement.expression.left;
2353
3185
  if (left) {
2354
3186
  return this.toSource(left);
@@ -2357,6 +3189,10 @@
2357
3189
  }
2358
3190
  return 'unnamed function expression';
2359
3191
  }
3192
+ /**
3193
+ * @param {Node} node - The Babel AST node.
3194
+ * @returns {string} Stringification of the node.
3195
+ */
2360
3196
  }, {
2361
3197
  key: "getName",
2362
3198
  value: function getName(node) {
@@ -2400,6 +3236,11 @@
2400
3236
  return '/*MISSING*/';
2401
3237
  }
2402
3238
  }
3239
+ /**
3240
+ * @override
3241
+ * @param {import("@babel/types").BinaryExpression} node - The Babel AST node.
3242
+ * @returns {string} Stringification of the node.
3243
+ */
2403
3244
  }, {
2404
3245
  key: "BinaryExpression",
2405
3246
  value: function BinaryExpression(node) {
@@ -2418,7 +3259,14 @@
2418
3259
  }
2419
3260
  }, {
2420
3261
  key: "File",
2421
- value: function File(node) {
3262
+ value:
3263
+ /**
3264
+ * @override
3265
+ * @param {import("@babel/types").File} node - The Babel AST node.
3266
+ * @returns {string} Stringification of the node.
3267
+ */
3268
+ function File(node) {
3269
+ // @todo figure out why errors is in Babel node and not in @babel/types...
2422
3270
  var program = node.program,
2423
3271
  comments = node.comments;
2424
3272
  if (comments) {
@@ -2436,6 +3284,7 @@
2436
3284
  _iterator3.f();
2437
3285
  }
2438
3286
  }
3287
+ //console.log("this.typedefs", this.typedefs);
2439
3288
  var out = '';
2440
3289
  for (var name in this.typedefs) {
2441
3290
  var typedef = this.typedefs[name];
@@ -2450,7 +3299,24 @@
2450
3299
  return Asserter;
2451
3300
  }(Stringifier);
2452
3301
 
3302
+ /**
3303
+ * Simple facade which does all the processing. Processes the input
3304
+ * source string, adding runtime type checks based on JSDoc comments.
3305
+ *
3306
+ * This function takes JavaScript source code as input, parses it to an AST, traverses the
3307
+ * AST to find type annotations in JSDoc comments, and generates appropriate runtime type
3308
+ * assertions. These are then inserted into the source, producing a new version of the code
3309
+ * that includes runtime type checking based on the original JSDoc annotations.
3310
+ *
3311
+ * @param {string} src - The input source code containing JSDoc comments to be processed
3312
+ * for type checks.
3313
+ * @param {import('./Asserter.mjs').Options} [options] - Configuration options that dictate
3314
+ * how the processing is performed.
3315
+ * @returns {string} The transformed source code with inserted runtime type checks, or the
3316
+ * original source code commented with an error if processing fails.
3317
+ */
2453
3318
  function addTypeChecks(src, options) {
3319
+ console.log("GOT OPTIONS", options);
2454
3320
  try {
2455
3321
  var asserter = new Asserter(options);
2456
3322
  var ast = parser.parse(src, {
@@ -2465,28 +3331,45 @@
2465
3331
  }
2466
3332
  }
2467
3333
 
3334
+ /**
3335
+ * @param {object} ast - The Babel AST.
3336
+ * @returns {string} String representation in JSON format for debugging/inspecting the AST.
3337
+ */
2468
3338
  function ast2json(ast) {
2469
3339
  return JSON.stringify(ast, function (name, val) {
2470
3340
  if (name === "loc" || name === "start" || name === "end") {
2471
- return;
3341
+ return; // remove
2472
3342
  }
2473
- return val;
3343
+
3344
+ return val; // keep
2474
3345
  }, 2);
2475
3346
  }
2476
3347
 
2477
3348
  var drop = ['loc', 'start', 'end', 'leadingComments', 'trailingComments', 'innerComments', 'innerComments', 'comments'];
3349
+ /**
3350
+ * @example
3351
+ * setRight(ast2jsonForComparison(parseSync("/** *"))); // Close comment with / after last *
3352
+ * @param {object} ast - The Babel AST.
3353
+ * @returns {string} String representation in JSON format for debugging/inspecting the AST.
3354
+ */
2478
3355
  function ast2jsonForComparison(ast) {
2479
3356
  return JSON.stringify(ast, function (name, val) {
2480
3357
  if (name === 'trailingComma' || name === 'parenStart') {
2481
3358
  return 'offset removed for better comparison';
2482
3359
  }
2483
3360
  if (drop.includes(name)) {
2484
- return undefined;
3361
+ return undefined; // remove
2485
3362
  }
2486
- return val;
3363
+
3364
+ return val; // keep
2487
3365
  }, 2);
2488
3366
  }
2489
3367
 
3368
+ /**
3369
+ * A roundtrip between code -> AST -> code to validate Stringifier.
3370
+ * @param {string} code - The code.
3371
+ * @returns {string | undefined} The new and once parsed and stringified code.
3372
+ */
2490
3373
  function code2ast2code(code) {
2491
3374
  var stringifier = new Stringifier();
2492
3375
  var ast = parser.parse(code, {
@@ -2499,6 +3382,11 @@
2499
3382
  return out;
2500
3383
  }
2501
3384
 
3385
+ /**
3386
+ * @param {string} left - Left source code.
3387
+ * @param {string} right - Right source code.
3388
+ * @returns {boolean} Whether source codes are identical on the AST level.
3389
+ */
2502
3390
  function compareAST(left, right) {
2503
3391
  var l = parser.parse(left, {
2504
3392
  sourceType: 'module'
@@ -2512,19 +3400,70 @@
2512
3400
  return test;
2513
3401
  }
2514
3402
 
3403
+ /**
3404
+ * Transforms a type string into a structured type representation.
3405
+ *
3406
+ * This function parses a given type string and converts it into a TypeScript
3407
+ * Abstract Syntax Tree (AST), then uses that AST to return a structured type
3408
+ * representation that can be further utilized or interpreted.
3409
+ *
3410
+ * @todo Better handling of weird case: Array<>
3411
+ * @example
3412
+ * const {expandType} = await import("./src-transpiler/expandType.mjs");
3413
+ * expandType('[string, Array|AnyTypedArray, number[]]|[ONNXTensor]');
3414
+ * expandType('(123) '); // Outputs: '123'
3415
+ * expandType(' ( ( 123 ) ) '); // Outputs: '123'
3416
+ * expandType('Array<number> '); // Outputs: {type: 'array', elementType: 'number'}
3417
+ * expandType('Array<(123) > '); // Outputs: {type: 'array', elementType: '123'}
3418
+ * expandType('Array<"abc" | 123> '); // Outputs: {type: 'array', elementType: {type: 'union', members: ['"abc"', '123']}}
3419
+ * expandType(' (string ) |(number ) '); // Outputs: {type: 'union', members: [ 'string', 'number']}
3420
+ * expandType(' "apples" | ( "bananas") '); // Outputs: {type: 'union', members: [ '"apples"', '"bananas"']}
3421
+ * expandType('123? '); // Outputs: {"type":"union","members":["123","null"]}
3422
+ * expandType('123|null '); // Outputs: {"type":"union","members":["123","null"]}
3423
+ * expandType('Map<string, any> '); // Outputs:
3424
+ * expandType('typeof Number '); // Outputs:
3425
+ * @param {string} type - The type string to be expanded into a structured representation.
3426
+ * @todo Share type with expandTypeBabelTS and expandTypeDepFree
3427
+ * @returns {string | {type: string, [key: string]: any} | undefined} The structured type
3428
+ * representation obtained from parsing and converting the provided type string.
3429
+ */
2515
3430
  function expandType(type) {
2516
3431
  var ast = parseType(type);
2517
3432
  return toSourceTS(ast);
2518
3433
  }
3434
+ /**
3435
+ * @todo I want to use for example: import('typescript').Node
3436
+ * But the TS types make no sense to me so far ... need to investigate more.
3437
+ * @typedef TypeScriptType
3438
+ * @property {object[]|undefined} typeArguments - The type arguments.
3439
+ * @property {import('typescript').Node} typeName - The type name.
3440
+ * @property {number} kind - The kind for `ts.SyntaxKind[kind]`.
3441
+ */
3442
+ /**
3443
+ * @param {string} str - The type string.
3444
+ * @returns {TypeScriptType} - The node containing all the information about the input type string.
3445
+ */
2519
3446
  function parseType(str) {
3447
+ // TS doesn't like ... notation in this context
2520
3448
  if (str.startsWith('...')) {
2521
- str = str.slice(3);
2522
- str += '[]';
3449
+ str = str.slice(3); // remove dots
3450
+ str += '[]'; // turn into array
2523
3451
  }
3452
+ // type tmp = (...string) => 123; to have a function context
2524
3453
  str = "type tmp = ".concat(str, ";");
2525
- var ast = ts.createSourceFile('repl.ts', str, ts.ScriptTarget.Latest, true);
3454
+ var ast = ts.createSourceFile('repl.ts', str, ts.ScriptTarget.Latest, true /*setParentNodes*/);
2526
3455
  return ast.statements[0].type;
2527
3456
  }
3457
+ /**
3458
+ * Converts a TypeScript AST node to a source string representation or to an intermediate object describing the type.
3459
+ *
3460
+ * This function handles various TypeScript AST node types and converts them into a string
3461
+ * or an object representing the type.
3462
+ *
3463
+ * @param {TypeScriptType} node - The TypeScript AST node to convert.
3464
+ * @returns {string | {type: string, [key: string]: any} | undefined} The source string or an object with type information based on the node,
3465
+ * or `undefined` if the node kind is not handled.
3466
+ */
2528
3467
  function toSourceTS(node) {
2529
3468
  var typeArguments = node.typeArguments,
2530
3469
  typeName = node.typeName;
@@ -2570,18 +3509,22 @@
2570
3509
  KeyOfKeyword = _ts$SyntaxKind.KeyOfKeyword,
2571
3510
  ConstructorType = _ts$SyntaxKind.ConstructorType,
2572
3511
  NamedTupleMember = _ts$SyntaxKind.NamedTupleMember;
3512
+ // console.log({typeArguments, typeName, kind_, node});
2573
3513
  switch (node.kind) {
2574
3514
  case BigIntKeyword:
2575
3515
  return {
2576
3516
  type: 'bigint'
2577
3517
  };
2578
3518
  case BigIntLiteral:
2579
- var literal = node.text.slice(0, -1);
3519
+ var literal = node.text.slice(0, -1); // Remove the "n"
2580
3520
  return {
2581
3521
  type: 'bigint',
2582
3522
  literal: literal
2583
3523
  };
2584
3524
  case ConditionalType:
3525
+ // Keys on node:
3526
+ // ['pos', 'end', 'flags', 'modifierFlagsCache', 'transformFlags', 'parent', 'kind', 'checkType',
3527
+ // 'extendsType', 'trueType', 'falseType', 'locals', 'nextContainer']
2585
3528
  var checkType = toSourceTS(node.checkType);
2586
3529
  var extendsType = toSourceTS(node.extendsType);
2587
3530
  var trueType = toSourceTS(node.trueType);
@@ -2629,6 +3572,8 @@
2629
3572
  type: 'union',
2630
3573
  members: [t, 'null']
2631
3574
  };
3575
+ // todo work out more: const jsdoc = `(...a: ...number) => 123
3576
+ // TS even thinks it's two parameters... just go for array/[]
2632
3577
  case Parameter:
2633
3578
  var type = node.type ? toSourceTS(node.type) : 'any';
2634
3579
  var name = toSourceTS(node.name);
@@ -2761,6 +3706,7 @@
2761
3706
  return toSourceTS(node.literal);
2762
3707
  case AnyKeyword:
2763
3708
  case BooleanKeyword:
3709
+ // ts.SyntaxKind[parseType("*").kind] === 'JSDocAllType'
2764
3710
  case JSDocAllType:
2765
3711
  case NullKeyword:
2766
3712
  case NumericLiteral:
@@ -2779,10 +3725,17 @@
2779
3725
  properties: {}
2780
3726
  };
2781
3727
  case ParenthesizedType:
3728
+ // fall-through for parentheses
2782
3729
  return toSourceTS(node.type);
2783
3730
  case LastTypeNode:
2784
3731
  return toSourceTS(node.qualifier);
2785
3732
  default:
3733
+ // const test = {};
3734
+ // Object.entries(ts.SyntaxKind).forEach(([name, id]) => {
3735
+ // test[id] = (test[id] || []);
3736
+ // test[id].push(name);
3737
+ // });
3738
+ // console.log(test);
2786
3739
  console.warn('toSourceTS> unhandled kind - make sure to understand you cannot reverse TS enums');
2787
3740
  console.warn('if they contain range aliases, for example:');
2788
3741
  console.warn('ts.SyntaxKind.NumericLiteral === ts.SyntaxKind.FirstLiteralToken');
@@ -2791,17 +3744,58 @@
2791
3744
  }
2792
3745
  }
2793
3746
 
3747
+ /**
3748
+ * @todo Better handling of weird case: Array<>
3749
+ * @example
3750
+ * const {expandTypeBabelTS} = await import("./src-transpiler/expandTypeBabelTS.mjs");
3751
+ * expandTypeBabelTS('[string, Array|AnyTypedArray, number[]]|[ONNXTensor]');
3752
+ * expandTypeBabelTS('(123) '); // Outputs: '123'
3753
+ * expandTypeBabelTS(' ( ( 123 ) ) '); // Outputs: '123'
3754
+ * expandTypeBabelTS('Array<number> '); // Outputs: {type: 'array', elementType: 'number'}
3755
+ * expandTypeBabelTS('Array<(123) > '); // Outputs: {type: 'array', elementType: '123'}
3756
+ * expandTypeBabelTS('Array<"abc" | 123> '); // Outputs: {type: 'array', elementType: {type: 'union', members: ['"abc"', '123']}}
3757
+ * expandTypeBabelTS(' (string ) |(number ) '); // Outputs: {type: 'union', members: [ 'string', 'number']}
3758
+ * expandTypeBabelTS(' "apples" | ( "bananas") '); // Outputs: {type: 'union', members: [ '"apples"', '"bananas"']}
3759
+ * expandTypeBabelTS('123? '); // Outputs: {type: 'union', members: ['123', 'null']}
3760
+ * expandTypeBabelTS('123|null '); // Outputs: {type: 'union', members: ['123', 'null']}
3761
+ * expandTypeBabelTS('Map<string, any> '); // Outputs: {type: 'map', key: 'string', val: 'any'}
3762
+ * expandTypeBabelTS("(a: number, b: number) => number")
3763
+ * @param {string} type - The input type.
3764
+ * @returns {string|object|undefined} - See `toSourceBabelTS`.
3765
+ */
2794
3766
  function expandTypeBabelTS(type) {
2795
3767
  var ast = parseTypeBabelTS(type);
2796
3768
  return toSourceBabelTS(ast);
2797
3769
  }
3770
+ /**
3771
+ * @param {string} str - The type string.
3772
+ * @returns {import('@babel/types').Node} - The node containing all the information about the input type string.
3773
+ */
2798
3774
  function parseTypeBabelTS(str) {
3775
+ // TS doesn't like ... notation in this context
3776
+ //if (str.startsWith('...')) {
3777
+ // str = str.slice(3); // remove dots
3778
+ // str += '[]'; // turn into array
3779
+ //}
3780
+ // type tmp = (...string) => 123; to have a function context
2799
3781
  str = "type tmp = ".concat(str, ";");
2800
3782
  var ast = parser.parse(str, {
2801
3783
  plugins: ['typescript']
2802
3784
  });
2803
3785
  return ast.program.body[0].typeAnnotation;
2804
3786
  }
3787
+ /**
3788
+ * Converts a Babel AST node to its source string representation or structured type object.
3789
+ *
3790
+ * This function handles a variety of node types provided by Babel and converts them into a string
3791
+ * or an intermediate object representing the type, depending on the complexity of the type described by the node.
3792
+ *
3793
+ * @param {import('@babel/types').Node} node - The Babel AST node to convert.
3794
+ * @returns {string|object|undefined} - A string, object representing a structured type, or `undefined` for unhandled types.
3795
+ * Depending on the node, it may return a simple type string (e.g., `"string"` for `TSStringKeyword`),
3796
+ * a structured type object (e.g., a record type for `TSTypeReference` with type arguments),
3797
+ * or `undefined` if the encountered type is not handled. Unhandled types trigger a warning and enter a debugger statement.
3798
+ */
2805
3799
  function toSourceBabelTS(node) {
2806
3800
  switch (node.type) {
2807
3801
  case 'TSBigIntKeyword':
@@ -2814,10 +3808,34 @@
2814
3808
  type: 'bigint',
2815
3809
  literal: literal
2816
3810
  };
3811
+ // expandTypeBabelTS("(a: number, b: number) => number")
3812
+ /**
3813
+ * @todo the parameters are given as identifiers with "typeAnnotation"
3814
+ */
3815
+ // case 'TSFunctionType':
3816
+ // const parameters = node.parameters.map(toSourceBabelTS);
3817
+ // // I wish Babel AST would be like tsc AST here:
3818
+ // // parseType("(a: number, b: number) => number").parameters[0].kind === ts.SyntaxKind.Parameter
3819
+ // return {type: 'function', parameters};
3820
+ // Fix first: https://github.com/babel/babel/issues/16073
3821
+ //case 'JSDocNullableType':
3822
+ // const t = toSourceBabelTS(node.type);
3823
+ // return {type: 'union', members: [t, 'null']};
3824
+ // todo work out more: const jsdoc = `(...a: ...number) => 123
3825
+ // TS even thinks it's two parameters... just go for array/[]
3826
+ //case 'Parameter':
3827
+ // const type = node.type ? toSourceBabelTS(node.type) : 'any';
3828
+ // const name = toSourceBabelTS(node.name);
3829
+ // const ret = {type, name};
3830
+ // if (node.dotDotDotToken) {
3831
+ // return {type: 'array', elementType: ret};
3832
+ // }
3833
+ // return ret;
2817
3834
  case 'TSTypeReference':
2818
3835
  {
2819
3836
  var name = toSourceBabelTS(node.typeName);
2820
3837
  if (!node.typeParameters) {
3838
+ // console.log(`node.typeName.name=${node.typeName.name} name=${name}`, node);
2821
3839
  return node.typeName.name;
2822
3840
  }
2823
3841
  console.assert(node.typeParameters.type === 'TSTypeParameterInstantiation');
@@ -2901,6 +3919,9 @@
2901
3919
  type: 'object',
2902
3920
  properties: properties
2903
3921
  };
3922
+ // case 'PropertySignature':
3923
+ // console.warn('toSourceBabelTS> should not happen, handled by TypeLiteral directly');
3924
+ // return `${toSourceBabelTS(node.name)}: ${toSourceBabelTS(node.type)}`;
2904
3925
  case 'Identifier':
2905
3926
  return node.name;
2906
3927
  case 'TSArrayType':
@@ -2910,25 +3931,36 @@
2910
3931
  };
2911
3932
  case 'TSLiteralType':
2912
3933
  return toSourceBabelTS(node.literal);
3934
+ // expandTypeBabelTS("any")
2913
3935
  case 'TSAnyKeyword':
2914
3936
  return 'any';
3937
+ // expandTypeBabelTS("boolean")
2915
3938
  case 'TSBooleanKeyword':
2916
3939
  return 'boolean';
3940
+ // expandTypeBabelTS('true | false');
2917
3941
  case 'BooleanLiteral':
2918
3942
  return node.value.toString();
3943
+ // ts.SyntaxKind[parseType("*").kind] === 'JSDocAllType'
3944
+ // But Babel-TS doesn't parse it atm
3945
+ //case 'JSDocAllType':
3946
+ // expandTypeBabelTS('null')
2919
3947
  case 'TSNullKeyword':
2920
3948
  return 'null';
3949
+ // expandTypeBabelTS('123')
2921
3950
  case 'NumericLiteral':
2922
3951
  case 'StringLiteral':
2923
3952
  return node.extra.raw;
3953
+ // expandTypeBabelTS('undefined')
2924
3954
  case 'TSUndefinedKeyword':
2925
3955
  return 'undefined';
2926
3956
  case 'TSUnknownKeyword':
2927
3957
  return 'unknown';
2928
3958
  case 'TSNeverKeyword':
2929
3959
  return 'never';
3960
+ // parseTypeBabelTS('void');
2930
3961
  case 'TSVoidKeyword':
2931
3962
  return 'void';
3963
+ // expandTypeBabelTS('this')
2932
3964
  case 'TSThisType':
2933
3965
  return 'this';
2934
3966
  case 'ObjectKeyword':
@@ -2937,6 +3969,7 @@
2937
3969
  properties: {}
2938
3970
  };
2939
3971
  case 'ParenthesizedType':
3972
+ // fall-through for parentheses
2940
3973
  return toSourceBabelTS(node.type);
2941
3974
  case 'LastTypeNode':
2942
3975
  return toSourceBabelTS(node.qualifier);