flow-api-translator 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,15 +24,25 @@ var _ErrorUtils = require("./utils/ErrorUtils");
24
24
 
25
25
  var _DocblockUtils = require("./utils/DocblockUtils");
26
26
 
27
+ var _os = require("os");
28
+
27
29
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
28
30
 
29
31
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
30
32
 
31
33
  const cloneJSDocCommentsToNewNode = // $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
32
34
  _hermesTransform.cloneJSDocCommentsToNewNode;
35
+ const makeCommentOwnLine = // $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
36
+ _hermesTransform.makeCommentOwnLine;
33
37
  const VALID_REACT_IMPORTS = new Set(['React', 'react']);
34
38
 
35
- function flowDefToTSDef(originalCode, ast, scopeManager) {
39
+ function isValidReactImportOrGlobal(id) {
40
+ return VALID_REACT_IMPORTS.has(id.name) || id.name.startsWith('React$');
41
+ }
42
+
43
+ let shouldAddReactImport = null;
44
+
45
+ function flowDefToTSDef(originalCode, ast, scopeManager, opts) {
36
46
  const tsBody = [];
37
47
  const tsProgram = {
38
48
  type: 'Program',
@@ -40,7 +50,8 @@ function flowDefToTSDef(originalCode, ast, scopeManager) {
40
50
  sourceType: ast.sourceType,
41
51
  docblock: ast.docblock == null ? null : (0, _DocblockUtils.removeAtFlowFromDocblock)(ast.docblock)
42
52
  };
43
- const transform = getTransforms(originalCode, scopeManager);
53
+ shouldAddReactImport = null;
54
+ const [transform, code] = getTransforms(originalCode, scopeManager, opts);
44
55
 
45
56
  for (const node of ast.body) {
46
57
  if (node.type in transform) {
@@ -51,15 +62,37 @@ function flowDefToTSDef(originalCode, ast, scopeManager) {
51
62
  tsBody.push(...(Array.isArray(result) ? result : [result]));
52
63
  } else {
53
64
  throw (0, _ErrorUtils.unexpectedTranslationError)(node, `Unexpected node type ${node.type}`, {
54
- code: originalCode
65
+ code
55
66
  });
56
67
  }
57
68
  }
58
69
 
59
- return tsProgram;
70
+ if (shouldAddReactImport === true) {
71
+ tsBody.unshift({
72
+ type: 'ImportDeclaration',
73
+ assertions: [],
74
+ source: {
75
+ type: 'Literal',
76
+ value: 'react',
77
+ raw: "'react'"
78
+ },
79
+ specifiers: [{
80
+ type: 'ImportNamespaceSpecifier',
81
+ local: {
82
+ type: 'Identifier',
83
+ name: 'React'
84
+ }
85
+ }],
86
+ importKind: 'value'
87
+ });
88
+ }
89
+
90
+ return [tsProgram, code];
60
91
  }
61
92
 
62
- const getTransforms = (code, scopeManager) => {
93
+ const getTransforms = (originalCode, scopeManager, opts) => {
94
+ let code = originalCode;
95
+
63
96
  function translationError(node, message) {
64
97
  return (0, _ErrorUtils.translationError)(node, message, {
65
98
  code
@@ -72,8 +105,66 @@ const getTransforms = (code, scopeManager) => {
72
105
  });
73
106
  }
74
107
 
75
- function unsupportedTranslationError(node, thing) {
76
- return translationError(node, `Unsupported feature: Translating "${thing}" is currently not supported.`);
108
+ function unsupportedFeatureMessage(thing) {
109
+ return `Unsupported feature: Translating "${thing}" is currently not supported.`;
110
+ }
111
+
112
+ function buildCodeFrameForComment(node, message) {
113
+ return (0, _ErrorUtils.buildCodeFrame)(node, message, code, false);
114
+ }
115
+
116
+ function addErrorComment(node, message) {
117
+ var _node$comments;
118
+
119
+ const comment = {
120
+ type: 'Block',
121
+ value: `*${_os.EOL} * ${message.replace(new RegExp(_os.EOL, 'g'), `${_os.EOL} * `)}${_os.EOL}*`,
122
+ leading: true,
123
+ printed: false
124
+ };
125
+ code = makeCommentOwnLine(code, comment); // $FlowExpectedError[prop-missing]
126
+ // $FlowExpectedError[cannot-write]
127
+
128
+ (_node$comments = node.comments) != null ? _node$comments : node.comments = []; // $FlowExpectedError[prop-missing]
129
+ // $FlowExpectedError[incompatible-cast]
130
+
131
+ node.comments.push(comment);
132
+ }
133
+
134
+ function unsupportedAnnotation(node, thing) {
135
+ const message = unsupportedFeatureMessage(thing);
136
+
137
+ if (opts.recoverFromErrors) {
138
+ const codeFrame = buildCodeFrameForComment(node, message);
139
+ const newNode = {
140
+ type: 'TSAnyKeyword'
141
+ };
142
+ addErrorComment(newNode, codeFrame);
143
+ return newNode;
144
+ }
145
+
146
+ throw translationError(node, message);
147
+ }
148
+
149
+ function unsupportedDeclaration(node, thing, id, declare = false, typeParameters = null) {
150
+ const message = unsupportedFeatureMessage(thing);
151
+
152
+ if (opts.recoverFromErrors) {
153
+ const codeFrame = buildCodeFrameForComment(node, message);
154
+ const newNode = {
155
+ type: 'TSTypeAliasDeclaration',
156
+ declare,
157
+ id: transform.Identifier(id, false),
158
+ typeAnnotation: {
159
+ type: 'TSAnyKeyword'
160
+ },
161
+ typeParameters: typeParameters == null ? undefined : transform.TypeParameterDeclaration(typeParameters)
162
+ };
163
+ addErrorComment(newNode, codeFrame);
164
+ return newNode;
165
+ }
166
+
167
+ throw translationError(node, message);
77
168
  }
78
169
 
79
170
  const topScope = (() => {
@@ -87,7 +178,21 @@ const getTransforms = (code, scopeManager) => {
87
178
  })();
88
179
 
89
180
  function isReactImport(id) {
90
- let currentScope = scopeManager.acquire(id);
181
+ let currentScope = (() => {
182
+ let scope = null;
183
+ let node = id;
184
+
185
+ while (!scope && node) {
186
+ scope = scopeManager.acquire(node, true);
187
+ node = node.parent;
188
+ }
189
+
190
+ return scope;
191
+ })();
192
+
193
+ if (currentScope == null) {
194
+ throw new Error('unable to resolve scope');
195
+ }
91
196
 
92
197
  const variableDef = (() => {
93
198
  while (currentScope != null) {
@@ -99,11 +204,12 @@ const getTransforms = (code, scopeManager) => {
99
204
 
100
205
  currentScope = currentScope.upper;
101
206
  }
102
- })(); // No variable found, it must be global. Using the `React` variable is enough in this case.
207
+ })(); // No variable found, it is not imported.
208
+ // It could be a global though if isValidReactImportOrGlobal returns true.
103
209
 
104
210
 
105
211
  if (variableDef == null) {
106
- return VALID_REACT_IMPORTS.has(id.name) || id.name.startsWith('React$');
212
+ return false;
107
213
  }
108
214
 
109
215
  const def = variableDef.defs[0]; // Detect:
@@ -133,6 +239,393 @@ const getTransforms = (code, scopeManager) => {
133
239
  return false;
134
240
  }
135
241
 
242
+ function EnumImpl(node) {
243
+ const body = node.body;
244
+
245
+ if (body.type === 'EnumSymbolBody') {
246
+ /*
247
+ There's unfortunately no way for us to support this in a clean way.
248
+ We can get really close using this code:
249
+ ```
250
+ declare namespace SymbolEnum {
251
+ export const member1: unique symbol;
252
+ export type member1 = typeof member1;
253
+ export const member2: unique symbol;
254
+ export type member2 = typeof member2;
255
+ }
256
+ type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
257
+ ```
258
+ However as explained in https://github.com/microsoft/TypeScript/issues/43657:
259
+ "A unique symbol type is never transferred from one declaration to another through inference."
260
+ This intended behaviour in TS means that the usage of the fake-enum would look like this:
261
+ ```
262
+ const value: SymbolEnum.member1 = SymbolEnum.member1;
263
+ // ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
264
+ ```
265
+ Which is really clunky and shitty. It definitely works, but ofc it's not good.
266
+ We can go with this design if users are okay with it!
267
+ Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
268
+ */
269
+ return unsupportedDeclaration(node, 'symbol enums', node.id, FlowESTree.isDeclareEnum(node));
270
+ }
271
+
272
+ if (body.type === 'EnumBooleanBody') {
273
+ /*
274
+ TODO - TS enums only allow strings or numbers as their values - not booleans.
275
+ This means we need a non-ts-enum representation of the enum.
276
+ We can support boolean enums using a construct like this:
277
+ ```ts
278
+ declare namespace BooleanEnum {
279
+ export const member1: true;
280
+ export type member1 = typeof member1;
281
+ export const member2: false;
282
+ export type member2 = typeof member1;
283
+ }
284
+ declare type BooleanEnum = boolean;
285
+ ```
286
+ But it's pretty clunky and ugly.
287
+ Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
288
+ */
289
+ return unsupportedDeclaration(node, 'boolean enums', node.id, FlowESTree.isDeclareEnum(node));
290
+ }
291
+
292
+ const members = [];
293
+
294
+ for (const member of body.members) {
295
+ switch (member.type) {
296
+ case 'EnumDefaultedMember':
297
+ {
298
+ if (body.type === 'EnumNumberBody') {
299
+ // this should be impossible!
300
+ throw unexpectedTranslationError(member, 'Unexpected defaulted number enum member');
301
+ }
302
+
303
+ members.push({
304
+ type: 'TSEnumMember',
305
+ computed: false,
306
+ id: transform.Identifier(member.id, false),
307
+ initializer: {
308
+ type: 'Literal',
309
+ raw: `"${member.id.name}"`,
310
+ value: member.id.name
311
+ }
312
+ });
313
+ break;
314
+ }
315
+
316
+ case 'EnumNumberMember':
317
+ case 'EnumStringMember':
318
+ members.push({
319
+ type: 'TSEnumMember',
320
+ computed: false,
321
+ id: transform.Identifier(member.id, false),
322
+ initializer: member.init.literalType === 'string' ? transform.StringLiteral(member.init) : transform.NumericLiteral(member.init)
323
+ });
324
+ }
325
+ }
326
+
327
+ const bodyRepresentationType = body.type === 'EnumNumberBody' ? {
328
+ type: 'TSNumberKeyword'
329
+ } : {
330
+ type: 'TSStringKeyword'
331
+ };
332
+ const enumName = transform.Identifier(node.id, false);
333
+ return [{
334
+ type: 'TSEnumDeclaration',
335
+ const: false,
336
+ declare: true,
337
+ id: enumName,
338
+ members
339
+ }, // flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
340
+ // we can use declaration merging to declare these functions on the enum:
341
+
342
+ /*
343
+ declare enum Foo {
344
+ A = 1,
345
+ B = 2,
346
+ }
347
+ declare namespace Foo {
348
+ export function cast(value: number | null | undefined): Foo;
349
+ export function isValid(value: number | null | undefined): value is Foo;
350
+ export function members(): IterableIterator<Foo>;
351
+ export function getName(value: Foo): string;
352
+ }
353
+ */
354
+ {
355
+ type: 'TSModuleDeclaration',
356
+ declare: true,
357
+ id: enumName,
358
+ body: {
359
+ type: 'TSModuleBlock',
360
+ body: [// export function cast(value: number | null | undefined): Foo
361
+ {
362
+ type: 'ExportNamedDeclaration',
363
+ declaration: {
364
+ type: 'TSDeclareFunction',
365
+ id: {
366
+ type: 'Identifier',
367
+ name: 'cast'
368
+ },
369
+ generator: false,
370
+ expression: false,
371
+ async: false,
372
+ params: [{
373
+ type: 'Identifier',
374
+ name: 'value',
375
+ typeAnnotation: {
376
+ type: 'TSTypeAnnotation',
377
+ typeAnnotation: {
378
+ type: 'TSUnionType',
379
+ types: [bodyRepresentationType, {
380
+ type: 'TSNullKeyword'
381
+ }, {
382
+ type: 'TSUndefinedKeyword'
383
+ }]
384
+ }
385
+ }
386
+ }],
387
+ returnType: {
388
+ type: 'TSTypeAnnotation',
389
+ typeAnnotation: {
390
+ type: 'TSTypeReference',
391
+ typeName: enumName
392
+ }
393
+ }
394
+ },
395
+ specifiers: [],
396
+ source: null,
397
+ exportKind: 'value',
398
+ assertions: []
399
+ }, // export function isValid(value: number | null | undefined): value is Foo;
400
+ {
401
+ type: 'ExportNamedDeclaration',
402
+ declaration: {
403
+ type: 'TSDeclareFunction',
404
+ id: {
405
+ type: 'Identifier',
406
+ name: 'isValid'
407
+ },
408
+ generator: false,
409
+ expression: false,
410
+ async: false,
411
+ params: [{
412
+ type: 'Identifier',
413
+ name: 'value',
414
+ typeAnnotation: {
415
+ type: 'TSTypeAnnotation',
416
+ typeAnnotation: {
417
+ type: 'TSUnionType',
418
+ types: [bodyRepresentationType, {
419
+ type: 'TSNullKeyword'
420
+ }, {
421
+ type: 'TSUndefinedKeyword'
422
+ }]
423
+ }
424
+ }
425
+ }],
426
+ returnType: {
427
+ type: 'TSTypeAnnotation',
428
+ typeAnnotation: {
429
+ type: 'TSTypePredicate',
430
+ asserts: false,
431
+ parameterName: {
432
+ type: 'Identifier',
433
+ name: 'value'
434
+ },
435
+ typeAnnotation: {
436
+ type: 'TSTypeAnnotation',
437
+ typeAnnotation: {
438
+ type: 'TSTypeReference',
439
+ typeName: enumName
440
+ }
441
+ }
442
+ }
443
+ }
444
+ },
445
+ specifiers: [],
446
+ source: null,
447
+ exportKind: 'value',
448
+ assertions: []
449
+ }, // export function members(): IterableIterator<Foo>;
450
+ {
451
+ type: 'ExportNamedDeclaration',
452
+ declaration: {
453
+ type: 'TSDeclareFunction',
454
+ id: {
455
+ type: 'Identifier',
456
+ name: 'members'
457
+ },
458
+ generator: false,
459
+ expression: false,
460
+ async: false,
461
+ params: [],
462
+ returnType: {
463
+ type: 'TSTypeAnnotation',
464
+ typeAnnotation: {
465
+ type: 'TSTypeReference',
466
+ typeName: {
467
+ type: 'Identifier',
468
+ name: 'IterableIterator'
469
+ },
470
+ typeParameters: {
471
+ type: 'TSTypeParameterInstantiation',
472
+ params: [{
473
+ type: 'TSTypeReference',
474
+ typeName: enumName
475
+ }]
476
+ }
477
+ }
478
+ }
479
+ },
480
+ specifiers: [],
481
+ source: null,
482
+ exportKind: 'value',
483
+ assertions: []
484
+ }, // export function getName(value: Foo): string;
485
+ {
486
+ type: 'ExportNamedDeclaration',
487
+ declaration: {
488
+ type: 'TSDeclareFunction',
489
+ id: {
490
+ type: 'Identifier',
491
+ name: 'getName'
492
+ },
493
+ generator: false,
494
+ expression: false,
495
+ async: false,
496
+ params: [{
497
+ type: 'Identifier',
498
+ name: 'value',
499
+ typeAnnotation: {
500
+ type: 'TSTypeAnnotation',
501
+ typeAnnotation: {
502
+ type: 'TSTypeReference',
503
+ typeName: enumName
504
+ }
505
+ }
506
+ }],
507
+ returnType: {
508
+ type: 'TSTypeAnnotation',
509
+ typeAnnotation: {
510
+ type: 'TSStringKeyword'
511
+ }
512
+ }
513
+ },
514
+ specifiers: [],
515
+ source: null,
516
+ exportKind: 'value',
517
+ assertions: []
518
+ }]
519
+ }
520
+ }];
521
+ }
522
+
523
+ const getPlaceholderNameForTypeofImport = (() => {
524
+ let typeof_import_count = 0;
525
+ return () => `$$IMPORT_TYPEOF_${++typeof_import_count}$$`;
526
+ })();
527
+
528
+ const transformTypeAnnotationType = node => {
529
+ switch (node.type) {
530
+ case 'AnyTypeAnnotation':
531
+ return transform.AnyTypeAnnotation(node);
532
+
533
+ case 'ArrayTypeAnnotation':
534
+ return transform.ArrayTypeAnnotation(node);
535
+
536
+ case 'BigIntLiteralTypeAnnotation':
537
+ return transform.BigIntLiteralTypeAnnotation(node);
538
+
539
+ case 'BigIntTypeAnnotation':
540
+ return transform.BigIntTypeAnnotation(node);
541
+
542
+ case 'BooleanLiteralTypeAnnotation':
543
+ return transform.BooleanLiteralTypeAnnotation(node);
544
+
545
+ case 'BooleanTypeAnnotation':
546
+ return transform.BooleanTypeAnnotation(node);
547
+
548
+ case 'EmptyTypeAnnotation':
549
+ return transform.EmptyTypeAnnotation(node);
550
+
551
+ case 'ExistsTypeAnnotation':
552
+ return transform.ExistsTypeAnnotation(node);
553
+
554
+ case 'FunctionTypeAnnotation':
555
+ return transform.FunctionTypeAnnotation(node);
556
+
557
+ case 'GenericTypeAnnotation':
558
+ return transform.GenericTypeAnnotation(node);
559
+
560
+ case 'IndexedAccessType':
561
+ return transform.IndexedAccessType(node);
562
+
563
+ case 'InterfaceTypeAnnotation':
564
+ return transform.InterfaceTypeAnnotation(node);
565
+
566
+ case 'IntersectionTypeAnnotation':
567
+ return transform.IntersectionTypeAnnotation(node);
568
+
569
+ case 'MixedTypeAnnotation':
570
+ return transform.MixedTypeAnnotation(node);
571
+
572
+ case 'NullLiteralTypeAnnotation':
573
+ return transform.NullLiteralTypeAnnotation(node);
574
+
575
+ case 'NullableTypeAnnotation':
576
+ return transform.NullableTypeAnnotation(node);
577
+
578
+ case 'NumberLiteralTypeAnnotation':
579
+ return transform.NumberLiteralTypeAnnotation(node);
580
+
581
+ case 'NumberTypeAnnotation':
582
+ return transform.NumberTypeAnnotation(node);
583
+
584
+ case 'ObjectTypeAnnotation':
585
+ return transform.ObjectTypeAnnotation(node);
586
+
587
+ case 'OptionalIndexedAccessType':
588
+ return transform.OptionalIndexedAccessType(node);
589
+
590
+ case 'QualifiedTypeIdentifier':
591
+ return transform.QualifiedTypeIdentifier(node);
592
+
593
+ case 'StringLiteralTypeAnnotation':
594
+ return transform.StringLiteralTypeAnnotation(node);
595
+
596
+ case 'StringTypeAnnotation':
597
+ return transform.StringTypeAnnotation(node);
598
+
599
+ case 'SymbolTypeAnnotation':
600
+ return transform.SymbolTypeAnnotation(node);
601
+
602
+ case 'ThisTypeAnnotation':
603
+ return transform.ThisTypeAnnotation(node);
604
+
605
+ case 'TupleTypeAnnotation':
606
+ return transform.TupleTypeAnnotation(node);
607
+
608
+ case 'TupleTypeLabeledElement':
609
+ case 'TupleTypeSpreadElement':
610
+ return unsupportedAnnotation(node, node.type);
611
+
612
+ case 'TypeofTypeAnnotation':
613
+ return transform.TypeofTypeAnnotation(node);
614
+
615
+ case 'UnionTypeAnnotation':
616
+ return transform.UnionTypeAnnotation(node);
617
+
618
+ case 'VoidTypeAnnotation':
619
+ return transform.VoidTypeAnnotation(node);
620
+
621
+ case 'TypePredicate':
622
+ return unsupportedAnnotation(node, node.type);
623
+
624
+ default:
625
+ throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
626
+ }
627
+ };
628
+
136
629
  const transform = {
137
630
  AnyTypeAnnotation(_node) {
138
631
  return {
@@ -143,7 +636,7 @@ const getTransforms = (code, scopeManager) => {
143
636
  ArrayTypeAnnotation(node) {
144
637
  return {
145
638
  type: 'TSArrayType',
146
- elementType: transform.TypeAnnotationType(node.elementType)
639
+ elementType: transformTypeAnnotationType(node.elementType)
147
640
  };
148
641
  },
149
642
 
@@ -221,7 +714,7 @@ const getTransforms = (code, scopeManager) => {
221
714
  const transformedBody = transform.ObjectTypeAnnotation(node.body);
222
715
 
223
716
  if (transformedBody.type !== 'TSTypeLiteral') {
224
- throw translationError(node.body, 'Spreads in declare class are not allowed');
717
+ return unsupportedDeclaration(node.body, 'Spreads in declare class are not allowed', node.id, true, node.typeParameters);
225
718
  }
226
719
 
227
720
  for (const member of transformedBody.members) {
@@ -348,7 +841,7 @@ const getTransforms = (code, scopeManager) => {
348
841
  ```
349
842
  Let's put a pin in it for now and deal with it later if the need arises.
350
843
  */
351
- throw unsupportedTranslationError((_node$body$callProper = node.body.callProperties[0]) != null ? _node$body$callProper : node.body, 'call signatures on classes');
844
+ return unsupportedDeclaration((_node$body$callProper = node.body.callProperties[0]) != null ? _node$body$callProper : node.body, 'call signatures on classes', node.id, true, node.typeParameters);
352
845
  }
353
846
 
354
847
  default:
@@ -492,7 +985,7 @@ const getTransforms = (code, scopeManager) => {
492
985
  name: SPECIFIER,
493
986
  typeAnnotation: {
494
987
  type: 'TSTypeAnnotation',
495
- typeAnnotation: transform.TypeAnnotationType(declaration)
988
+ typeAnnotation: transformTypeAnnotationType(declaration)
496
989
  }
497
990
  },
498
991
  init: null
@@ -526,44 +1019,59 @@ const getTransforms = (code, scopeManager) => {
526
1019
  };
527
1020
  }
528
1021
 
529
- const {
530
- declaration,
531
- exportKind
532
- } = (() => {
1022
+ const declarations = (() => {
533
1023
  switch (node.declaration.type) {
534
1024
  case 'DeclareClass':
535
- return {
1025
+ return [{
536
1026
  declaration: transform.DeclareClass(node.declaration),
537
1027
  exportKind: 'value'
538
- };
1028
+ }];
539
1029
 
540
1030
  case 'DeclareFunction':
541
- return {
1031
+ return [{
542
1032
  declaration: transform.DeclareFunction(node.declaration),
543
1033
  exportKind: 'value'
544
- };
1034
+ }];
545
1035
 
546
1036
  case 'DeclareInterface':
547
- return {
1037
+ return [{
548
1038
  declaration: transform.DeclareInterface(node.declaration),
549
1039
  exportKind: 'type'
550
- };
1040
+ }];
551
1041
 
552
1042
  case 'DeclareOpaqueType':
553
- return {
1043
+ return [{
554
1044
  declaration: transform.DeclareOpaqueType(node.declaration),
555
1045
  exportKind: 'type'
556
- };
1046
+ }];
557
1047
 
558
1048
  case 'DeclareVariable':
559
- return {
1049
+ return [{
560
1050
  declaration: transform.DeclareVariable(node.declaration),
561
1051
  exportKind: 'value'
562
- };
1052
+ }];
1053
+
1054
+ case 'DeclareEnum':
1055
+ {
1056
+ const result = transform.DeclareEnum(node.declaration);
1057
+ return Array.isArray(result) ? [{
1058
+ declaration: result[0],
1059
+ exportKind: 'type'
1060
+ }, {
1061
+ declaration: result[1],
1062
+ exportKind: 'type'
1063
+ }] : [{
1064
+ declaration: result,
1065
+ exportKind: 'type'
1066
+ }];
1067
+ }
563
1068
  }
564
1069
  })();
565
1070
 
566
- return {
1071
+ return declarations.map(({
1072
+ declaration,
1073
+ exportKind
1074
+ }) => ({
567
1075
  type: 'ExportNamedDeclaration',
568
1076
  // flow does not currently support assertions
569
1077
  assertions: [],
@@ -571,7 +1079,7 @@ const getTransforms = (code, scopeManager) => {
571
1079
  exportKind,
572
1080
  source: null,
573
1081
  specifiers: []
574
- };
1082
+ }));
575
1083
  } else {
576
1084
  return {
577
1085
  type: 'ExportNamedDeclaration',
@@ -633,7 +1141,7 @@ const getTransforms = (code, scopeManager) => {
633
1141
  type: 'TSTypeAliasDeclaration',
634
1142
  declare: node.type === 'DeclareTypeAlias',
635
1143
  id: transform.Identifier(node.id, false),
636
- typeAnnotation: transform.TypeAnnotationType(node.right),
1144
+ typeAnnotation: transformTypeAnnotationType(node.right),
637
1145
  typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
638
1146
  };
639
1147
  },
@@ -647,313 +1155,40 @@ const getTransforms = (code, scopeManager) => {
647
1155
  declare: true,
648
1156
  id: transform.Identifier(node.id, false),
649
1157
  typeAnnotation: node.supertype == null ? {
650
- type: 'TSUnknownKeyword'
651
- } : transform.TypeAnnotationType(node.supertype),
652
- typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
653
- };
654
- },
655
-
656
- DeclareVariable(node) {
657
- return {
658
- type: 'VariableDeclaration',
659
- declare: true,
660
- declarations: [{
661
- type: 'VariableDeclarator',
662
- declare: true,
663
- id: transform.Identifier(node.id, true),
664
- init: null
665
- }],
666
- kind: 'var'
667
- };
668
- },
669
-
670
- EmptyTypeAnnotation(node) {
671
- // Flow's `empty` type doesn't map well to any types in TS.
672
- // The closest is `never`, but `never` has a number of different semantics
673
- // In reality no human code should ever directly use the `empty` type in flow
674
- // So let's put a pin in it for now
675
- throw unsupportedTranslationError(node, 'empty type');
676
- },
677
-
678
- EnumDeclaration(node) {
679
- const body = node.body;
680
-
681
- if (body.type === 'EnumSymbolBody') {
682
- /*
683
- There's unfortunately no way for us to support this in a clean way.
684
- We can get really close using this code:
685
- ```
686
- declare namespace SymbolEnum {
687
- export const member1: unique symbol;
688
- export type member1 = typeof member1;
689
- export const member2: unique symbol;
690
- export type member2 = typeof member2;
691
- }
692
- type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
693
- ```
694
- However as explained in https://github.com/microsoft/TypeScript/issues/43657:
695
- "A unique symbol type is never transferred from one declaration to another through inference."
696
- This intended behaviour in TS means that the usage of the fake-enum would look like this:
697
- ```
698
- const value: SymbolEnum.member1 = SymbolEnum.member1;
699
- // ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
700
- ```
701
- Which is really clunky and shitty. It definitely works, but ofc it's not good.
702
- We can go with this design if users are okay with it!
703
- Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
704
- */
705
- throw unsupportedTranslationError(node, 'symbol enums');
706
- }
707
-
708
- if (body.type === 'EnumBooleanBody') {
709
- /*
710
- TODO - TS enums only allow strings or numbers as their values - not booleans.
711
- This means we need a non-ts-enum representation of the enum.
712
- We can support boolean enums using a construct like this:
713
- ```ts
714
- declare namespace BooleanEnum {
715
- export const member1: true;
716
- export type member1 = typeof member1;
717
- export const member2: false;
718
- export type member2 = typeof member1;
719
- }
720
- declare type BooleanEnum = boolean;
721
- ```
722
- But it's pretty clunky and ugly.
723
- Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
724
- */
725
- throw unsupportedTranslationError(node, 'boolean enums');
726
- }
727
-
728
- const members = [];
729
-
730
- for (const member of body.members) {
731
- switch (member.type) {
732
- case 'EnumDefaultedMember':
733
- {
734
- if (body.type === 'EnumNumberBody') {
735
- // this should be impossible!
736
- throw unexpectedTranslationError(member, 'Unexpected defaulted number enum member');
737
- }
738
-
739
- members.push({
740
- type: 'TSEnumMember',
741
- computed: false,
742
- id: transform.Identifier(member.id, false),
743
- initializer: {
744
- type: 'Literal',
745
- raw: `"${member.id.name}"`,
746
- value: member.id.name
747
- }
748
- });
749
- break;
750
- }
751
-
752
- case 'EnumNumberMember':
753
- case 'EnumStringMember':
754
- members.push({
755
- type: 'TSEnumMember',
756
- computed: false,
757
- id: transform.Identifier(member.id, false),
758
- initializer: member.init.literalType === 'string' ? transform.StringLiteral(member.init) : transform.NumericLiteral(member.init)
759
- });
760
- }
761
- }
762
-
763
- const bodyRepresentationType = body.type === 'EnumNumberBody' ? {
764
- type: 'TSNumberKeyword'
765
- } : {
766
- type: 'TSStringKeyword'
767
- };
768
- const enumName = transform.Identifier(node.id, false);
769
- return [{
770
- type: 'TSEnumDeclaration',
771
- const: false,
772
- declare: true,
773
- id: enumName,
774
- members
775
- }, // flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
776
- // we can use declaration merging to declare these functions on the enum:
777
-
778
- /*
779
- declare enum Foo {
780
- A = 1,
781
- B = 2,
782
- }
783
- declare namespace Foo {
784
- export function cast(value: number | null | undefined): Foo;
785
- export function isValid(value: number | null | undefined): value is Foo;
786
- export function members(): IterableIterator<Foo>;
787
- export function getName(value: Foo): string;
788
- }
789
- */
790
- {
791
- type: 'TSModuleDeclaration',
792
- declare: true,
793
- id: enumName,
794
- body: {
795
- type: 'TSModuleBlock',
796
- body: [// export function cast(value: number | null | undefined): Foo
797
- {
798
- type: 'ExportNamedDeclaration',
799
- declaration: {
800
- type: 'TSDeclareFunction',
801
- id: {
802
- type: 'Identifier',
803
- name: 'cast'
804
- },
805
- generator: false,
806
- expression: false,
807
- async: false,
808
- params: [{
809
- type: 'Identifier',
810
- name: 'value',
811
- typeAnnotation: {
812
- type: 'TSTypeAnnotation',
813
- typeAnnotation: {
814
- type: 'TSUnionType',
815
- types: [bodyRepresentationType, {
816
- type: 'TSNullKeyword'
817
- }, {
818
- type: 'TSUndefinedKeyword'
819
- }]
820
- }
821
- }
822
- }],
823
- returnType: {
824
- type: 'TSTypeAnnotation',
825
- typeAnnotation: {
826
- type: 'TSTypeReference',
827
- typeName: enumName
828
- }
829
- }
830
- },
831
- specifiers: [],
832
- source: null,
833
- exportKind: 'value',
834
- assertions: []
835
- }, // export function isValid(value: number | null | undefined): value is Foo;
836
- {
837
- type: 'ExportNamedDeclaration',
838
- declaration: {
839
- type: 'TSDeclareFunction',
840
- id: {
841
- type: 'Identifier',
842
- name: 'isValid'
843
- },
844
- generator: false,
845
- expression: false,
846
- async: false,
847
- params: [{
848
- type: 'Identifier',
849
- name: 'value',
850
- typeAnnotation: {
851
- type: 'TSTypeAnnotation',
852
- typeAnnotation: {
853
- type: 'TSUnionType',
854
- types: [bodyRepresentationType, {
855
- type: 'TSNullKeyword'
856
- }, {
857
- type: 'TSUndefinedKeyword'
858
- }]
859
- }
860
- }
861
- }],
862
- returnType: {
863
- type: 'TSTypeAnnotation',
864
- typeAnnotation: {
865
- type: 'TSTypePredicate',
866
- asserts: false,
867
- parameterName: {
868
- type: 'Identifier',
869
- name: 'value'
870
- },
871
- typeAnnotation: {
872
- type: 'TSTypeAnnotation',
873
- typeAnnotation: {
874
- type: 'TSTypeReference',
875
- typeName: enumName
876
- }
877
- }
878
- }
879
- }
880
- },
881
- specifiers: [],
882
- source: null,
883
- exportKind: 'value',
884
- assertions: []
885
- }, // export function members(): IterableIterator<Foo>;
886
- {
887
- type: 'ExportNamedDeclaration',
888
- declaration: {
889
- type: 'TSDeclareFunction',
890
- id: {
891
- type: 'Identifier',
892
- name: 'members'
893
- },
894
- generator: false,
895
- expression: false,
896
- async: false,
897
- params: [],
898
- returnType: {
899
- type: 'TSTypeAnnotation',
900
- typeAnnotation: {
901
- type: 'TSTypeReference',
902
- typeName: {
903
- type: 'Identifier',
904
- name: 'IterableIterator'
905
- },
906
- typeParameters: {
907
- type: 'TSTypeParameterInstantiation',
908
- params: [{
909
- type: 'TSTypeReference',
910
- typeName: enumName
911
- }]
912
- }
913
- }
914
- }
915
- },
916
- specifiers: [],
917
- source: null,
918
- exportKind: 'value',
919
- assertions: []
920
- }, // export function getName(value: Foo): string;
921
- {
922
- type: 'ExportNamedDeclaration',
923
- declaration: {
924
- type: 'TSDeclareFunction',
925
- id: {
926
- type: 'Identifier',
927
- name: 'getName'
928
- },
929
- generator: false,
930
- expression: false,
931
- async: false,
932
- params: [{
933
- type: 'Identifier',
934
- name: 'value',
935
- typeAnnotation: {
936
- type: 'TSTypeAnnotation',
937
- typeAnnotation: {
938
- type: 'TSTypeReference',
939
- typeName: enumName
940
- }
941
- }
942
- }],
943
- returnType: {
944
- type: 'TSTypeAnnotation',
945
- typeAnnotation: {
946
- type: 'TSStringKeyword'
947
- }
948
- }
949
- },
950
- specifiers: [],
951
- source: null,
952
- exportKind: 'value',
953
- assertions: []
954
- }]
955
- }
956
- }];
1158
+ type: 'TSUnknownKeyword'
1159
+ } : transformTypeAnnotationType(node.supertype),
1160
+ typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
1161
+ };
1162
+ },
1163
+
1164
+ DeclareVariable(node) {
1165
+ return {
1166
+ type: 'VariableDeclaration',
1167
+ declare: true,
1168
+ declarations: [{
1169
+ type: 'VariableDeclarator',
1170
+ declare: true,
1171
+ id: transform.Identifier(node.id, true),
1172
+ init: null
1173
+ }],
1174
+ kind: node.kind
1175
+ };
1176
+ },
1177
+
1178
+ DeclareEnum(node) {
1179
+ return EnumImpl(node);
1180
+ },
1181
+
1182
+ EmptyTypeAnnotation(node) {
1183
+ // Flow's `empty` type doesn't map well to any types in TS.
1184
+ // The closest is `never`, but `never` has a number of different semantics
1185
+ // In reality no human code should ever directly use the `empty` type in flow
1186
+ // So let's put a pin in it for now
1187
+ return unsupportedAnnotation(node, 'empty type');
1188
+ },
1189
+
1190
+ EnumDeclaration(node) {
1191
+ return EnumImpl(node);
957
1192
  },
958
1193
 
959
1194
  DeclareModuleExports(node) {
@@ -963,7 +1198,7 @@ const getTransforms = (code, scopeManager) => {
963
1198
  ExistsTypeAnnotation(node) {
964
1199
  // The existential type does not map to any types in TS
965
1200
  // It's also super deprecated - so let's not ever worry
966
- throw unsupportedTranslationError(node, 'exestential type');
1201
+ return unsupportedAnnotation(node, 'existential type');
967
1202
  },
968
1203
 
969
1204
  ExportNamedDeclaration(node) {
@@ -982,11 +1217,12 @@ const getTransforms = (code, scopeManager) => {
982
1217
 
983
1218
  const [exportedDeclaration, mergedDeclaration] = (() => {
984
1219
  if (node.declaration == null) {
985
- return [null];
1220
+ return [null, null];
986
1221
  }
987
1222
 
988
1223
  switch (node.declaration.type) {
989
1224
  case 'ClassDeclaration':
1225
+ case 'ComponentDeclaration':
990
1226
  case 'FunctionDeclaration':
991
1227
  case 'VariableDeclaration':
992
1228
  // These cases shouldn't happen in flow defs because they have their own special
@@ -994,7 +1230,10 @@ const getTransforms = (code, scopeManager) => {
994
1230
  throw unexpectedTranslationError(node.declaration, `Unexpected named declaration found ${node.declaration.type}`);
995
1231
 
996
1232
  case 'EnumDeclaration':
997
- return transform.EnumDeclaration(node.declaration);
1233
+ {
1234
+ const result = transform.EnumDeclaration(node.declaration);
1235
+ return Array.isArray(result) ? result : [result, null];
1236
+ }
998
1237
 
999
1238
  case 'InterfaceDeclaration':
1000
1239
  return [transform.InterfaceDeclaration(node.declaration), null];
@@ -1050,7 +1289,7 @@ const getTransforms = (code, scopeManager) => {
1050
1289
  name: 'this',
1051
1290
  typeAnnotation: {
1052
1291
  type: 'TSTypeAnnotation',
1053
- typeAnnotation: transform.TypeAnnotationType(node.this.typeAnnotation)
1292
+ typeAnnotation: transformTypeAnnotationType(node.this.typeAnnotation)
1054
1293
  }
1055
1294
  });
1056
1295
  }
@@ -1065,7 +1304,7 @@ const getTransforms = (code, scopeManager) => {
1065
1304
  } : transform.Identifier(rest.name, false),
1066
1305
  typeAnnotation: {
1067
1306
  type: 'TSTypeAnnotation',
1068
- typeAnnotation: transform.TypeAnnotationType(rest.typeAnnotation)
1307
+ typeAnnotation: transformTypeAnnotationType(rest.typeAnnotation)
1069
1308
  }
1070
1309
  });
1071
1310
  }
@@ -1075,7 +1314,7 @@ const getTransforms = (code, scopeManager) => {
1075
1314
  params,
1076
1315
  returnType: {
1077
1316
  type: 'TSTypeAnnotation',
1078
- typeAnnotation: transform.TypeAnnotationType(node.returnType)
1317
+ typeAnnotation: transformTypeAnnotationType(node.returnType)
1079
1318
  },
1080
1319
  typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
1081
1320
  };
@@ -1087,7 +1326,7 @@ const getTransforms = (code, scopeManager) => {
1087
1326
  name: node.name == null ? `$$PARAM_${idx}$$` : node.name.name,
1088
1327
  typeAnnotation: {
1089
1328
  type: 'TSTypeAnnotation',
1090
- typeAnnotation: transform.TypeAnnotationType(node.typeAnnotation)
1329
+ typeAnnotation: transformTypeAnnotationType(node.typeAnnotation)
1091
1330
  },
1092
1331
  optional: node.optional
1093
1332
  };
@@ -1127,7 +1366,7 @@ const getTransforms = (code, scopeManager) => {
1127
1366
  const res = [];
1128
1367
 
1129
1368
  for (const param of node.typeParameters.params) {
1130
- res.push(transform.TypeAnnotationType(param));
1369
+ res.push(transformTypeAnnotationType(param));
1131
1370
  }
1132
1371
 
1133
1372
  return res;
@@ -1166,7 +1405,7 @@ const getTransforms = (code, scopeManager) => {
1166
1405
  type PropType = ReturnType<ExtractPropType<Obj>>; // number
1167
1406
  ```
1168
1407
  */
1169
- throw unsupportedTranslationError(node, fullTypeName);
1408
+ return unsupportedAnnotation(node, fullTypeName);
1170
1409
  }
1171
1410
 
1172
1411
  case '$Diff':
@@ -1411,20 +1650,93 @@ const getTransforms = (code, scopeManager) => {
1411
1650
  } // React special conversion:
1412
1651
 
1413
1652
 
1414
- if (isReactImport(baseId)) {
1415
- const reactId = {
1416
- type: 'Identifier',
1417
- name: `React`
1653
+ const validReactImportOrGlobal = isValidReactImportOrGlobal(baseId);
1654
+ const reactImport = isReactImport(baseId);
1655
+
1656
+ if (validReactImportOrGlobal || reactImport) {
1657
+ // Returns appropriate Identifier for `React` import.
1658
+ // If a global is in use, set a flag to indicate that we should add the import.
1659
+ const getReactIdentifier = () => {
1660
+ if (shouldAddReactImport !== false) {
1661
+ shouldAddReactImport = !reactImport;
1662
+ }
1663
+
1664
+ return {
1665
+ type: 'Identifier',
1666
+ name: `React`
1667
+ };
1418
1668
  };
1419
1669
 
1420
1670
  switch (fullTypeName) {
1671
+ // TODO: In flow this is `ChildrenArray<T> = T | $ReadOnlyArray<ChildrenArray<T>>`.
1672
+ // The recursive nature of it is rarely needed, so we're simplifying this for now
1673
+ // but omitting that aspect. Once we're able to provide utility types for our translations,
1674
+ // we should update this.
1675
+ // React.ChildrenArray<T> -> T | ReadonlyArray<T>
1676
+ // React$ChildrenArray<T> -> T | ReadonlyArray<T>
1677
+ case 'React.ChildrenArray':
1678
+ case 'React$ChildrenArray':
1679
+ {
1680
+ const [param] = assertHasExactlyNTypeParameters(1);
1681
+ return {
1682
+ type: 'TSUnionType',
1683
+ types: [param, {
1684
+ type: 'TSTypeReference',
1685
+ typeName: {
1686
+ type: 'Identifier',
1687
+ name: 'ReadonlyArray'
1688
+ },
1689
+ typeParameters: {
1690
+ type: 'TSTypeParameterInstantiation',
1691
+ params: [param]
1692
+ }
1693
+ }]
1694
+ };
1695
+ }
1696
+ // React.Component<A,B> -> React.Component<A,B>
1697
+ // React$Component<A,B> -> React.Component<A,B>
1698
+
1699
+ case 'React.Component':
1700
+ case 'React$Component':
1701
+ {
1702
+ const typeParameters = node.typeParameters;
1703
+
1704
+ if (typeParameters == null || typeParameters.params.length === 0) {
1705
+ throw translationError(node, `Expected at least 1 type parameter with \`${fullTypeName}\``);
1706
+ }
1707
+
1708
+ const params = typeParameters.params;
1709
+
1710
+ if (params.length > 2) {
1711
+ throw translationError(node, `Expected at no more than 2 type parameters with \`${fullTypeName}\``);
1712
+ }
1713
+
1714
+ return {
1715
+ type: 'TSTypeReference',
1716
+ typeName: {
1717
+ type: 'TSQualifiedName',
1718
+ left: getReactIdentifier(),
1719
+ right: {
1720
+ type: 'Identifier',
1721
+ name: 'Component'
1722
+ }
1723
+ },
1724
+ typeParameters: {
1725
+ type: 'TSTypeParameterInstantiation',
1726
+ params: params.map(param => transformTypeAnnotationType(param))
1727
+ }
1728
+ };
1729
+ }
1730
+ // React.Context<A> -> React.Context<A>
1731
+ // React$Context<A> -> React.Context<A>
1732
+
1421
1733
  case 'React$Context':
1422
1734
  case 'React.Context':
1423
1735
  return {
1424
1736
  type: 'TSTypeReference',
1425
1737
  typeName: {
1426
1738
  type: 'TSQualifiedName',
1427
- left: reactId,
1739
+ left: getReactIdentifier(),
1428
1740
  right: {
1429
1741
  type: 'Identifier',
1430
1742
  name: `Context`
@@ -1435,6 +1747,43 @@ const getTransforms = (code, scopeManager) => {
1435
1747
  params: assertHasExactlyNTypeParameters(1)
1436
1748
  }
1437
1749
  };
1750
+ // React.Key -> React.Key
1751
+ // React$Key -> React.Key
1752
+
1753
+ case 'React.Key':
1754
+ case 'React$Key':
1755
+ assertHasExactlyNTypeParameters(0);
1756
+ return {
1757
+ type: 'TSTypeReference',
1758
+ typeName: {
1759
+ type: 'TSQualifiedName',
1760
+ left: getReactIdentifier(),
1761
+ right: {
1762
+ type: 'Identifier',
1763
+ name: 'Key'
1764
+ }
1765
+ }
1766
+ };
1767
+ // React.ElementType -> React.ElementType
1768
+ // React$ElementType -> React.ElementType
1769
+
1770
+ case 'React$ElementType':
1771
+ case 'React.ElementType':
1772
+ {
1773
+ assertHasExactlyNTypeParameters(0);
1774
+ return {
1775
+ type: 'TSTypeReference',
1776
+ typeName: {
1777
+ type: 'TSQualifiedName',
1778
+ left: getReactIdentifier(),
1779
+ right: {
1780
+ type: 'Identifier',
1781
+ name: `ElementType`
1782
+ }
1783
+ },
1784
+ typeParameters: undefined
1785
+ };
1786
+ }
1438
1787
  // React.Node -> React.ReactNode
1439
1788
 
1440
1789
  case 'React$Node':
@@ -1445,7 +1794,7 @@ const getTransforms = (code, scopeManager) => {
1445
1794
  type: 'TSTypeReference',
1446
1795
  typeName: {
1447
1796
  type: 'TSQualifiedName',
1448
- left: reactId,
1797
+ left: getReactIdentifier(),
1449
1798
  right: {
1450
1799
  type: 'Identifier',
1451
1800
  name: `ReactNode`
@@ -1463,7 +1812,7 @@ const getTransforms = (code, scopeManager) => {
1463
1812
  type: 'TSTypeReference',
1464
1813
  typeName: {
1465
1814
  type: 'TSQualifiedName',
1466
- left: reactId,
1815
+ left: getReactIdentifier(),
1467
1816
  right: {
1468
1817
  type: 'Identifier',
1469
1818
  name: `ReactElement`
@@ -1484,7 +1833,7 @@ const getTransforms = (code, scopeManager) => {
1484
1833
  type: 'TSTypeReference',
1485
1834
  typeName: {
1486
1835
  type: 'TSQualifiedName',
1487
- left: reactId,
1836
+ left: getReactIdentifier(),
1488
1837
  right: {
1489
1838
  type: 'Identifier',
1490
1839
  name: `ElementRef`
@@ -1505,7 +1854,7 @@ const getTransforms = (code, scopeManager) => {
1505
1854
  type: 'TSTypeReference',
1506
1855
  typeName: {
1507
1856
  type: 'TSQualifiedName',
1508
- left: reactId,
1857
+ left: getReactIdentifier(),
1509
1858
  right: {
1510
1859
  type: 'Identifier',
1511
1860
  name: `Fragment`
@@ -1534,16 +1883,35 @@ const getTransforms = (code, scopeManager) => {
1534
1883
  typeParameters: undefined
1535
1884
  };
1536
1885
  }
1537
- // React.AbstractComponent<Config> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<unknown>>
1538
- // React.AbstractComponent<Config, Instance> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<Instance>>
1539
- // React$AbstractComponent<Config, Instance> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<Instance>>
1540
- // React.ComponentType<Config> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<unknown>>
1541
- // React$ComponentType<Config> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<unknown>>
1886
+ // React.ComponentType<Config> -> React.ComponentType<Config>
1887
+ // React$ComponentType<Config> -> React.ComponentType<Config>
1542
1888
 
1543
- case 'React.AbstractComponent':
1544
- case 'React$AbstractComponent':
1545
1889
  case 'React.ComponentType':
1546
1890
  case 'React$ComponentType':
1891
+ {
1892
+ return {
1893
+ type: 'TSTypeReference',
1894
+ typeName: {
1895
+ type: 'TSQualifiedName',
1896
+ left: getReactIdentifier(),
1897
+ right: {
1898
+ type: 'Identifier',
1899
+ name: 'ComponentType'
1900
+ }
1901
+ },
1902
+ typeParameters: {
1903
+ type: 'TSTypeParameterInstantiation',
1904
+ params: assertHasExactlyNTypeParameters(1)
1905
+ }
1906
+ };
1907
+ }
1908
+ // React.AbstractComponent<Config> -> React.ComponentType<Config>
1909
+ // React$AbstractComponent<Config> -> React.ComponentType<Config>
1910
+ // React.AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
1911
+ // React$AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
1912
+
1913
+ case 'React.AbstractComponent':
1914
+ case 'React$AbstractComponent':
1547
1915
  {
1548
1916
  const typeParameters = node.typeParameters;
1549
1917
 
@@ -1557,49 +1925,131 @@ const getTransforms = (code, scopeManager) => {
1557
1925
  throw translationError(node, `Expected at no more than 2 type parameters with \`${fullTypeName}\``);
1558
1926
  }
1559
1927
 
1560
- let newTypeParam = transform.TypeAnnotationType(params[0]);
1561
- newTypeParam = {
1562
- type: 'TSIntersectionType',
1563
- types: [newTypeParam, {
1564
- type: 'TSTypeReference',
1565
- typeName: {
1566
- type: 'TSQualifiedName',
1567
- left: {
1568
- type: 'Identifier',
1569
- name: 'React'
1928
+ const newParams = (() => {
1929
+ if (params.length === 1) {
1930
+ return assertHasExactlyNTypeParameters(1);
1931
+ }
1932
+
1933
+ const [props, ref] = assertHasExactlyNTypeParameters(2);
1934
+ return [{
1935
+ type: 'TSIntersectionType',
1936
+ types: [props, {
1937
+ type: 'TSTypeReference',
1938
+ typeName: {
1939
+ type: 'TSQualifiedName',
1940
+ left: {
1941
+ type: 'Identifier',
1942
+ name: 'React'
1943
+ },
1944
+ right: {
1945
+ type: 'Identifier',
1946
+ name: 'RefAttributes'
1947
+ }
1570
1948
  },
1571
- right: {
1572
- type: 'Identifier',
1573
- name: 'RefAttributes'
1949
+ typeParameters: {
1950
+ type: 'TSTypeParameterInstantiation',
1951
+ params: [ref]
1574
1952
  }
1575
- },
1576
- typeParameters: {
1577
- type: 'TSTypeParameterInstantiation',
1578
- params: [params[1] ? transform.TypeAnnotationType(params[1]) : {
1579
- type: 'TSUnknownKeyword'
1580
- }]
1953
+ }]
1954
+ }];
1955
+ })();
1956
+
1957
+ return {
1958
+ type: 'TSTypeReference',
1959
+ typeName: {
1960
+ type: 'TSQualifiedName',
1961
+ left: getReactIdentifier(),
1962
+ right: {
1963
+ type: 'Identifier',
1964
+ name: 'ComponentType'
1581
1965
  }
1582
- }]
1966
+ },
1967
+ typeParameters: {
1968
+ type: 'TSTypeParameterInstantiation',
1969
+ params: newParams
1970
+ }
1583
1971
  };
1972
+ }
1973
+ // React.ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
1974
+ // React$ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
1975
+
1976
+ case 'React.ElementConfig':
1977
+ case 'React$ElementConfig':
1978
+ {
1979
+ const [param] = assertHasExactlyNTypeParameters(1);
1584
1980
  return {
1585
1981
  type: 'TSTypeReference',
1586
1982
  typeName: {
1587
1983
  type: 'TSQualifiedName',
1588
- left: reactId,
1984
+ left: {
1985
+ type: 'Identifier',
1986
+ name: 'JSX'
1987
+ },
1589
1988
  right: {
1590
1989
  type: 'Identifier',
1591
- name: `ForwardRefExoticComponent`
1990
+ name: 'LibraryManagedAttributes'
1592
1991
  }
1593
1992
  },
1594
1993
  typeParameters: {
1595
1994
  type: 'TSTypeParameterInstantiation',
1596
- params: [newTypeParam]
1995
+ params: [param, {
1996
+ type: 'TSTypeReference',
1997
+ typeName: {
1998
+ type: 'TSQualifiedName',
1999
+ left: getReactIdentifier(),
2000
+ right: {
2001
+ type: 'Identifier',
2002
+ name: `ComponentProps`
2003
+ }
2004
+ },
2005
+ typeParameters: {
2006
+ type: 'TSTypeParameterInstantiation',
2007
+ params: [param]
2008
+ }
2009
+ }]
1597
2010
  }
1598
2011
  };
1599
2012
  }
2013
+ // React.Ref<C> -> NonNullable<React.Ref<C> | string | number>
2014
+ // React$Ref<C> -> NonNullable<React.Ref<C> | string | number>
2015
+
2016
+ case 'React.Ref':
2017
+ case 'React$Ref':
2018
+ return {
2019
+ type: 'TSTypeReference',
2020
+ typeName: {
2021
+ type: 'Identifier',
2022
+ name: 'NonNullable'
2023
+ },
2024
+ typeParameters: {
2025
+ type: 'TSTypeParameterInstantiation',
2026
+ params: [{
2027
+ type: 'TSUnionType',
2028
+ types: [{
2029
+ type: 'TSTypeReference',
2030
+ typeName: {
2031
+ type: 'TSQualifiedName',
2032
+ left: getReactIdentifier(),
2033
+ right: {
2034
+ type: 'Identifier',
2035
+ name: 'Ref'
2036
+ }
2037
+ },
2038
+ typeParameters: {
2039
+ type: 'TSTypeParameterInstantiation',
2040
+ params: assertHasExactlyNTypeParameters(1)
2041
+ }
2042
+ }, {
2043
+ type: 'TSStringKeyword'
2044
+ }, {
2045
+ type: 'TSNumberKeyword'
2046
+ }]
2047
+ }]
2048
+ }
2049
+ };
1600
2050
 
1601
2051
  default:
1602
- throw unsupportedTranslationError(node, fullTypeName);
2052
+ return unsupportedAnnotation(node, fullTypeName);
1603
2053
  }
1604
2054
  }
1605
2055
 
@@ -1623,8 +2073,8 @@ const getTransforms = (code, scopeManager) => {
1623
2073
  IndexedAccessType(node) {
1624
2074
  return {
1625
2075
  type: 'TSIndexedAccessType',
1626
- objectType: transform.TypeAnnotationType(node.objectType),
1627
- indexType: transform.TypeAnnotationType(node.indexType)
2076
+ objectType: transformTypeAnnotationType(node.objectType),
2077
+ indexType: transformTypeAnnotationType(node.indexType)
1628
2078
  };
1629
2079
  },
1630
2080
 
@@ -1641,63 +2091,63 @@ const getTransforms = (code, scopeManager) => {
1641
2091
  },
1642
2092
 
1643
2093
  ImportDeclaration(node) {
1644
- if (node.importKind === 'typeof') {
1645
- /*
1646
- TODO - this is a complicated change to support because TS
1647
- does not have typeof imports.
1648
- Making it a `type` import would change the meaning!
1649
- The only way to truly support this is to prefix all **usages** with `typeof T`.
1650
- eg:
1651
- ```
1652
- import typeof Foo from 'Foo';
1653
- type T = Foo;
1654
- ```
1655
- would become:
1656
- ```
1657
- import type Foo from 'Foo';
1658
- type T = typeof Foo;
1659
- ```
1660
- This seems simple, but will actually be super complicated for us to do with
1661
- our current translation architecture
1662
- */
1663
- throw unsupportedTranslationError(node, 'typeof imports');
1664
- }
1665
-
1666
2094
  const importKind = node.importKind;
1667
- return {
1668
- type: 'ImportDeclaration',
1669
- assertions: node.assertions.map(transform.ImportAttribute),
1670
- importKind: importKind != null ? importKind : 'value',
1671
- source: transform.StringLiteral(node.source),
1672
- specifiers: node.specifiers.map(spec => {
1673
- switch (spec.type) {
1674
- case 'ImportDefaultSpecifier':
1675
- return {
1676
- type: 'ImportDefaultSpecifier',
1677
- local: transform.Identifier(spec.local, false)
1678
- };
2095
+ const specifiers = [];
2096
+ const unsupportedSpecifiers = [];
2097
+ node.specifiers.forEach(spec => {
2098
+ let id = (() => {
2099
+ if (node.importKind === 'typeof' || spec.importKind === 'typeof') {
2100
+ const id = {
2101
+ type: 'Identifier',
2102
+ name: getPlaceholderNameForTypeofImport()
2103
+ };
2104
+ unsupportedSpecifiers.push({
2105
+ type: 'TSTypeAliasDeclaration',
2106
+ id: transform.Identifier(spec.local, false),
2107
+ typeAnnotation: {
2108
+ type: 'TSTypeQuery',
2109
+ exprName: id
2110
+ }
2111
+ });
2112
+ return id;
2113
+ }
1679
2114
 
1680
- case 'ImportNamespaceSpecifier':
1681
- return {
1682
- type: 'ImportNamespaceSpecifier',
1683
- local: transform.Identifier(spec.local, false)
1684
- };
2115
+ return transform.Identifier(spec.local, false);
2116
+ })();
1685
2117
 
1686
- case 'ImportSpecifier':
1687
- if (spec.importKind === 'typeof') {
1688
- // see above
1689
- throw unsupportedTranslationError(node, 'typeof imports');
1690
- }
2118
+ switch (spec.type) {
2119
+ case 'ImportDefaultSpecifier':
2120
+ specifiers.push({
2121
+ type: 'ImportDefaultSpecifier',
2122
+ local: id
2123
+ });
2124
+ return;
1691
2125
 
1692
- return {
1693
- type: 'ImportSpecifier',
1694
- importKind: spec.importKind === 'type' ? 'type' : null,
1695
- imported: transform.Identifier(spec.imported, false),
1696
- local: transform.Identifier(spec.local, false)
1697
- };
1698
- }
1699
- })
1700
- };
2126
+ case 'ImportNamespaceSpecifier':
2127
+ specifiers.push({
2128
+ type: 'ImportNamespaceSpecifier',
2129
+ local: id
2130
+ });
2131
+ return;
2132
+
2133
+ case 'ImportSpecifier':
2134
+ specifiers.push({
2135
+ type: 'ImportSpecifier',
2136
+ importKind: spec.importKind === 'typeof' || spec.importKind === 'type' ? 'type' : null,
2137
+ imported: transform.Identifier(spec.imported, false),
2138
+ local: id
2139
+ });
2140
+ return;
2141
+ }
2142
+ });
2143
+ const out = specifiers.length ? [{
2144
+ type: 'ImportDeclaration',
2145
+ assertions: node.assertions.map(transform.ImportAttribute),
2146
+ importKind: importKind === 'typeof' ? 'type' : importKind != null ? importKind : 'value',
2147
+ source: transform.StringLiteral(node.source),
2148
+ specifiers
2149
+ }] : [];
2150
+ return [...out, ...unsupportedSpecifiers];
1701
2151
  },
1702
2152
 
1703
2153
  InterfaceExtends(node) {
@@ -1729,7 +2179,7 @@ const getTransforms = (code, scopeManager) => {
1729
2179
  IntersectionTypeAnnotation(node) {
1730
2180
  return {
1731
2181
  type: 'TSIntersectionType',
1732
- types: node.types.map(transform.TypeAnnotationType)
2182
+ types: node.types.map(transformTypeAnnotationType)
1733
2183
  };
1734
2184
  },
1735
2185
 
@@ -1784,7 +2234,7 @@ const getTransforms = (code, scopeManager) => {
1784
2234
  type: 'TSNullKeyword'
1785
2235
  }, {
1786
2236
  type: 'TSUndefinedKeyword'
1787
- }, transform.TypeAnnotationType(node.typeAnnotation)]
2237
+ }, transformTypeAnnotationType(node.typeAnnotation)]
1788
2238
  };
1789
2239
  },
1790
2240
 
@@ -1841,7 +2291,7 @@ const getTransforms = (code, scopeManager) => {
1841
2291
 
1842
2292
 
1843
2293
  if (node.internalSlots.length > 0) {
1844
- throw unsupportedTranslationError(node.internalSlots[0], 'internal slots');
2294
+ return unsupportedAnnotation(node.internalSlots[0], 'internal slots');
1845
2295
  }
1846
2296
 
1847
2297
  if (!node.properties.find(FlowESTree.isObjectTypeSpreadProperty)) {
@@ -1852,6 +2302,11 @@ const getTransforms = (code, scopeManager) => {
1852
2302
  throw unexpectedTranslationError(property, 'Impossible state');
1853
2303
  }
1854
2304
 
2305
+ if (property.type === 'ObjectTypeMappedTypeProperty') {
2306
+ // TODO - Support mapped types
2307
+ return unsupportedAnnotation(property, 'object type with mapped type property');
2308
+ }
2309
+
1855
2310
  members.push({
1856
2311
  start: property.range[0],
1857
2312
  node: transform.ObjectTypeProperty(property)
@@ -1928,7 +2383,7 @@ const getTransforms = (code, scopeManager) => {
1928
2383
  - spreads of things that aren't "Identifiers"
1929
2384
  */
1930
2385
  if (members.length > 0) {
1931
- throw unsupportedTranslationError(node, 'object types with spreads, indexers and/or call properties at the same time');
2386
+ return unsupportedAnnotation(node, 'object types with spreads, indexers and/or call properties at the same time');
1932
2387
  }
1933
2388
 
1934
2389
  const typesToIntersect = [];
@@ -1936,16 +2391,19 @@ const getTransforms = (code, scopeManager) => {
1936
2391
  for (const property of node.properties) {
1937
2392
  if (property.type === 'ObjectTypeSpreadProperty') {
1938
2393
  if (members.length > 0) {
1939
- throw unsupportedTranslationError(property, 'object types with spreads in the middle or at the end');
2394
+ return unsupportedAnnotation(property, 'object types with spreads in the middle or at the end');
1940
2395
  }
1941
2396
 
1942
- const spreadType = transform.TypeAnnotationType(property.argument);
2397
+ const spreadType = transformTypeAnnotationType(property.argument);
1943
2398
 
1944
2399
  if (spreadType.type !== 'TSTypeReference') {
1945
- throw unsupportedTranslationError(property, 'object types with complex spreads');
2400
+ return unsupportedAnnotation(property, 'object types with complex spreads');
1946
2401
  }
1947
2402
 
1948
2403
  typesToIntersect.push(spreadType);
2404
+ } else if (property.type === 'ObjectTypeMappedTypeProperty') {
2405
+ // TODO - Support mapped types
2406
+ return unsupportedAnnotation(property, 'object type with mapped type property');
1949
2407
  } else {
1950
2408
  members.push({
1951
2409
  start: property.range[0],
@@ -2015,14 +2473,14 @@ const getTransforms = (code, scopeManager) => {
2015
2473
  name: node.id == null ? '$$Key$$' : node.id.name,
2016
2474
  typeAnnotation: {
2017
2475
  type: 'TSTypeAnnotation',
2018
- typeAnnotation: transform.TypeAnnotationType(node.key)
2476
+ typeAnnotation: transformTypeAnnotationType(node.key)
2019
2477
  }
2020
2478
  }],
2021
2479
  readonly: ((_node$variance = node.variance) == null ? void 0 : _node$variance.kind) === 'plus',
2022
2480
  static: node.static,
2023
2481
  typeAnnotation: {
2024
2482
  type: 'TSTypeAnnotation',
2025
- typeAnnotation: transform.TypeAnnotationType(node.value)
2483
+ typeAnnotation: transformTypeAnnotationType(node.value)
2026
2484
  }
2027
2485
  };
2028
2486
  },
@@ -2077,7 +2535,7 @@ const getTransforms = (code, scopeManager) => {
2077
2535
  static: node.static,
2078
2536
  typeAnnotation: {
2079
2537
  type: 'TSTypeAnnotation',
2080
- typeAnnotation: transform.TypeAnnotationType(node.value)
2538
+ typeAnnotation: transformTypeAnnotationType(node.value)
2081
2539
  }
2082
2540
  };
2083
2541
  },
@@ -2106,10 +2564,10 @@ const getTransforms = (code, scopeManager) => {
2106
2564
  },
2107
2565
  typeParameters: {
2108
2566
  type: 'TSTypeParameterInstantiation',
2109
- params: [transform.TypeAnnotationType(node.objectType)]
2567
+ params: [transformTypeAnnotationType(node.objectType)]
2110
2568
  }
2111
2569
  },
2112
- indexType: transform.TypeAnnotationType(node.indexType)
2570
+ indexType: transformTypeAnnotationType(node.indexType)
2113
2571
  };
2114
2572
  },
2115
2573
 
@@ -2122,6 +2580,15 @@ const getTransforms = (code, scopeManager) => {
2122
2580
  };
2123
2581
  },
2124
2582
 
2583
+ QualifiedTypeofIdentifier(node) {
2584
+ const qual = node.qualification;
2585
+ return {
2586
+ type: 'TSQualifiedName',
2587
+ left: qual.type === 'Identifier' ? transform.Identifier(qual, false) : transform.QualifiedTypeofIdentifier(qual),
2588
+ right: transform.Identifier(node.id, false)
2589
+ };
2590
+ },
2591
+
2125
2592
  RegExpLiteral(node) {
2126
2593
  return {
2127
2594
  type: 'Literal',
@@ -2174,7 +2641,7 @@ const getTransforms = (code, scopeManager) => {
2174
2641
  TupleTypeAnnotation(node) {
2175
2642
  return {
2176
2643
  type: 'TSTupleType',
2177
- elementTypes: node.types.map(transform.TypeAnnotationType)
2644
+ elementTypes: node.types.map(transformTypeAnnotationType)
2178
2645
  };
2179
2646
  },
2180
2647
 
@@ -2185,116 +2652,26 @@ const getTransforms = (code, scopeManager) => {
2185
2652
  TypeAnnotation(node) {
2186
2653
  return {
2187
2654
  type: 'TSTypeAnnotation',
2188
- typeAnnotation: transform.TypeAnnotationType(node.typeAnnotation)
2655
+ typeAnnotation: transformTypeAnnotationType(node.typeAnnotation)
2189
2656
  };
2190
2657
  },
2191
2658
 
2192
- TypeAnnotationType(node) {
2193
- switch (node.type) {
2194
- case 'AnyTypeAnnotation':
2195
- return transform.AnyTypeAnnotation(node);
2196
-
2197
- case 'ArrayTypeAnnotation':
2198
- return transform.ArrayTypeAnnotation(node);
2199
-
2200
- case 'BigIntLiteralTypeAnnotation':
2201
- return transform.BigIntLiteralTypeAnnotation(node);
2202
-
2203
- case 'BigIntTypeAnnotation':
2204
- return transform.BigIntTypeAnnotation(node);
2205
-
2206
- case 'BooleanLiteralTypeAnnotation':
2207
- return transform.BooleanLiteralTypeAnnotation(node);
2208
-
2209
- case 'BooleanTypeAnnotation':
2210
- return transform.BooleanTypeAnnotation(node);
2211
-
2212
- case 'EmptyTypeAnnotation':
2213
- return transform.EmptyTypeAnnotation(node);
2214
-
2215
- case 'ExistsTypeAnnotation':
2216
- return transform.ExistsTypeAnnotation(node);
2217
-
2218
- case 'FunctionTypeAnnotation':
2219
- return transform.FunctionTypeAnnotation(node);
2220
-
2221
- case 'GenericTypeAnnotation':
2222
- return transform.GenericTypeAnnotation(node);
2223
-
2224
- case 'IndexedAccessType':
2225
- return transform.IndexedAccessType(node);
2226
-
2227
- case 'InterfaceTypeAnnotation':
2228
- return transform.InterfaceTypeAnnotation(node);
2229
-
2230
- case 'IntersectionTypeAnnotation':
2231
- return transform.IntersectionTypeAnnotation(node);
2232
-
2233
- case 'MixedTypeAnnotation':
2234
- return transform.MixedTypeAnnotation(node);
2235
-
2236
- case 'NullLiteralTypeAnnotation':
2237
- return transform.NullLiteralTypeAnnotation(node);
2238
-
2239
- case 'NullableTypeAnnotation':
2240
- return transform.NullableTypeAnnotation(node);
2241
-
2242
- case 'NumberLiteralTypeAnnotation':
2243
- return transform.NumberLiteralTypeAnnotation(node);
2244
-
2245
- case 'NumberTypeAnnotation':
2246
- return transform.NumberTypeAnnotation(node);
2247
-
2248
- case 'ObjectTypeAnnotation':
2249
- return transform.ObjectTypeAnnotation(node);
2250
-
2251
- case 'OptionalIndexedAccessType':
2252
- return transform.OptionalIndexedAccessType(node);
2253
-
2254
- case 'QualifiedTypeIdentifier':
2255
- return transform.QualifiedTypeIdentifier(node);
2256
-
2257
- case 'StringLiteralTypeAnnotation':
2258
- return transform.StringLiteralTypeAnnotation(node);
2259
-
2260
- case 'StringTypeAnnotation':
2261
- return transform.StringTypeAnnotation(node);
2262
-
2263
- case 'SymbolTypeAnnotation':
2264
- return transform.SymbolTypeAnnotation(node);
2265
-
2266
- case 'ThisTypeAnnotation':
2267
- return transform.ThisTypeAnnotation(node);
2268
-
2269
- case 'TupleTypeAnnotation':
2270
- return transform.TupleTypeAnnotation(node);
2271
-
2272
- case 'TypeofTypeAnnotation':
2273
- return transform.TypeofTypeAnnotation(node);
2274
-
2275
- case 'UnionTypeAnnotation':
2276
- return transform.UnionTypeAnnotation(node);
2277
-
2278
- case 'VoidTypeAnnotation':
2279
- return transform.VoidTypeAnnotation(node);
2280
-
2281
- default:
2282
- throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
2283
- }
2284
- },
2285
-
2286
2659
  TypeofTypeAnnotation(node) {
2287
- const argument = transform.TypeAnnotationType(node.argument);
2660
+ switch (node.argument.type) {
2661
+ case 'Identifier':
2662
+ return {
2663
+ type: 'TSTypeQuery',
2664
+ exprName: transform.Identifier(node.argument),
2665
+ typeParameters: undefined
2666
+ };
2288
2667
 
2289
- if (argument.type !== 'TSTypeReference') {
2290
- throw unexpectedTranslationError(node, `Expected to find a type reference as the argument to the TypeofTypeAnnotation, but got ${node.argument.type}`);
2668
+ case 'QualifiedTypeofIdentifier':
2669
+ return {
2670
+ type: 'TSTypeQuery',
2671
+ exprName: transform.QualifiedTypeofIdentifier(node.argument),
2672
+ typeParameters: undefined
2673
+ };
2291
2674
  }
2292
-
2293
- return {
2294
- type: 'TSTypeQuery',
2295
- exprName: argument.typeName,
2296
- typeParameters: argument.typeParameters
2297
- };
2298
2675
  },
2299
2676
 
2300
2677
  TypeParameter(node) {
@@ -2323,8 +2700,8 @@ const getTransforms = (code, scopeManager) => {
2323
2700
  type: 'Identifier',
2324
2701
  name: node.name
2325
2702
  },
2326
- constraint: node.bound == null ? undefined : transform.TypeAnnotationType(node.bound.typeAnnotation),
2327
- default: node.default == null ? undefined : transform.TypeAnnotationType(node.default),
2703
+ constraint: node.bound == null ? undefined : transformTypeAnnotationType(node.bound.typeAnnotation),
2704
+ default: node.default == null ? undefined : transformTypeAnnotationType(node.default),
2328
2705
  in: false,
2329
2706
  out: false // in: variance.has('in'),
2330
2707
  // out: variance.has('out'),
@@ -2342,14 +2719,14 @@ const getTransforms = (code, scopeManager) => {
2342
2719
  TypeParameterInstantiation(node) {
2343
2720
  return {
2344
2721
  type: 'TSTypeParameterInstantiation',
2345
- params: node.params.map(transform.TypeAnnotationType)
2722
+ params: node.params.map(transformTypeAnnotationType)
2346
2723
  };
2347
2724
  },
2348
2725
 
2349
2726
  UnionTypeAnnotation(node) {
2350
2727
  return {
2351
2728
  type: 'TSUnionType',
2352
- types: node.types.map(transform.TypeAnnotationType)
2729
+ types: node.types.map(transformTypeAnnotationType)
2353
2730
  };
2354
2731
  },
2355
2732
 
@@ -2379,5 +2756,5 @@ const getTransforms = (code, scopeManager) => {
2379
2756
  };
2380
2757
  }
2381
2758
 
2382
- return transform;
2759
+ return [transform, code];
2383
2760
  };