flow-api-translator 0.28.1 → 0.29.1

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.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.flowToJS = flowToJS;
16
+
17
+ var _hermesParser = require("hermes-parser");
18
+
19
+ var _DocblockUtils = require("./utils/DocblockUtils");
20
+
21
+ const {
22
+ nodeWith
23
+ } = _hermesParser.astNodeMutationHelpers;
24
+
25
+ function stripAtFlow(ast, _options) {
26
+ const docblock = ast.docblock;
27
+
28
+ if (docblock == null) {
29
+ return ast;
30
+ }
31
+
32
+ return nodeWith(ast, {
33
+ docblock: (0, _DocblockUtils.removeAtFlowFromDocblock)(docblock)
34
+ });
35
+ }
36
+
37
+ function flowToJS(sourceAST, _code, _scopeManager) {
38
+ return [_hermesParser.Transforms.stripComponentSyntax, _hermesParser.Transforms.stripFlowTypes, stripAtFlow].reduce((ast, transform) => transform(ast, {}), sourceAST);
39
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.translateFlowDefToTSDef = translateFlowDefToTSDef;
16
+ exports.translateFlowImportsTo = translateFlowImportsTo;
17
+ exports.translateFlowToFlowDef = translateFlowToFlowDef;
18
+ exports.translateFlowToJS = translateFlowToJS;
19
+ exports.translateFlowToTSDef = translateFlowToTSDef;
20
+ exports.unstable_translateTSDefToFlowDef = unstable_translateTSDefToFlowDef;
21
+
22
+ var _hermesTransform = require("hermes-transform");
23
+
24
+ var _parser = require("@typescript-eslint/parser");
25
+
26
+ var _visitorKeys = require("@typescript-eslint/visitor-keys");
27
+
28
+ var _flowToFlowDef = _interopRequireDefault(require("./flowToFlowDef"));
29
+
30
+ var _flowDefToTSDef = require("./flowDefToTSDef");
31
+
32
+ var _flowToJS = require("./flowToJS");
33
+
34
+ var _flowImportTo = require("./flowImportTo");
35
+
36
+ var _TSDefToFlowDef = require("./TSDefToFlowDef");
37
+
38
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39
+
40
+ async function translateFlowToFlowDef(code, prettierOptions = {}) {
41
+ const {
42
+ ast,
43
+ scopeManager
44
+ } = await (0, _hermesTransform.parse)(code);
45
+ const [flowDefAst, mutatedCode] = (0, _flowToFlowDef.default)(ast, code, scopeManager, {
46
+ recoverFromErrors: true
47
+ });
48
+ return (0, _hermesTransform.print)(flowDefAst, mutatedCode, prettierOptions);
49
+ }
50
+
51
+ async function translateFlowToTSDef(code, prettierOptions = {}) {
52
+ const flowDefCode = await translateFlowToFlowDef(code, prettierOptions);
53
+ return translateFlowDefToTSDef(flowDefCode, prettierOptions);
54
+ }
55
+
56
+ async function translateFlowDefToTSDef(code, prettierOptions = {}) {
57
+ const {
58
+ ast,
59
+ scopeManager
60
+ } = await (0, _hermesTransform.parse)(code);
61
+ const [tsAST, mutatedCode] = (0, _flowDefToTSDef.flowDefToTSDef)(code, ast, scopeManager, {
62
+ recoverFromErrors: true
63
+ });
64
+ return (0, _hermesTransform.print)( // $FlowExpectedError[incompatible-call] - this is fine as we're providing the visitor keys
65
+ tsAST, mutatedCode, { ...prettierOptions
66
+ }, _visitorKeys.visitorKeys);
67
+ }
68
+
69
+ async function translateFlowToJS(code, prettierOptions = {}) {
70
+ const {
71
+ ast,
72
+ scopeManager
73
+ } = await (0, _hermesTransform.parse)(code);
74
+ const jsAST = (0, _flowToJS.flowToJS)(ast, code, scopeManager);
75
+ return (0, _hermesTransform.print)(jsAST, code, prettierOptions);
76
+ }
77
+ /**
78
+ * This translator is very experimental and unstable.
79
+ *
80
+ * It is not written with productionizing it in mind, but instead used to evaluate how close Flow
81
+ * is to TypeScript.
82
+ *
83
+ * If you are going to use it anyways, you agree that you are calling a potentially broken function
84
+ * without any guarantee.
85
+ *
86
+ * @deprecated
87
+ */
88
+
89
+
90
+ async function unstable_translateTSDefToFlowDef(code, prettierOptions = {}) {
91
+ const ast = (0, _parser.parse)(code, {
92
+ loc: true,
93
+ range: true,
94
+ sourceType: 'module'
95
+ });
96
+
97
+ if (ast == null) {
98
+ throw `Failed to parse ${code} with @typescript-eslint/parser`;
99
+ }
100
+
101
+ const [flowAST, mutatedCode] = (0, _TSDefToFlowDef.TSDefToFlowDef)(code, ast, {
102
+ recoverFromErrors: false
103
+ });
104
+ return (0, _hermesTransform.print)(flowAST, mutatedCode, prettierOptions);
105
+ }
106
+
107
+ async function translateFlowImportsTo(code, prettierOptions = {}, opts) {
108
+ const {
109
+ ast,
110
+ scopeManager
111
+ } = await (0, _hermesTransform.parse)(code);
112
+ const jsAST = (0, _flowImportTo.flowImportTo)(ast, code, scopeManager, opts);
113
+ return (0, _hermesTransform.print)(jsAST, code, prettierOptions);
114
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.removeAtFlowFromDocblock = removeAtFlowFromDocblock;
16
+ const FLOW_DIRECTIVE = /(@flow(\s+(strict(-local)?|weak))?|@noflow)/;
17
+
18
+ function removeAtFlowFromDocblock(docblock) {
19
+ if (!FLOW_DIRECTIVE.test(docblock.comment.value)) {
20
+ return docblock;
21
+ }
22
+
23
+ return {
24
+ // $FlowExpectedError[cannot-spread-interface]
25
+ comment: { ...docblock.comment,
26
+ value: docblock.comment.value.replace(FLOW_DIRECTIVE, '')
27
+ },
28
+ directives: { ...docblock.directives,
29
+ flow: undefined,
30
+ noflow: undefined
31
+ }
32
+ };
33
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.UnexpectedTranslationError = exports.ExpectedTranslationError = void 0;
16
+ exports.buildCodeFrame = buildCodeFrame;
17
+ exports.flowFixMeOrError = flowFixMeOrError;
18
+ exports.translationError = translationError;
19
+ exports.unexpectedTranslationError = unexpectedTranslationError;
20
+
21
+ var _hermesTransform = require("hermes-transform");
22
+
23
+ var _codeFrame = require("@babel/code-frame");
24
+
25
+ function flowFixMeOrError(container, message, context) {
26
+ if (context.recoverFromErrors) {
27
+ return _hermesTransform.t.GenericTypeAnnotation({
28
+ id: _hermesTransform.t.Identifier({
29
+ name: '$FlowFixMe'
30
+ })
31
+ });
32
+ }
33
+
34
+ throw translationError(container, message, context);
35
+ }
36
+
37
+ class TranslationErrorBase extends Error {
38
+ constructor(node, message, context) {
39
+ const framedMessage = buildCodeFrame(node, message, context.code);
40
+ super( // jest error snapshots will use a hard-coded string representation if
41
+ // `instanceof Error` which makes the code frame look awful and hard to verify:
42
+ //
43
+ // [TranslationError: > 12 | code
44
+ // | ^^^^ error]
45
+ //
46
+ // this just adds a newline in jest tests so that it all lines up nicely
47
+ //
48
+ // [TranslationError:
49
+ // > 12 | code
50
+ // | ^^^^ error]
51
+ process.env.JEST_WORKER_ID == null ? framedMessage : `\n${framedMessage}`);
52
+ this.name = 'TranslationError';
53
+ }
54
+
55
+ }
56
+
57
+ class ExpectedTranslationError extends TranslationErrorBase {
58
+ constructor(...args) {
59
+ super(...args);
60
+ this.name = 'ExpectedTranslationError';
61
+ }
62
+
63
+ }
64
+
65
+ exports.ExpectedTranslationError = ExpectedTranslationError;
66
+
67
+ function translationError(node, message, context) {
68
+ return new ExpectedTranslationError(node, message, context);
69
+ }
70
+
71
+ class UnexpectedTranslationError extends TranslationErrorBase {
72
+ constructor(...args) {
73
+ super(...args);
74
+ this.name = 'UnexpectedTranslationError';
75
+ }
76
+
77
+ }
78
+
79
+ exports.UnexpectedTranslationError = UnexpectedTranslationError;
80
+
81
+ function unexpectedTranslationError(node, message, context) {
82
+ return new UnexpectedTranslationError(node, message, context);
83
+ }
84
+
85
+ function buildCodeFrame(node, message, code, highlightCode = process.env.NODE_ENV !== 'test') {
86
+ // babel uses 1-indexed columns
87
+ const locForBabel = {
88
+ start: {
89
+ line: node.loc.start.line,
90
+ column: node.loc.start.column + 1
91
+ },
92
+ end: {
93
+ line: node.loc.end.line,
94
+ column: node.loc.end.column + 1
95
+ }
96
+ };
97
+ return (0, _codeFrame.codeFrameColumns)(code, locForBabel, {
98
+ linesAbove: 0,
99
+ linesBelow: 0,
100
+ highlightCode,
101
+ message: message
102
+ });
103
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.analyzeFunctionReturn = analyzeFunctionReturn;
16
+ exports.analyzeTypeDependencies = analyzeTypeDependencies;
17
+
18
+ var _hermesTransform = require("hermes-transform");
19
+
20
+ var _hermesParser = require("hermes-parser");
21
+
22
+ function analyzeFunctionReturn(func) {
23
+ const returnType = func.returnType;
24
+
25
+ if (returnType != null) {
26
+ return returnType;
27
+ } // We trust Flow has validated this function to only return void
28
+ // $FlowFixMe[incompatible-return]
29
+
30
+
31
+ return _hermesTransform.t.TypeAnnotation({
32
+ typeAnnotation: _hermesTransform.t.VoidTypeAnnotation()
33
+ });
34
+ }
35
+
36
+ function analyzeTypeDependencies(rootNode, context) {
37
+ const deps = [];
38
+
39
+ _hermesParser.SimpleTraverser.traverse(rootNode, {
40
+ enter(node) {
41
+ if (node.type === 'Identifier' || node.type === 'JSXIdentifier') {
42
+ const variable = context.referenceMap.get(node);
43
+
44
+ if (variable != null) {
45
+ deps.push(variable.name);
46
+ }
47
+ }
48
+ },
49
+
50
+ leave() {}
51
+
52
+ });
53
+
54
+ return deps;
55
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.createTranslationContext = createTranslationContext;
16
+
17
+ function createTranslationContext(code, scopeManager, {
18
+ recoverFromErrors
19
+ }) {
20
+ const referenceMap = new Map();
21
+ const variableMap = new Map();
22
+ const moduleScope = scopeManager.globalScope.childScopes[0];
23
+
24
+ if (moduleScope == null || moduleScope.type !== 'module') {
25
+ throw new Error('createTranslationContext: Module scope not found');
26
+ }
27
+
28
+ for (const variable of moduleScope.variables) {
29
+ for (const reference of variable.references) {
30
+ referenceMap.set(reference.identifier, variable);
31
+ variableMap.set(variable.name, variable);
32
+ }
33
+ }
34
+
35
+ return {
36
+ scopeManager,
37
+ referenceMap,
38
+ variableMap,
39
+ recoverFromErrors,
40
+ code
41
+ };
42
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+
11
+ /**
12
+ * The following types have been adapted by hand from
13
+ * https://unpkg.com/browse/@typescript-eslint/types@5.41.0/dist/generated/ast-spec.d.ts
14
+ *
15
+ * Changes:
16
+ * - remove and inline `ValueOf` type
17
+ * - `undefined` -> `void`
18
+ * - remove all `declare` keywords
19
+ * - comment out `bigint` type
20
+ * -> flow doesn't support it yet
21
+ * - remove `range` and `loc` from `NodeOrTokenData`
22
+ * -> during conversion our locations will be all off, so we'll rely on prettier to print later
23
+ * - make all properties readonly and all arrays $ReadOnlyArray
24
+ * -> unlike TS - flow enforces subtype constraints strictly!
25
+ * - add `type` to interfaces that previously relied upon inheriting the `type`
26
+ * -> this is because flow sentinel refinement does not check inherited members
27
+ * - create "Ambiguous" versions for some nodes that have unions (like PropertyDefinition, MemberDefinition)
28
+ * -> makes it easier to construct them from other nodes that have unions
29
+ */
30
+ 'use strict';
@@ -350,7 +350,7 @@ export interface ExportDefaultDeclaration extends BaseNode {
350
350
  */
351
351
  +exportKind: ExportKind;
352
352
  }
353
- type ExportKind = ExportAndImportKind;
353
+ export type ExportKind = ExportAndImportKind;
354
354
  export type ExportNamedDeclaration =
355
355
  | ExportNamedDeclarationWithoutSourceWithMultiple
356
356
  | ExportNamedDeclarationWithoutSourceWithSingle
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-api-translator",
3
- "version": "0.28.1",
3
+ "version": "0.29.1",
4
4
  "description": "Toolkit for creating Flow and TypeScript compatible libraries from Flow source code.",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -13,10 +13,10 @@
13
13
  "@typescript-eslint/parser": "7.2.0",
14
14
  "@typescript-eslint/visitor-keys": "7.2.0",
15
15
  "flow-enums-runtime": "^0.0.6",
16
- "hermes-eslint": "0.28.1",
17
- "hermes-estree": "0.28.1",
18
- "hermes-parser": "0.28.1",
19
- "hermes-transform": "0.28.1",
16
+ "hermes-eslint": "0.29.1",
17
+ "hermes-estree": "0.29.1",
18
+ "hermes-parser": "0.29.1",
19
+ "hermes-transform": "0.29.1",
20
20
  "typescript": "5.3.2"
21
21
  },
22
22
  "peerDependencies": {