Skip to content

Commit 241b1a6

Browse files
coadoreact-native-bot
authored andcommitted
Add transform that moves comments for default exported variable declarations (#51135)
Summary: Pull Request resolved: #51135 In generated types default exported variables are re-declared which shadows attached tags and doc blocks. This transform moves necessary comments on top of re-declarations to keep them accessible. Example output for SafeAreaView: ```ts import type { ViewProps } from "../View/ViewPropTypes"; import View from "../View/View"; import * as React from "react"; declare const exported: (props: Omit<ViewProps, keyof { ref?: React.Ref<React.ComponentRef<typeof View>>; }> & { ref?: React.Ref<React.ComponentRef<typeof View>>; }) => React.ReactNode; /** * Renders nested content and automatically applies paddings reflect the portion * of the view that is not covered by navigation bars, tab bars, toolbars, and * other ancestor views. * * Moreover, and most importantly, Safe Area's paddings reflect physical * limitation of the screen, such as rounded corners or camera notches (aka * sensor housing area on iPhone X). */ declare const SafeAreaView_DEFAULT: typeof exported; declare type SafeAreaView_DEFAULT = typeof SafeAreaView_DEFAULT; export default SafeAreaView_DEFAULT; ``` Changelog: [Internal] Reviewed By: huntie Differential Revision: D74249424 fbshipit-source-id: 5cdd1c746e7fed99e3d3427d6ebf4c0e7ba3f3fd
1 parent e8b14c7 commit 241b1a6

3 files changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
* @flow strict-local
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
const reattachDocComments = require('../reattachDocComments.js');
13+
const {parse, print} = require('hermes-transform');
14+
15+
const prettierOptions = {parser: 'babel'};
16+
17+
async function translate(code: string): Promise<string> {
18+
const parsed = await parse(code);
19+
const result = await reattachDocComments(parsed);
20+
return print(result.ast, result.mutatedCode, prettierOptions);
21+
}
22+
23+
describe('reattachDocComments', () => {
24+
test('should move component doc block', async () => {
25+
const code = `
26+
import Bar from './Bar';
27+
28+
/**
29+
* Foo documentation
30+
*/
31+
let Foo: component(
32+
ref?: React.RefSetter<
33+
React.ElementRef<FooType>,
34+
>,
35+
...props: FooProps
36+
);
37+
38+
export default Foo;
39+
`;
40+
41+
const result = await translate(code);
42+
expect(result).toMatchInlineSnapshot(`
43+
"import Bar from \\"./Bar\\";
44+
45+
let Foo: component(
46+
ref?: React.RefSetter<React.ElementRef<FooType>>,
47+
...props: FooProps
48+
);
49+
50+
/**
51+
* Foo documentation
52+
*/
53+
export default Foo;
54+
"
55+
`);
56+
});
57+
test('should move variable doc block', async () => {
58+
const code = `
59+
const bar = 'bar';
60+
/**
61+
* Foo documentation
62+
*/
63+
const Foo: component(
64+
ref?: React.RefSetter<
65+
React.ElementRef<FooType>,
66+
>,
67+
...props: FooProps
68+
) = () => {};
69+
70+
export default Foo;
71+
`;
72+
const result = await translate(code);
73+
expect(result).toMatchInlineSnapshot(`
74+
"const bar = \\"bar\\";
75+
const Foo: component(
76+
ref?: React.RefSetter<React.ElementRef<FooType>>,
77+
...props: FooProps
78+
) = () => {};
79+
80+
/**
81+
* Foo documentation
82+
*/
83+
export default Foo;
84+
"
85+
`);
86+
});
87+
});
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
* @flow strict-local
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
import type {ExportDefaultDeclaration, Program} from 'hermes-estree/dist';
13+
import type {TransformVisitor} from 'hermes-transform';
14+
import type {ParseResult} from 'hermes-transform/dist/transform/parse';
15+
import type {TransformASTResult} from 'hermes-transform/dist/transform/transformAST';
16+
17+
const {transformAST} = require('hermes-transform/dist/transform/transformAST');
18+
19+
const visitors: TransformVisitor = context => ({
20+
Program(node): void {
21+
const getExportDefaultDeclaration = (
22+
programNode: Program,
23+
): [ExportDefaultDeclaration, string] | null => {
24+
for (const bodyNode of programNode.body) {
25+
if (bodyNode.type === 'ExportDefaultDeclaration') {
26+
if (bodyNode.declaration.type === 'Identifier') {
27+
return [bodyNode, bodyNode.declaration.name];
28+
}
29+
}
30+
}
31+
32+
return null;
33+
};
34+
35+
const exportDefaultDeclResult = getExportDefaultDeclaration(node);
36+
if (exportDefaultDeclResult == null) {
37+
return;
38+
}
39+
40+
const [exportDefaultDecl, exportDefaultDeclName] = exportDefaultDeclResult;
41+
for (const bodyNode of node.body) {
42+
if (bodyNode.type === 'VariableDeclaration') {
43+
for (const decl of bodyNode.declarations) {
44+
if (
45+
decl.id.type === 'Identifier' &&
46+
decl.id.name === exportDefaultDeclName
47+
) {
48+
const comments = context.getComments(bodyNode);
49+
if (comments != null) {
50+
context.addLeadingComments(exportDefaultDecl, comments);
51+
context.removeComments(comments);
52+
}
53+
}
54+
}
55+
}
56+
}
57+
},
58+
});
59+
60+
async function reattachDocComments(
61+
source: ParseResult,
62+
): Promise<TransformASTResult> {
63+
return transformAST(source, visitors);
64+
}
65+
66+
module.exports = reattachDocComments;

scripts/build-types/translateSourceFile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const preTransforms: Array<PreTransformFn> = [
2727
require('./transforms/replaceEmptyWithNever'),
2828
require('./transforms/replaceStringishWithString'),
2929
require('./transforms/replaceNullablePropertiesWithUndefined'),
30+
require('./transforms/reattachDocComments'),
3031
];
3132
const postTransforms: Array<PluginObj<mixed>> = [];
3233
const prettierOptions = {parser: 'babel'};

0 commit comments

Comments
 (0)