flow-api-translator 0.331.0 → 0.333.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.
@@ -29,6 +29,7 @@ import {removeAtFlowFromDocblock} from './utils/DocblockUtils';
29
29
  import {
30
30
  ensureTypeIncludesUndefined,
31
31
  extractPropertyKeyLiterals,
32
+ getDefaultExportBindingName,
32
33
  } from './utils/TSNodeUtils';
33
34
  import {EOL} from 'os';
34
35
 
@@ -745,6 +746,66 @@ const getTransforms = (
745
746
  return () => `$$IMPORT_TYPEOF_${++typeof_import_count}$$`;
746
747
  })();
747
748
 
749
+ function transformImportTypeReference(
750
+ node:
751
+ | FlowESTree.ImportType
752
+ | FlowESTree.Identifier
753
+ | FlowESTree.QualifiedTypeIdentifier
754
+ | FlowESTree.QualifiedTypeofIdentifier,
755
+ typeArguments: TSESTree.TSTypeParameterInstantiation | null = null,
756
+ ): TSESTree.TSImportType | null {
757
+ const names: Array<FlowESTree.Identifier> = [];
758
+ let current = node;
759
+ while (
760
+ current.type === 'QualifiedTypeIdentifier' ||
761
+ current.type === 'QualifiedTypeofIdentifier'
762
+ ) {
763
+ names.unshift(current.id);
764
+ current = current.qualification;
765
+ }
766
+ if (current.type !== 'ImportType') {
767
+ return null;
768
+ }
769
+
770
+ let qualifier: TSESTree.EntityName | null = null;
771
+ for (const name of names) {
772
+ const identifier: TSESTree.Identifier = {
773
+ type: 'Identifier',
774
+ loc: DUMMY_LOC,
775
+ name: name.name,
776
+ };
777
+ qualifier =
778
+ qualifier == null
779
+ ? identifier
780
+ : {
781
+ type: 'TSQualifiedName',
782
+ loc: DUMMY_LOC,
783
+ left: qualifier,
784
+ right: identifier,
785
+ };
786
+ }
787
+
788
+ const source: TSESTree.StringLiteral = {
789
+ type: 'Literal',
790
+ loc: DUMMY_LOC,
791
+ raw: current.source.raw,
792
+ value: current.source.value,
793
+ };
794
+ return {
795
+ type: 'TSImportType',
796
+ loc: DUMMY_LOC,
797
+ argument: {
798
+ type: 'TSLiteralType',
799
+ loc: DUMMY_LOC,
800
+ literal: source,
801
+ },
802
+ options: null,
803
+ qualifier,
804
+ source,
805
+ typeArguments,
806
+ };
807
+ }
808
+
748
809
  const transformTypeAnnotationType = (
749
810
  node: FlowESTree.TypeAnnotationType,
750
811
  ): TSESTree.TypeNode => {
@@ -799,8 +860,12 @@ const getTransforms = (
799
860
  return transform.SymbolTypeAnnotation(node);
800
861
  case 'ThisTypeAnnotation':
801
862
  return transform.ThisTypeAnnotation(node);
863
+ case 'TemplateLiteralTypeAnnotation':
864
+ return transform.TemplateLiteralTypeAnnotation(node);
802
865
  case 'TupleTypeAnnotation':
803
866
  return transform.TupleTypeAnnotation(node);
867
+ case 'TupleTypeElement':
868
+ return transform.TupleTypeElement(node);
804
869
  case 'TypeofTypeAnnotation':
805
870
  return transform.TypeofTypeAnnotation(node);
806
871
  case 'UnionTypeAnnotation':
@@ -811,6 +876,8 @@ const getTransforms = (
811
876
  return transform.TypePredicateAnnotation(node);
812
877
  case 'ConditionalTypeAnnotation':
813
878
  return transform.ConditionalTypeAnnotation(node);
879
+ case 'ConstructorTypeAnnotation':
880
+ return transform.ConstructorTypeAnnotation(node);
814
881
  case 'InferTypeAnnotation':
815
882
  return transform.InferTypeAnnotation(node);
816
883
  case 'KeyofTypeAnnotation':
@@ -830,6 +897,83 @@ const getTransforms = (
830
897
  }
831
898
  };
832
899
 
900
+ /*
901
+ Flow can export a bare type, eg
902
+ ```
903
+ declare export default TypeName;
904
+ declare module.exports: TypeName;
905
+ ```
906
+ but TS can only export values, so declare a temporary variable to hold the
907
+ type and reference that in the export declaration:
908
+ ```
909
+ declare const SPECIFIER: TypeName;
910
+ declare type SPECIFIER = typeof SPECIFIER;
911
+ ```
912
+ */
913
+ const declareTypeAsVariable = (
914
+ specifier: string,
915
+ type: FlowESTree.TypeAnnotationType,
916
+ ): [TSESTree.VariableDeclaration, TSESTree.TSTypeAliasDeclaration] => [
917
+ {
918
+ type: 'VariableDeclaration',
919
+ loc: DUMMY_LOC,
920
+ declarations: [
921
+ {
922
+ type: 'VariableDeclarator',
923
+ loc: DUMMY_LOC,
924
+ id: {
925
+ type: 'Identifier',
926
+ loc: DUMMY_LOC,
927
+ name: specifier,
928
+ typeAnnotation: {
929
+ type: 'TSTypeAnnotation',
930
+ loc: DUMMY_LOC,
931
+ typeAnnotation: transformTypeAnnotationType(type),
932
+ },
933
+ },
934
+ init: null,
935
+ },
936
+ ],
937
+ declare: true,
938
+ kind: 'const',
939
+ },
940
+ {
941
+ type: 'TSTypeAliasDeclaration',
942
+ declare: true,
943
+ id: {
944
+ type: 'Identifier',
945
+ decorators: [],
946
+ name: specifier,
947
+ optional: false,
948
+ loc: DUMMY_LOC,
949
+ },
950
+ typeAnnotation: {
951
+ type: 'TSTypeQuery',
952
+ exprName: {
953
+ type: 'Identifier',
954
+ decorators: [],
955
+ name: specifier,
956
+ optional: false,
957
+ loc: DUMMY_LOC,
958
+ },
959
+ loc: DUMMY_LOC,
960
+ },
961
+ loc: DUMMY_LOC,
962
+ },
963
+ ];
964
+
965
+ // Whether `name` is bound at the top level by a class declaration, which is
966
+ // the one case where `typeof name` can be re-exported as `name` itself and
967
+ // keep both its value and its type meaning.
968
+ const isDeclaredClass = (name: string): boolean => {
969
+ const exportedVar = topScope.set.get(name);
970
+ return (
971
+ exportedVar != null &&
972
+ exportedVar.defs.length === 1 &&
973
+ exportedVar.defs[0].type === 'ClassName'
974
+ );
975
+ };
976
+
833
977
  const wellKnownSymbols = new Set([
834
978
  'iterator',
835
979
  'asyncIterator',
@@ -1127,6 +1271,29 @@ const getTransforms = (
1127
1271
  }
1128
1272
 
1129
1273
  const superClass = node.extends.length > 0 ? node.extends[0] : undefined;
1274
+ let superClassExpression: TSESTree.LeftHandSideExpression | null = null;
1275
+ let superTypeArguments: TSESTree.TSTypeParameterInstantiation | void;
1276
+ if (superClass != null) {
1277
+ switch (superClass.type) {
1278
+ case 'DeclareClassExtendsCall':
1279
+ return unsupportedDeclaration(
1280
+ superClass,
1281
+ 'mixin class extends clauses',
1282
+ node.id,
1283
+ true,
1284
+ node.typeParameters,
1285
+ );
1286
+ case 'InterfaceExtends':
1287
+ superClassExpression =
1288
+ superClass.id.type === 'QualifiedTypeIdentifier'
1289
+ ? transform.QualifiedTypeIdentifier(superClass.id)
1290
+ : transform.Identifier(superClass.id as $FlowFixMe, false);
1291
+ superTypeArguments = transform.TypeParameterInstantiation(
1292
+ superClass.typeParameters,
1293
+ );
1294
+ break;
1295
+ }
1296
+ }
1130
1297
 
1131
1298
  return {
1132
1299
  type: 'ClassDeclaration',
@@ -1142,15 +1309,8 @@ const getTransforms = (
1142
1309
  node.implements == null
1143
1310
  ? undefined
1144
1311
  : node.implements.map(transform.ClassImplements),
1145
- superClass:
1146
- superClass == null
1147
- ? null
1148
- : superClass.id.type === 'QualifiedTypeIdentifier'
1149
- ? transform.QualifiedTypeIdentifier(superClass.id)
1150
- : transform.Identifier(superClass.id as $FlowFixMe, false),
1151
- superTypeArguments: transform.TypeParameterInstantiation(
1152
- superClass?.typeParameters,
1153
- ),
1312
+ superClass: superClassExpression,
1313
+ superTypeArguments,
1154
1314
  typeParameters:
1155
1315
  node.typeParameters == null
1156
1316
  ? undefined
@@ -1209,6 +1369,14 @@ const getTransforms = (
1209
1369
  // TS doesn't support direct default export for declare'd functions
1210
1370
  case 'DeclareFunction': {
1211
1371
  const functionDecl = transform.DeclareFunction(declaration);
1372
+ if (declaration.id == null) {
1373
+ return {
1374
+ type: 'ExportDefaultDeclaration',
1375
+ loc: DUMMY_LOC,
1376
+ declaration: functionDecl,
1377
+ exportKind: 'value',
1378
+ };
1379
+ }
1212
1380
  const name = declaration.id.name;
1213
1381
  return [
1214
1382
  functionDecl,
@@ -1332,97 +1500,33 @@ const getTransforms = (
1332
1500
  case 'TypeofTypeAnnotation': {
1333
1501
  if (
1334
1502
  declaration.type === 'TypeofTypeAnnotation' &&
1335
- declaration.argument.type === 'Identifier'
1503
+ declaration.argument.type === 'Identifier' &&
1504
+ isDeclaredClass(declaration.argument.name)
1336
1505
  ) {
1337
- const name = declaration.argument.name;
1338
- const exportedVar = topScope.set.get(name);
1339
- if (exportedVar != null && exportedVar.defs.length === 1) {
1340
- const def = exportedVar.defs[0];
1341
-
1342
- switch (def.type) {
1343
- case 'ClassName': {
1344
- return {
1345
- type: 'ExportDefaultDeclaration',
1346
- declaration: {
1347
- type: 'Identifier',
1348
- decorators: [],
1349
- name,
1350
- optional: false,
1351
- loc: DUMMY_LOC,
1352
- },
1353
- exportKind: 'value',
1354
- loc: DUMMY_LOC,
1355
- };
1356
- }
1357
- }
1358
- }
1506
+ return {
1507
+ type: 'ExportDefaultDeclaration',
1508
+ declaration: {
1509
+ type: 'Identifier',
1510
+ decorators: [],
1511
+ name: declaration.argument.name,
1512
+ optional: false,
1513
+ loc: DUMMY_LOC,
1514
+ },
1515
+ exportKind: 'value',
1516
+ loc: DUMMY_LOC,
1517
+ };
1359
1518
  }
1360
1519
 
1361
1520
  // intentional fallthrough to the "default" handling
1362
1521
  }
1363
1522
 
1364
1523
  default: {
1365
- /*
1366
- flow allows syntax like
1367
- ```
1368
- declare export default TypeName;
1369
- ```
1370
- but TS does not, so we have to declare a temporary variable to
1371
- reference in the export declaration:
1372
- ```
1373
- declare const $$EXPORT_DEFAULT_DECLARATION$$: TypeName;
1374
- export default $$EXPORT_DEFAULT_DECLARATION$$;
1375
- ```
1376
- */
1377
- const SPECIFIER = '$$EXPORT_DEFAULT_DECLARATION$$';
1524
+ const SPECIFIER = getDefaultExportBindingName(
1525
+ declaration,
1526
+ opts.useSemanticDefaultExportNames === true,
1527
+ );
1378
1528
  return [
1379
- {
1380
- type: 'VariableDeclaration',
1381
- loc: DUMMY_LOC,
1382
- declarations: [
1383
- {
1384
- type: 'VariableDeclarator',
1385
- loc: DUMMY_LOC,
1386
- id: {
1387
- type: 'Identifier',
1388
- loc: DUMMY_LOC,
1389
- name: SPECIFIER,
1390
- typeAnnotation: {
1391
- type: 'TSTypeAnnotation',
1392
- loc: DUMMY_LOC,
1393
- typeAnnotation:
1394
- transformTypeAnnotationType(declaration),
1395
- },
1396
- },
1397
- init: null,
1398
- },
1399
- ],
1400
- declare: true,
1401
- kind: 'const',
1402
- },
1403
- {
1404
- type: 'TSTypeAliasDeclaration',
1405
- declare: true,
1406
- id: {
1407
- type: 'Identifier',
1408
- decorators: [],
1409
- name: SPECIFIER,
1410
- optional: false,
1411
- loc: DUMMY_LOC,
1412
- },
1413
- typeAnnotation: {
1414
- type: 'TSTypeQuery',
1415
- exprName: {
1416
- type: 'Identifier',
1417
- decorators: [],
1418
- name: SPECIFIER,
1419
- optional: false,
1420
- loc: DUMMY_LOC,
1421
- },
1422
- loc: DUMMY_LOC,
1423
- },
1424
- loc: DUMMY_LOC,
1425
- },
1529
+ ...declareTypeAsVariable(SPECIFIER, declaration),
1426
1530
  {
1427
1531
  type: 'ExportDefaultDeclaration',
1428
1532
  loc: DUMMY_LOC,
@@ -1494,6 +1598,17 @@ const getTransforms = (
1494
1598
  exportKind: 'type',
1495
1599
  },
1496
1600
  ];
1601
+ case 'DeclareNamespace':
1602
+ return [
1603
+ {
1604
+ declaration: unsupportedDeclaration(
1605
+ node.declaration,
1606
+ 'namespaces',
1607
+ node.declaration.id,
1608
+ ),
1609
+ exportKind: 'value',
1610
+ },
1611
+ ];
1497
1612
  case 'DeclareOpaqueType':
1498
1613
  return [
1499
1614
  {
@@ -1788,11 +1903,12 @@ const getTransforms = (
1788
1903
  DeclareFunction(
1789
1904
  node: FlowESTree.DeclareFunction,
1790
1905
  ): TSESTree.TSDeclareFunction {
1791
- // the function information is stored as an annotation on the ID...
1792
- const id = transform.Identifier(node.id, false);
1793
- const functionInfo = transform.FunctionTypeAnnotation(
1794
- node.id.typeAnnotation.typeAnnotation,
1795
- );
1906
+ const annotation = node.id?.typeAnnotation ?? node.typeAnnotation;
1907
+ if (annotation == null) {
1908
+ throw translationError(node, 'Declare function is missing its type');
1909
+ }
1910
+ const functionType = annotation.typeAnnotation;
1911
+ const functionInfo = transform.FunctionTypeAnnotation(functionType);
1796
1912
 
1797
1913
  return {
1798
1914
  type: 'TSDeclareFunction',
@@ -1802,11 +1918,14 @@ const getTransforms = (
1802
1918
  declare: true,
1803
1919
  expression: false,
1804
1920
  generator: false,
1805
- id: {
1806
- type: 'Identifier',
1807
- loc: DUMMY_LOC,
1808
- name: id.name,
1809
- },
1921
+ id:
1922
+ node.id == null
1923
+ ? null
1924
+ : {
1925
+ type: 'Identifier',
1926
+ loc: DUMMY_LOC,
1927
+ name: node.id.name,
1928
+ },
1810
1929
  params: functionInfo.params,
1811
1930
  returnType: functionInfo.returnType,
1812
1931
  typeParameters: functionInfo.typeParameters,
@@ -1974,8 +2093,65 @@ const getTransforms = (
1974
2093
  },
1975
2094
  DeclareModuleExports(
1976
2095
  node: FlowESTree.DeclareModuleExports,
1977
- ): TSESTree.TypeNode {
1978
- throw translationError(node, 'CommonJS exports are not supported.');
2096
+ ):
2097
+ | TSESTree.TSExportAssignment
2098
+ | [
2099
+ TSESTree.VariableDeclaration,
2100
+ TSESTree.TSTypeAliasDeclaration,
2101
+ TSESTree.TSExportAssignment,
2102
+ ] {
2103
+ // TS forbids `export = ` in a module that has any other export, so a
2104
+ // module combining the two has no faithful translation.
2105
+ if (
2106
+ node.parent.type === 'Program' &&
2107
+ node.parent.body.some(
2108
+ statement =>
2109
+ statement.type === 'DeclareExportAllDeclaration' ||
2110
+ statement.type === 'DeclareExportDeclaration' ||
2111
+ statement.type === 'ExportAllDeclaration' ||
2112
+ statement.type === 'ExportDefaultDeclaration' ||
2113
+ statement.type === 'ExportNamedDeclaration',
2114
+ )
2115
+ ) {
2116
+ throw translationError(
2117
+ node,
2118
+ 'CommonJS exports cannot be combined with ES module exports.',
2119
+ );
2120
+ }
2121
+
2122
+ // `declare module.exports: T` is TS's `export = <value>`, which - like
2123
+ // `export default` - can only name a value.
2124
+ const type = node.typeAnnotation.typeAnnotation;
2125
+
2126
+ if (
2127
+ type.type === 'TypeofTypeAnnotation' &&
2128
+ type.argument.type === 'Identifier' &&
2129
+ isDeclaredClass(type.argument.name)
2130
+ ) {
2131
+ return {
2132
+ type: 'TSExportAssignment',
2133
+ loc: DUMMY_LOC,
2134
+ expression: {
2135
+ type: 'Identifier',
2136
+ loc: DUMMY_LOC,
2137
+ name: type.argument.name,
2138
+ },
2139
+ };
2140
+ }
2141
+
2142
+ const SPECIFIER = '$$MODULE_EXPORTS$$';
2143
+ return [
2144
+ ...declareTypeAsVariable(SPECIFIER, type),
2145
+ {
2146
+ type: 'TSExportAssignment',
2147
+ loc: DUMMY_LOC,
2148
+ expression: {
2149
+ type: 'Identifier',
2150
+ loc: DUMMY_LOC,
2151
+ name: SPECIFIER,
2152
+ },
2153
+ },
2154
+ ];
1979
2155
  },
1980
2156
  ExistsTypeAnnotation(
1981
2157
  node: FlowESTree.ExistsTypeAnnotation,
@@ -2086,8 +2262,48 @@ const getTransforms = (
2086
2262
  loc: DUMMY_LOC,
2087
2263
  exported: transform.Identifier(node.exported, false),
2088
2264
  local: transform.Identifier(node.local, false),
2089
- // flow does not support inline exportKind for named exports
2090
- exportKind: 'value',
2265
+ exportKind: node.exportKind,
2266
+ };
2267
+ },
2268
+ ConstructorTypeAnnotation(
2269
+ node: FlowESTree.ConstructorTypeAnnotation,
2270
+ ): TSESTree.TSConstructorType {
2271
+ const params = node.params.map(transform.FunctionTypeParam);
2272
+ if (node.rest != null) {
2273
+ const rest = node.rest;
2274
+ params.push({
2275
+ type: 'RestElement',
2276
+ loc: DUMMY_LOC,
2277
+ argument:
2278
+ rest.name == null
2279
+ ? {
2280
+ type: 'Identifier',
2281
+ loc: DUMMY_LOC,
2282
+ name: '$$REST$$',
2283
+ }
2284
+ : transform.Identifier(rest.name, false),
2285
+ typeAnnotation: {
2286
+ type: 'TSTypeAnnotation',
2287
+ loc: DUMMY_LOC,
2288
+ typeAnnotation: transformTypeAnnotationType(rest.typeAnnotation),
2289
+ },
2290
+ });
2291
+ }
2292
+
2293
+ return {
2294
+ type: 'TSConstructorType',
2295
+ loc: DUMMY_LOC,
2296
+ abstract: node.abstract,
2297
+ params,
2298
+ returnType: {
2299
+ type: 'TSTypeAnnotation',
2300
+ loc: DUMMY_LOC,
2301
+ typeAnnotation: transformTypeAnnotationType(node.returnType),
2302
+ },
2303
+ typeParameters:
2304
+ node.typeParameters == null
2305
+ ? undefined
2306
+ : transform.TypeParameterDeclaration(node.typeParameters),
2091
2307
  };
2092
2308
  },
2093
2309
  FunctionTypeAnnotation(
@@ -2136,7 +2352,10 @@ const getTransforms = (
2136
2352
  returnType: {
2137
2353
  type: 'TSTypeAnnotation',
2138
2354
  loc: DUMMY_LOC,
2139
- typeAnnotation: transformTypeAnnotationType(node.returnType),
2355
+ typeAnnotation:
2356
+ node.returnType == null
2357
+ ? {type: 'TSAnyKeyword', loc: DUMMY_LOC}
2358
+ : transformTypeAnnotationType(node.returnType),
2140
2359
  },
2141
2360
  typeParameters:
2142
2361
  node.typeParameters == null
@@ -2163,6 +2382,14 @@ const getTransforms = (
2163
2382
  GenericTypeAnnotation(
2164
2383
  node: FlowESTree.GenericTypeAnnotation,
2165
2384
  ): TSESTree.TypeNode {
2385
+ const importType = transformImportTypeReference(
2386
+ node.id,
2387
+ transform.TypeParameterInstantiation(node.typeParameters) ?? null,
2388
+ );
2389
+ if (importType != null) {
2390
+ return importType;
2391
+ }
2392
+
2166
2393
  const [fullTypeName, baseId] = (() => {
2167
2394
  let names: Array<string> = [];
2168
2395
  let currentNode = node.id;
@@ -3189,13 +3416,19 @@ const getTransforms = (
3189
3416
  }
3190
3417
  }
3191
3418
 
3419
+ const typeName =
3420
+ node.id.type === 'Identifier'
3421
+ ? transform.Identifier(node.id, false)
3422
+ : node.id.type === 'QualifiedTypeIdentifier'
3423
+ ? transform.QualifiedTypeIdentifier(node.id)
3424
+ : null;
3425
+ if (typeName == null) {
3426
+ throw unexpectedTranslationError(node, 'Unreachable import type');
3427
+ }
3192
3428
  return {
3193
3429
  type: 'TSTypeReference',
3194
3430
  loc: DUMMY_LOC,
3195
- typeName:
3196
- node.id.type === 'Identifier'
3197
- ? transform.Identifier(node.id, false)
3198
- : transform.QualifiedTypeIdentifier(node.id),
3431
+ typeName,
3199
3432
  typeArguments: transform.TypeParameterInstantiation(
3200
3433
  node.typeParameters,
3201
3434
  ),
@@ -3503,11 +3736,15 @@ const getTransforms = (
3503
3736
  },
3504
3737
  constraint: transformTypeAnnotationType(prop.sourceType),
3505
3738
  readonly:
3506
- prop.variance?.kind === 'plus' ||
3507
- prop.variance?.kind === 'readonly',
3739
+ prop.varianceOp ??
3740
+ (prop.variance?.kind === 'plus' ||
3741
+ prop.variance?.kind === 'readonly'),
3508
3742
  optional: prop.optional === 'Optional',
3509
3743
  typeAnnotation: transformTypeAnnotationType(prop.propType),
3510
- nameType: null,
3744
+ nameType:
3745
+ prop.nameType == null
3746
+ ? null
3747
+ : transformTypeAnnotationType(prop.nameType),
3511
3748
  };
3512
3749
 
3513
3750
  return tsProp;
@@ -3557,6 +3794,10 @@ const getTransforms = (
3557
3794
  );
3558
3795
  }
3559
3796
 
3797
+ if (property.type === 'ObjectTypePrivateField') {
3798
+ return unsupportedAnnotation(property, 'private type fields');
3799
+ }
3800
+
3560
3801
  members.push({
3561
3802
  start: property.range[0],
3562
3803
  node: transform.ObjectTypeProperty(property),
@@ -3678,6 +3919,8 @@ const getTransforms = (
3678
3919
  property,
3679
3920
  'object type with mapped type property',
3680
3921
  );
3922
+ } else if (property.type === 'ObjectTypePrivateField') {
3923
+ return unsupportedAnnotation(property, 'private type fields');
3681
3924
  } else {
3682
3925
  members.push({
3683
3926
  start: property.range[0],
@@ -3772,6 +4015,9 @@ const getTransforms = (
3772
4015
  node: FlowESTree.ObjectTypeIndexer,
3773
4016
  ): TSESTree.TSIndexSignature | TSESTree.TSPropertySignatureComputedName {
3774
4017
  if (node.key.type === 'GenericTypeAnnotation') {
4018
+ if (node.key.id.type === 'ImportType') {
4019
+ throw translationError(node, 'Unsupported import type indexer key');
4020
+ }
3775
4021
  const ident =
3776
4022
  node.key.id.type === 'Identifier' ? node.key.id : node.key.id.id;
3777
4023
  return {
@@ -3975,14 +4221,18 @@ const getTransforms = (
3975
4221
  node: FlowESTree.QualifiedTypeIdentifier,
3976
4222
  ): TSESTree.TSQualifiedName {
3977
4223
  const qual = node.qualification;
4224
+ if (qual.type === 'ImportType') {
4225
+ throw unexpectedTranslationError(qual, 'Unreachable import type');
4226
+ }
4227
+ const left =
4228
+ qual.type === 'Identifier'
4229
+ ? transform.Identifier(qual, false)
4230
+ : transform.QualifiedTypeIdentifier(qual);
3978
4231
 
3979
4232
  return {
3980
4233
  type: 'TSQualifiedName',
3981
4234
  loc: DUMMY_LOC,
3982
- left:
3983
- qual.type === 'Identifier'
3984
- ? transform.Identifier(qual, false)
3985
- : transform.QualifiedTypeIdentifier(qual),
4235
+ left,
3986
4236
  right: transform.Identifier(node.id, false),
3987
4237
  };
3988
4238
  },
@@ -3990,14 +4240,18 @@ const getTransforms = (
3990
4240
  node: FlowESTree.QualifiedTypeofIdentifier,
3991
4241
  ): TSESTree.TSQualifiedName {
3992
4242
  const qual = node.qualification;
4243
+ if (qual.type === 'ImportType') {
4244
+ throw unexpectedTranslationError(qual, 'Unreachable import type');
4245
+ }
4246
+ const left =
4247
+ qual.type === 'Identifier'
4248
+ ? transform.Identifier(qual, false)
4249
+ : transform.QualifiedTypeofIdentifier(qual);
3993
4250
 
3994
4251
  return {
3995
4252
  type: 'TSQualifiedName',
3996
4253
  loc: DUMMY_LOC,
3997
- left:
3998
- qual.type === 'Identifier'
3999
- ? transform.Identifier(qual, false)
4000
- : transform.QualifiedTypeofIdentifier(qual),
4254
+ left,
4001
4255
  right: transform.Identifier(node.id, false),
4002
4256
  };
4003
4257
  },
@@ -4059,6 +4313,24 @@ const getTransforms = (
4059
4313
  loc: DUMMY_LOC,
4060
4314
  };
4061
4315
  },
4316
+ TemplateLiteralTypeAnnotation(
4317
+ node: FlowESTree.TemplateLiteralTypeAnnotation,
4318
+ ): TSESTree.TSTemplateLiteralType {
4319
+ return {
4320
+ type: 'TSTemplateLiteralType',
4321
+ loc: DUMMY_LOC,
4322
+ quasis: node.quasis.map(quasi => ({
4323
+ type: 'TemplateElement',
4324
+ loc: DUMMY_LOC,
4325
+ tail: quasi.tail,
4326
+ value: {
4327
+ cooked: quasi.value.cooked,
4328
+ raw: quasi.value.raw,
4329
+ },
4330
+ })),
4331
+ types: node.types.map(transformTypeAnnotationType),
4332
+ };
4333
+ },
4062
4334
  TupleTypeAnnotation(
4063
4335
  node: FlowESTree.TupleTypeAnnotation,
4064
4336
  ): TSESTree.TSTupleType | TSESTree.TSTypeOperator {
@@ -4141,6 +4413,16 @@ const getTransforms = (
4141
4413
  }
4142
4414
  : tupleAnnot;
4143
4415
  },
4416
+ TupleTypeElement(node: FlowESTree.TupleTypeElement): TSESTree.TypeNode {
4417
+ const elementType = transformTypeAnnotationType(node.elementType);
4418
+ return node.optional
4419
+ ? {
4420
+ type: 'TSOptionalType',
4421
+ loc: DUMMY_LOC,
4422
+ typeAnnotation: elementType,
4423
+ }
4424
+ : elementType;
4425
+ },
4144
4426
  TypeAlias(node: FlowESTree.TypeAlias): TSESTree.TSTypeAliasDeclaration {
4145
4427
  return transform.DeclareTypeAlias(node);
4146
4428
  },
@@ -4154,6 +4436,30 @@ const getTransforms = (
4154
4436
  TypeofTypeAnnotation(
4155
4437
  node: FlowESTree.TypeofTypeAnnotation,
4156
4438
  ): TSESTree.TSTypeQuery {
4439
+ if (node.argument.type === 'ImportType') {
4440
+ const importType = transformImportTypeReference(node.argument);
4441
+ if (importType == null) {
4442
+ throw unexpectedTranslationError(node, 'Invalid import type');
4443
+ }
4444
+ return {
4445
+ type: 'TSTypeQuery',
4446
+ loc: DUMMY_LOC,
4447
+ exprName: importType,
4448
+ typeArguments: undefined,
4449
+ };
4450
+ }
4451
+ const importType =
4452
+ node.argument.type === 'QualifiedTypeofIdentifier'
4453
+ ? transformImportTypeReference(node.argument)
4454
+ : null;
4455
+ if (importType != null) {
4456
+ return {
4457
+ type: 'TSTypeQuery',
4458
+ loc: DUMMY_LOC,
4459
+ exprName: importType,
4460
+ typeArguments: undefined,
4461
+ };
4462
+ }
4157
4463
  switch (node.argument.type) {
4158
4464
  case 'Identifier':
4159
4465
  return {
@@ -4169,6 +4475,11 @@ const getTransforms = (
4169
4475
  exprName: transform.QualifiedTypeofIdentifier(node.argument),
4170
4476
  typeArguments: undefined,
4171
4477
  };
4478
+ default:
4479
+ throw unexpectedTranslationError(
4480
+ node.argument,
4481
+ 'Unexpected typeof annotation argument',
4482
+ );
4172
4483
  }
4173
4484
  },
4174
4485
  TypeParameter(node: FlowESTree.TypeParameter): TSESTree.TSTypeParameter {
@@ -4326,8 +4637,15 @@ const getTransforms = (
4326
4637
  typeAnnotation: transformTypeAnnotationType(node.argument),
4327
4638
  };
4328
4639
  },
4329
- TypeOperator(node: FlowESTree.RendersType): TSESTree.TypeNode {
4640
+ TypeOperator(node: FlowESTree.TypeOperator): TSESTree.TypeNode {
4330
4641
  switch (node.operator) {
4642
+ case 'unique':
4643
+ return {
4644
+ type: 'TSTypeOperator',
4645
+ loc: DUMMY_LOC,
4646
+ operator: 'unique',
4647
+ typeAnnotation: transformTypeAnnotationType(node.typeAnnotation),
4648
+ };
4331
4649
  case 'renders':
4332
4650
  case 'renders?':
4333
4651
  case 'renders*': {