flow-api-translator 0.330.0 → 0.332.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') {
package/dist/src/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, {
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.ensureTypeIncludesUndefined = ensureTypeIncludesUndefined;
7
7
  exports.extractPropertyKeyLiterals = extractPropertyKeyLiterals;
8
+ exports.getDefaultExportBindingName = getDefaultExportBindingName;
8
9
  var TSESTree = _interopRequireWildcard(require("./ts-estree-ast-types"));
9
10
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
11
  const DUMMY_LOC = {
@@ -17,6 +18,25 @@ const DUMMY_LOC = {
17
18
  column: 0
18
19
  }
19
20
  };
21
+ function inferDefaultExportName(typeAnnotation) {
22
+ switch (typeAnnotation.type) {
23
+ case 'GenericTypeAnnotation':
24
+ return typeAnnotation.id.type === 'Identifier' && typeAnnotation.id.name !== '$FlowFixMe' ? typeAnnotation.id.name : null;
25
+ case 'NullableTypeAnnotation':
26
+ return inferDefaultExportName(typeAnnotation.typeAnnotation);
27
+ case 'TypeofTypeAnnotation':
28
+ return typeAnnotation.argument.type === 'Identifier' && typeAnnotation.argument.name !== '$FlowFixMe' ? typeAnnotation.argument.name : null;
29
+ default:
30
+ return null;
31
+ }
32
+ }
33
+ function getDefaultExportBindingName(typeAnnotation, useSemanticName) {
34
+ if (!useSemanticName) {
35
+ return '$$EXPORT_DEFAULT_DECLARATION$$';
36
+ }
37
+ const inferredName = inferDefaultExportName(typeAnnotation);
38
+ return inferredName == null ? '$$default' : `$$${inferredName}`;
39
+ }
20
40
  function extractPropertyKeyLiterals(members) {
21
41
  if (members.length === 0) {
22
42
  return null;
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.ensureTypeIncludesUndefined = ensureTypeIncludesUndefined;
7
7
  exports.extractPropertyKeyLiterals = extractPropertyKeyLiterals;
8
+ exports.getDefaultExportBindingName = getDefaultExportBindingName;
8
9
  var TSESTree = _interopRequireWildcard(require("./ts-estree-ast-types"));
9
10
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
11
  const DUMMY_LOC = {
@@ -17,6 +18,25 @@ const DUMMY_LOC = {
17
18
  column: 0
18
19
  }
19
20
  };
21
+ function inferDefaultExportName(typeAnnotation) {
22
+ switch (typeAnnotation.type) {
23
+ case 'GenericTypeAnnotation':
24
+ return typeAnnotation.id.type === 'Identifier' && typeAnnotation.id.name !== '$FlowFixMe' ? typeAnnotation.id.name : null;
25
+ case 'NullableTypeAnnotation':
26
+ return inferDefaultExportName(typeAnnotation.typeAnnotation);
27
+ case 'TypeofTypeAnnotation':
28
+ return typeAnnotation.argument.type === 'Identifier' && typeAnnotation.argument.name !== '$FlowFixMe' ? typeAnnotation.argument.name : null;
29
+ default:
30
+ return null;
31
+ }
32
+ }
33
+ function getDefaultExportBindingName(typeAnnotation, useSemanticName) {
34
+ if (!useSemanticName) {
35
+ return '$$EXPORT_DEFAULT_DECLARATION$$';
36
+ }
37
+ const inferredName = inferDefaultExportName(typeAnnotation);
38
+ return inferredName == null ? '$$default' : `$$${inferredName}`;
39
+ }
20
40
  function extractPropertyKeyLiterals(members) {
21
41
  if (members.length === 0) {
22
42
  return null;
@@ -10,7 +10,7 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- import type {SourceLocation} from 'flow-estree';
13
+ import type {SourceLocation, TypeAnnotationType} from 'flow-estree';
14
14
 
15
15
  import * as TSESTree from './ts-estree-ast-types';
16
16
 
@@ -19,6 +19,51 @@ const DUMMY_LOC: SourceLocation = {
19
19
  end: {line: 1, column: 0},
20
20
  };
21
21
 
22
+ /**
23
+ * Returns the identifier referenced by a default-exported Flow type, unwrapping
24
+ * nullable types, or `null` when the type does not reference exactly one
25
+ * identifier.
26
+ *
27
+ * `$FlowFixMe` is rejected because it translates to `any`, so naming the
28
+ * binding after it would describe the recovery placeholder rather than the
29
+ * exported type.
30
+ */
31
+ function inferDefaultExportName(
32
+ typeAnnotation: TypeAnnotationType,
33
+ ): string | null {
34
+ switch (typeAnnotation.type) {
35
+ case 'GenericTypeAnnotation':
36
+ return typeAnnotation.id.type === 'Identifier' &&
37
+ typeAnnotation.id.name !== '$FlowFixMe'
38
+ ? typeAnnotation.id.name
39
+ : null;
40
+ case 'NullableTypeAnnotation':
41
+ return inferDefaultExportName(typeAnnotation.typeAnnotation);
42
+ case 'TypeofTypeAnnotation':
43
+ return typeAnnotation.argument.type === 'Identifier' &&
44
+ typeAnnotation.argument.name !== '$FlowFixMe'
45
+ ? typeAnnotation.argument.name
46
+ : null;
47
+ default:
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Returns the binding name to use when TypeScript requires a synthetic value
54
+ * for a Flow default export.
55
+ */
56
+ export function getDefaultExportBindingName(
57
+ typeAnnotation: TypeAnnotationType,
58
+ useSemanticName: boolean,
59
+ ): string {
60
+ if (!useSemanticName) {
61
+ return '$$EXPORT_DEFAULT_DECLARATION$$';
62
+ }
63
+ const inferredName = inferDefaultExportName(typeAnnotation);
64
+ return inferredName == null ? '$$default' : `$$${inferredName}`;
65
+ }
66
+
22
67
  /**
23
68
  * Extract statically known property key names from a list of TS type element
24
69
  * nodes and return them as `TSLiteralType` (string literal) AST nodes.
@@ -14,9 +14,25 @@ import type {Identifier, JSXIdentifier} from 'flow-estree';
14
14
  import type {ScopeManager, Variable} from 'flow-eslint';
15
15
 
16
16
  export type Dep = string;
17
+
18
+ /**
19
+ * Where the documentation for a default-exported value should end up.
20
+ *
21
+ * TypeScript resolves a default re-export to the synthetic `export default`
22
+ * symbol rather than the declaration it aliases, so consumers that care about
23
+ * doc comments surviving a re-export need `'export'` or `'both'`.
24
+ */
25
+ export type DefaultExportDocPlacement = 'both' | 'declaration' | 'export';
26
+
17
27
  export type TranslationOptions = {
28
+ defaultExportDocPlacement?: DefaultExportDocPlacement,
18
29
  recoverFromErrors: boolean,
19
30
  mungeUnderscores?: boolean,
31
+ /**
32
+ * Name synthetic default exports after their referenced identifier, falling
33
+ * back to `$$default` for anonymous types. Defaults to false.
34
+ */
35
+ useSemanticDefaultExportNames?: boolean,
20
36
  };
21
37
  export type TranslationContext = {
22
38
  scopeManager: ScopeManager,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-api-translator",
3
- "version": "0.330.0",
3
+ "version": "0.332.0",
4
4
  "description": "Toolkit for creating Flow and TypeScript compatible libraries from Flow source code.",
5
5
  "homepage": "https://flow.org",
6
6
  "license": "MIT",
@@ -14,10 +14,10 @@
14
14
  "@typescript-eslint/parser": "8.38.0",
15
15
  "@typescript-eslint/visitor-keys": "8.38.0",
16
16
  "flow-enums-runtime": "^0.0.6",
17
- "flow-eslint": "0.330.0",
18
- "flow-estree": "0.330.0",
19
- "flow-parser": "0.330.0",
20
- "flow-transform": "0.330.0",
17
+ "flow-eslint": "0.332.0",
18
+ "flow-estree": "0.332.0",
19
+ "flow-parser": "0.332.0",
20
+ "flow-transform": "0.332.0",
21
21
  "typescript": "5.3.2"
22
22
  },
23
23
  "peerDependencies": {