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.
@@ -10,6 +10,120 @@ var _TranslationUtils = require("./utils/TranslationUtils");
10
10
  var _ErrorUtils = require("./utils/ErrorUtils");
11
11
  var _flowEstree = require("flow-estree");
12
12
  const EMPTY_TRANSLATION_RESULT = [null, []];
13
+ function isDocComment(comment) {
14
+ return comment.type === 'Block' && comment.value.startsWith('*') && !/@(flow|noflow|format)\b/.test(comment.value) && !comment.value.includes('Copyright');
15
+ }
16
+ function findDefaultExport(body) {
17
+ for (const statement of body) {
18
+ if (statement.type === 'ExportDefaultDeclaration' || statement.type === 'DeclareExportDeclaration' && statement.default === true) {
19
+ return statement;
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ function getExportedIdentifierName(defaultExport) {
25
+ const declaration = defaultExport.declaration;
26
+ if (declaration == null) {
27
+ return null;
28
+ }
29
+ let node = declaration;
30
+ while (node.type === 'AsExpression' || node.type === 'TypeCastExpression') {
31
+ node = node.expression;
32
+ }
33
+ if (node.type === 'TypeofTypeAnnotation') {
34
+ return node.argument.type === 'Identifier' ? node.argument.name : null;
35
+ }
36
+ return node.type === 'Identifier' ? node.name : null;
37
+ }
38
+ function findDeclarationByName(body, name) {
39
+ for (const statement of body) {
40
+ const declaration = statement.type === 'ExportNamedDeclaration' && statement.declaration != null ? statement.declaration : statement;
41
+ if ((declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration' || declaration.type === 'ComponentDeclaration') && declaration.id != null && declaration.id.name === name) {
42
+ return {
43
+ kind: declaration.type,
44
+ statement
45
+ };
46
+ }
47
+ if (declaration.type === 'VariableDeclaration' || declaration.type === 'DeclareVariable') {
48
+ for (const declarator of declaration.declarations) {
49
+ if (declarator.id.type === 'Identifier' && declarator.id.name === name) {
50
+ return {
51
+ kind: declaration.type,
52
+ statement
53
+ };
54
+ }
55
+ }
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function findDisplayName(body, name) {
61
+ for (const statement of body) {
62
+ if (statement.type === 'ExpressionStatement' && statement.expression.type === 'AssignmentExpression') {
63
+ const {
64
+ left,
65
+ right
66
+ } = statement.expression;
67
+ if (left.type === 'MemberExpression' && left.object.type === 'Identifier' && left.object.name === name && left.property.type === 'Identifier' && left.property.name === 'displayName' && right.type === 'Literal' && typeof right.value === 'string') {
68
+ return right.value;
69
+ }
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ function applyDefaultExportDocPlacement(body, translatedStatements, placement, code) {
75
+ if (placement === 'declaration') {
76
+ return code;
77
+ }
78
+ const defaultExport = findDefaultExport(body);
79
+ if (defaultExport == null || (0, _flowTransform.getLeadingCommentsForNode)(defaultExport).some(isDocComment)) {
80
+ return code;
81
+ }
82
+ const exportedName = getExportedIdentifierName(defaultExport);
83
+ if (exportedName == null) {
84
+ return code;
85
+ }
86
+ const exportedDeclaration = findDeclarationByName(body, exportedName);
87
+ if ((exportedDeclaration == null ? void 0 : exportedDeclaration.kind) === 'ClassDeclaration') {
88
+ return code;
89
+ }
90
+ const sources = [];
91
+ if (exportedDeclaration != null) {
92
+ sources.push(exportedDeclaration);
93
+ }
94
+ const displayName = findDisplayName(body, exportedName);
95
+ if (displayName != null && displayName !== exportedName) {
96
+ const displayNameDeclaration = findDeclarationByName(body, displayName);
97
+ if (displayNameDeclaration != null) {
98
+ sources.push(displayNameDeclaration);
99
+ }
100
+ }
101
+ const translatedDefaultExport = translatedStatements.get(defaultExport);
102
+ if (translatedDefaultExport == null) {
103
+ return code;
104
+ }
105
+ for (const source of sources) {
106
+ const docComments = (0, _flowTransform.getLeadingCommentsForNode)(source.statement).filter(isDocComment);
107
+ if (docComments.length === 0) {
108
+ continue;
109
+ }
110
+ let mutatedCode = code;
111
+ const clonedComments = docComments.map(comment => {
112
+ const clonedComment = (0, _flowTransform.cloneCommentWithMarkers)(comment);
113
+ mutatedCode = (0, _flowTransform.makeCommentOwnLine)(mutatedCode, clonedComment);
114
+ return clonedComment;
115
+ });
116
+ (0, _flowTransform.setCommentsOnNode)(translatedDefaultExport, [...(0, _flowTransform.getCommentsForNode)(translatedDefaultExport), ...clonedComments]);
117
+ if (placement === 'export') {
118
+ const translatedSource = translatedStatements.get(source.statement);
119
+ if (translatedSource != null) {
120
+ (0, _flowTransform.setCommentsOnNode)(translatedSource, (0, _flowTransform.getCommentsForNode)(translatedSource).filter(comment => !docComments.includes(comment)));
121
+ }
122
+ }
123
+ return mutatedCode;
124
+ }
125
+ return code;
126
+ }
13
127
  function convertArray(items, convert) {
14
128
  const resultItems = [];
15
129
  const deps = [];
@@ -39,7 +153,7 @@ function transferProgramStatementProperties(stmt, orgStmt) {
39
153
  stmt.loc = orgStmt.loc;
40
154
  }
41
155
  function flowToFlowDef(ast, code, scopeManager, opts) {
42
- var _ast$interpreter$valu, _ast$interpreter;
156
+ var _opts$defaultExportDo, _ast$interpreter$valu, _ast$interpreter;
43
157
  const context = (0, _TranslationUtils.createTranslationContext)(code, scopeManager, opts);
44
158
  const translatedStatements = new Map();
45
159
  function storeTranslatedStatement(stmt, orgStmt) {
@@ -100,9 +214,11 @@ function flowToFlowDef(ast, code, scopeManager, opts) {
100
214
  if (translatedStatement != null) {
101
215
  const optimizedStatement = stripUnusedDefs(translatedStatement, seenDeps, context);
102
216
  transferProgramStatementProperties(optimizedStatement, stmt);
217
+ storeTranslatedStatement(optimizedStatement, stmt);
103
218
  translatedBody.push(optimizedStatement);
104
219
  }
105
220
  }
221
+ const outputCode = applyDefaultExportDocPlacement(ast.body, translatedStatements, (_opts$defaultExportDo = opts.defaultExportDocPlacement) != null ? _opts$defaultExportDo : 'declaration', code);
106
222
  return [_flowTransform.t.Program({
107
223
  body: translatedBody,
108
224
  sourceType: ast.sourceType,
@@ -110,7 +226,7 @@ function flowToFlowDef(ast, code, scopeManager, opts) {
110
226
  comments: ast.comments,
111
227
  tokens: ast.tokens,
112
228
  docblock: ast.docblock
113
- }), code];
229
+ }), outputCode];
114
230
  }
115
231
  function convertExport(stmt, context) {
116
232
  switch (stmt.type) {
@@ -740,6 +856,9 @@ function convertSuperClass(superClass, superTypeArguments, context) {
740
856
  {
741
857
  const typeAnnotation = superClass.type === 'TypeCastExpression' ? superClass.typeAnnotation.typeAnnotation : superClass.typeAnnotation;
742
858
  if (typeAnnotation.type === 'GenericTypeAnnotation') {
859
+ if (typeAnnotation.id.type === 'ImportType') {
860
+ throw (0, _ErrorUtils.translationError)(superClass, 'SuperClass: Import type not supported', context);
861
+ }
743
862
  return convertSuperClassHelper((0, _flowTransform.asDetachedNode)(typeAnnotation.id), typeAnnotation, superTypeArguments, context);
744
863
  }
745
864
  if (typeAnnotation.type === 'TypeofTypeAnnotation') {
@@ -22,8 +22,10 @@ import type {
22
22
  ComponentDeclaration,
23
23
  ComponentParameter,
24
24
  ComponentTypeParameter,
25
+ Comment,
25
26
  DeclareClass,
26
27
  DeclareComponent,
28
+ DeclareExportDeclaration,
27
29
  DeclareHook,
28
30
  DeclareFunction,
29
31
  DeclareOpaqueType,
@@ -68,6 +70,7 @@ import type {
68
70
  import type {ScopeManager} from 'flow-eslint';
69
71
  import type {DetachedNode} from 'flow-transform';
70
72
  import type {
73
+ DefaultExportDocPlacement,
71
74
  Dep,
72
75
  TranslationContext,
73
76
  TranslationOptions,
@@ -79,7 +82,14 @@ import {
79
82
  analyzeTypeDependencies,
80
83
  } from './utils/FlowAnalyze';
81
84
  import {createTranslationContext} from './utils/TranslationUtils';
82
- import {asDetachedNode} from 'flow-transform';
85
+ import {
86
+ asDetachedNode,
87
+ cloneCommentWithMarkers,
88
+ getCommentsForNode,
89
+ getLeadingCommentsForNode,
90
+ makeCommentOwnLine,
91
+ setCommentsOnNode,
92
+ } from 'flow-transform';
83
93
  import {translationError, flowFixMeOrError} from './utils/ErrorUtils';
84
94
  import {
85
95
  isExpression,
@@ -103,6 +113,223 @@ type TranslatedResult<T> = [DetachedNode<T>, TranslatedDeps];
103
113
 
104
114
  type ProgramStatement = Statement | ModuleDeclaration;
105
115
 
116
+ type DefaultExport = ExportDefaultDeclaration | DeclareExportDeclaration;
117
+
118
+ type DeclarationMatch = {
119
+ kind: string,
120
+ statement: ProgramStatement,
121
+ };
122
+
123
+ /**
124
+ * A JSDoc-style block comment (`/** ... *\/`), excluding the license/pragma
125
+ * docblock, which describes the module rather than the exported value.
126
+ */
127
+ function isDocComment(comment: Comment): boolean {
128
+ return (
129
+ comment.type === 'Block' &&
130
+ comment.value.startsWith('*') &&
131
+ !/@(flow|noflow|format)\b/.test(comment.value) &&
132
+ !comment.value.includes('Copyright')
133
+ );
134
+ }
135
+
136
+ function findDefaultExport(
137
+ body: ReadonlyArray<ProgramStatement>,
138
+ ): ?DefaultExport {
139
+ for (const statement of body) {
140
+ if (
141
+ statement.type === 'ExportDefaultDeclaration' ||
142
+ (statement.type === 'DeclareExportDeclaration' &&
143
+ statement.default === true)
144
+ ) {
145
+ return statement;
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ /**
152
+ * Name of the exported identifier, unwrapping `as` casts and the `typeof X`
153
+ * form. Returns `null` for inline/anonymous declarations.
154
+ */
155
+ function getExportedIdentifierName(defaultExport: DefaultExport): ?string {
156
+ const declaration = defaultExport.declaration;
157
+ if (declaration == null) {
158
+ return null;
159
+ }
160
+
161
+ let node: ESNode = declaration;
162
+ while (node.type === 'AsExpression' || node.type === 'TypeCastExpression') {
163
+ node = node.expression;
164
+ }
165
+ if (node.type === 'TypeofTypeAnnotation') {
166
+ return node.argument.type === 'Identifier' ? node.argument.name : null;
167
+ }
168
+ return node.type === 'Identifier' ? node.name : null;
169
+ }
170
+
171
+ function findDeclarationByName(
172
+ body: ReadonlyArray<ProgramStatement>,
173
+ name: string,
174
+ ): ?DeclarationMatch {
175
+ for (const statement of body) {
176
+ const declaration =
177
+ statement.type === 'ExportNamedDeclaration' &&
178
+ statement.declaration != null
179
+ ? statement.declaration
180
+ : statement;
181
+
182
+ if (
183
+ (declaration.type === 'ClassDeclaration' ||
184
+ declaration.type === 'FunctionDeclaration' ||
185
+ declaration.type === 'ComponentDeclaration') &&
186
+ declaration.id != null &&
187
+ declaration.id.name === name
188
+ ) {
189
+ return {kind: declaration.type, statement};
190
+ }
191
+
192
+ // `DeclareVariable` is `declare const X` in an already-declaration input
193
+ if (
194
+ declaration.type === 'VariableDeclaration' ||
195
+ declaration.type === 'DeclareVariable'
196
+ ) {
197
+ for (const declarator of declaration.declarations) {
198
+ if (
199
+ declarator.id.type === 'Identifier' &&
200
+ declarator.id.name === name
201
+ ) {
202
+ return {kind: declaration.type, statement};
203
+ }
204
+ }
205
+ }
206
+ }
207
+ return null;
208
+ }
209
+
210
+ function findDisplayName(
211
+ body: ReadonlyArray<ProgramStatement>,
212
+ name: string,
213
+ ): ?string {
214
+ for (const statement of body) {
215
+ if (
216
+ statement.type === 'ExpressionStatement' &&
217
+ statement.expression.type === 'AssignmentExpression'
218
+ ) {
219
+ const {left, right} = statement.expression;
220
+ if (
221
+ left.type === 'MemberExpression' &&
222
+ left.object.type === 'Identifier' &&
223
+ left.object.name === name &&
224
+ left.property.type === 'Identifier' &&
225
+ left.property.name === 'displayName' &&
226
+ right.type === 'Literal' &&
227
+ typeof right.value === 'string'
228
+ ) {
229
+ return right.value;
230
+ }
231
+ }
232
+ }
233
+ return null;
234
+ }
235
+
236
+ /**
237
+ * Associate a declaration's documentation with the module's default export.
238
+ *
239
+ * Stripping the runtime implementation leaves the documentation on the
240
+ * declaration the `export default` aliases via `typeof`, which is not the
241
+ * symbol TypeScript resolves a default re-export to. Returns the (possibly
242
+ * mutated) source text, since cloned comments need a range that makes prettier
243
+ * print them on their own line.
244
+ */
245
+ function applyDefaultExportDocPlacement(
246
+ body: ReadonlyArray<ProgramStatement>,
247
+ translatedStatements: Map<ProgramStatement, DetachedNode<ProgramStatement>>,
248
+ placement: DefaultExportDocPlacement,
249
+ code: string,
250
+ ): string {
251
+ if (placement === 'declaration') {
252
+ return code;
253
+ }
254
+
255
+ const defaultExport = findDefaultExport(body);
256
+ if (
257
+ defaultExport == null ||
258
+ // Leave already-documented (and inline) default exports untouched.
259
+ getLeadingCommentsForNode(defaultExport).some(isDocComment)
260
+ ) {
261
+ return code;
262
+ }
263
+
264
+ const exportedName = getExportedIdentifierName(defaultExport);
265
+ if (exportedName == null) {
266
+ return code;
267
+ }
268
+
269
+ const exportedDeclaration = findDeclarationByName(body, exportedName);
270
+ // A directly-exported class keeps its declaration, where TypeScript already
271
+ // resolves the documentation; moving it would hide it.
272
+ if (exportedDeclaration?.kind === 'ClassDeclaration') {
273
+ return code;
274
+ }
275
+
276
+ // Statements whose leading comment may document the default export, in
277
+ // priority order.
278
+ const sources: Array<DeclarationMatch> = [];
279
+ if (exportedDeclaration != null) {
280
+ sources.push(exportedDeclaration);
281
+ }
282
+ // Renamed wrappers (e.g. `memo`-wrapped) carry the documentation on the
283
+ // declaration matching the display name.
284
+ const displayName = findDisplayName(body, exportedName);
285
+ if (displayName != null && displayName !== exportedName) {
286
+ const displayNameDeclaration = findDeclarationByName(body, displayName);
287
+ if (displayNameDeclaration != null) {
288
+ sources.push(displayNameDeclaration);
289
+ }
290
+ }
291
+
292
+ const translatedDefaultExport = translatedStatements.get(defaultExport);
293
+ if (translatedDefaultExport == null) {
294
+ return code;
295
+ }
296
+
297
+ for (const source of sources) {
298
+ const docComments = getLeadingCommentsForNode(source.statement).filter(
299
+ isDocComment,
300
+ );
301
+ if (docComments.length === 0) {
302
+ continue;
303
+ }
304
+
305
+ let mutatedCode = code;
306
+ const clonedComments = docComments.map(comment => {
307
+ const clonedComment = cloneCommentWithMarkers(comment);
308
+ mutatedCode = makeCommentOwnLine(mutatedCode, clonedComment);
309
+ return clonedComment;
310
+ });
311
+ setCommentsOnNode(translatedDefaultExport, [
312
+ ...getCommentsForNode(translatedDefaultExport),
313
+ ...clonedComments,
314
+ ]);
315
+
316
+ if (placement === 'export') {
317
+ const translatedSource = translatedStatements.get(source.statement);
318
+ if (translatedSource != null) {
319
+ setCommentsOnNode(
320
+ translatedSource,
321
+ getCommentsForNode(translatedSource).filter(
322
+ comment => !docComments.includes(comment),
323
+ ),
324
+ );
325
+ }
326
+ }
327
+ return mutatedCode;
328
+ }
329
+
330
+ return code;
331
+ }
332
+
106
333
  function convertArray<TIn, TOut>(
107
334
  items: ReadonlyArray<TIn>,
108
335
  convert: TIn => TranslatedResultOrNull<TOut>,
@@ -246,10 +473,18 @@ export default function flowToFlowDef(
246
473
  context,
247
474
  );
248
475
  transferProgramStatementProperties(optimizedStatement, stmt);
476
+ storeTranslatedStatement(optimizedStatement, stmt);
249
477
  translatedBody.push(optimizedStatement);
250
478
  }
251
479
  }
252
480
 
481
+ const outputCode = applyDefaultExportDocPlacement(
482
+ ast.body,
483
+ translatedStatements,
484
+ opts.defaultExportDocPlacement ?? 'declaration',
485
+ code,
486
+ );
487
+
253
488
  return [
254
489
  t.Program({
255
490
  body: translatedBody,
@@ -259,7 +494,7 @@ export default function flowToFlowDef(
259
494
  tokens: ast.tokens,
260
495
  docblock: ast.docblock,
261
496
  }),
262
- code,
497
+ outputCode,
263
498
  ];
264
499
  }
265
500
 
@@ -1193,6 +1428,13 @@ function convertSuperClass(
1193
1428
  : superClass.typeAnnotation;
1194
1429
 
1195
1430
  if (typeAnnotation.type === 'GenericTypeAnnotation') {
1431
+ if (typeAnnotation.id.type === 'ImportType') {
1432
+ throw translationError(
1433
+ superClass,
1434
+ 'SuperClass: Import type not supported',
1435
+ context,
1436
+ );
1437
+ }
1196
1438
  return convertSuperClassHelper(
1197
1439
  asDetachedNode(typeAnnotation.id),
1198
1440
  typeAnnotation,
package/dist/index.js CHANGED
@@ -24,21 +24,22 @@ async function translateFlowToFlowDef(code, prettierOptions = {}, opts) {
24
24
  scopeManager
25
25
  } = await (0, _flowTransform.parse)(code);
26
26
  const [flowDefAst, mutatedCode] = (0, _flowToFlowDef.default)(ast, code, scopeManager, {
27
- recoverFromErrors: true,
28
- mungeUnderscores: opts == null ? void 0 : opts.mungeUnderscores
27
+ ...opts,
28
+ recoverFromErrors: true
29
29
  });
30
30
  return (0, _flowTransform.print)(flowDefAst, mutatedCode, prettierOptions);
31
31
  }
32
- async function translateFlowToTSDef(code, prettierOptions = {}) {
33
- const flowDefCode = await translateFlowToFlowDef(code, prettierOptions);
34
- return translateFlowDefToTSDef(flowDefCode, prettierOptions);
32
+ async function translateFlowToTSDef(code, prettierOptions = {}, opts) {
33
+ const flowDefCode = await translateFlowToFlowDef(code, prettierOptions, opts);
34
+ return translateFlowDefToTSDef(flowDefCode, prettierOptions, opts);
35
35
  }
36
- async function translateFlowDefToTSDef(code, prettierOptions = {}) {
36
+ async function translateFlowDefToTSDef(code, prettierOptions = {}, opts) {
37
37
  const {
38
38
  ast,
39
39
  scopeManager
40
40
  } = await (0, _flowTransform.parse)(code);
41
41
  const [tsAST, mutatedCode] = (0, _flowDefToTSDef.flowDefToTSDef)(code, ast, scopeManager, {
42
+ ...opts,
42
43
  recoverFromErrors: true
43
44
  });
44
45
  return (0, _flowTransform.print)(tsAST, mutatedCode, {
@@ -11,6 +11,10 @@
11
11
  'use strict';
12
12
 
13
13
  import type {MapperOptions} from './flowImportTo';
14
+ import type {
15
+ DefaultExportDocPlacement,
16
+ TranslationOptions,
17
+ } from './utils/TranslationUtils';
14
18
 
15
19
  import {parse, print} from 'flow-transform';
16
20
  import {parse as parseTS} from '@typescript-eslint/parser';
@@ -21,16 +25,21 @@ import {flowToJS} from './flowToJS';
21
25
  import {flowImportTo} from './flowImportTo';
22
26
  import {TSDefToFlowDef} from './TSDefToFlowDef';
23
27
 
28
+ // `recoverFromErrors` is deliberately not exposed: the entry points always recover.
29
+ export type TranslateOptions = Omit<TranslationOptions, 'recoverFromErrors'>;
30
+
31
+ export type {DefaultExportDocPlacement};
32
+
24
33
  export async function translateFlowToFlowDef(
25
34
  code: string,
26
35
  prettierOptions: {...} = {},
27
- opts?: {mungeUnderscores?: boolean},
36
+ opts?: TranslateOptions,
28
37
  ): Promise<string> {
29
38
  const {ast, scopeManager} = await parse(code);
30
39
 
31
40
  const [flowDefAst, mutatedCode] = flowToFlowDef(ast, code, scopeManager, {
41
+ ...opts,
32
42
  recoverFromErrors: true,
33
- mungeUnderscores: opts?.mungeUnderscores,
34
43
  });
35
44
 
36
45
  return print(flowDefAst, mutatedCode, prettierOptions);
@@ -39,18 +48,21 @@ export async function translateFlowToFlowDef(
39
48
  export async function translateFlowToTSDef(
40
49
  code: string,
41
50
  prettierOptions: {...} = {},
51
+ opts?: TranslateOptions,
42
52
  ): Promise<string> {
43
- const flowDefCode = await translateFlowToFlowDef(code, prettierOptions);
53
+ const flowDefCode = await translateFlowToFlowDef(code, prettierOptions, opts);
44
54
 
45
- return translateFlowDefToTSDef(flowDefCode, prettierOptions);
55
+ return translateFlowDefToTSDef(flowDefCode, prettierOptions, opts);
46
56
  }
47
57
 
48
58
  export async function translateFlowDefToTSDef(
49
59
  code: string,
50
60
  prettierOptions: {...} = {},
61
+ opts?: TranslateOptions,
51
62
  ): Promise<string> {
52
63
  const {ast, scopeManager} = await parse(code);
53
64
  const [tsAST, mutatedCode] = flowDefToTSDef(code, ast, scopeManager, {
65
+ ...opts,
54
66
  recoverFromErrors: true,
55
67
  });
56
68
 
@@ -264,11 +264,15 @@ const getTransforms = (originalCode, opts) => {
264
264
  value: node.source.value,
265
265
  raw: node.source.raw
266
266
  });
267
- const specifiers = node.specifiers.map(specifier => constructFlowNode({
268
- type: 'ExportSpecifier',
269
- local: Transform.Identifier(specifier.local),
270
- exported: Transform.Identifier(specifier.exported)
271
- }));
267
+ const specifiers = node.specifiers.map(specifier => {
268
+ var _specifier$exportKind;
269
+ return constructFlowNode({
270
+ type: 'ExportSpecifier',
271
+ local: Transform.Identifier(specifier.local),
272
+ exported: Transform.Identifier(specifier.exported),
273
+ exportKind: (_specifier$exportKind = specifier.exportKind) != null ? _specifier$exportKind : 'value'
274
+ });
275
+ });
272
276
  return constructFlowNode({
273
277
  type: 'DeclareExportDeclaration',
274
278
  declaration: null,
@@ -318,7 +322,8 @@ const getTransforms = (originalCode, opts) => {
318
322
  specifiers: [constructFlowNode({
319
323
  type: 'ExportSpecifier',
320
324
  local: decl.id,
321
- exported: decl.id
325
+ exported: decl.id,
326
+ exportKind: 'value'
322
327
  })]
323
328
  })];
324
329
  }
@@ -814,6 +819,9 @@ const getTransforms = (originalCode, opts) => {
814
819
  const namesRev = [];
815
820
  while (qualifier.type !== 'Identifier') {
816
821
  namesRev.push(qualifier.id.name);
822
+ if (qualifier.qualification.type === 'ImportType') {
823
+ return unsupportedAnnotation(node, 'nested import types in import type qualifiers');
824
+ }
817
825
  qualifier = qualifier.qualification;
818
826
  }
819
827
  namesRev.push(qualifier.name);
@@ -949,10 +957,12 @@ const getTransforms = (originalCode, opts) => {
949
957
  keyTparam,
950
958
  propType: Transform.TSTypeAnnotationOpt(node.typeAnnotation),
951
959
  sourceType,
952
- variance: node.readonly === '+' || Boolean(node.readonly) ? constructFlowNode({
960
+ nameType: node.nameType == null ? null : Transform.TSTypeAnnotation(node.nameType),
961
+ variance: node.readonly != null && node.readonly !== false ? constructFlowNode({
953
962
  type: 'Variance',
954
963
  kind: 'plus'
955
964
  }) : null,
965
+ varianceOp: node.readonly === '+' ? '+' : node.readonly === '-' ? '-' : null,
956
966
  optional: node.optional === '+' ? 'PlusOptional' : node.optional === '-' ? 'MinusOptional' : Boolean(node.optional) ? 'Optional' : null
957
967
  });
958
968
  return constructFlowNode({