Skip to content

Commit c0a46c6

Browse files
Pranav-yadavfacebook-github-bot
authored andcommitted
Merge defaultExports.forEach(statement => ... (Flow, TS) to findNativeComponentType fn in parser-commons.js (#36466)
Summary: >[Codegen 95] Extract the `defaultExports.forEach(statement =>` (Flow, TS) function in `parser-commons`, so that it accept a Parser parameter to unify the behaviors between flow and typescript. The Parser object needs to be enriched with all the methods to extract the required information from the Node, if they are not there yet. ### Changes - merged TS & Flow parsers' logic for `defaultExports.forEach(statement =>` of `/components/index.js:findComponentConfig()` into; - `findNativeComponentType` fn to `parsers-commons.js` - add `getTypeArgumentParamsFromDeclaration` & `getNativeComponentType` fn's - add **_tests_** for getTypeArgumentParamsFromDeclaration & `getNativeComponentType` fn's ## Changelog [INTERNAL] [CHANGED] - Merge `defaultExports.forEach(statement => ...` (Flow, TS) to `findNativeComponentType` fn in `parser-commons.js` Pull Request resolved: #36466 Test Plan: - `yarn lint && yarn run flow && yarn jest react-native` ⇒ � Reviewed By: rshest Differential Revision: D44088862 Pulled By: cipolleschi fbshipit-source-id: 91bf0edcd53b2e054160af34d7c128355c178b26
1 parent 94f505b commit c0a46c6

File tree

8 files changed

+307
-64
lines changed

8 files changed

+307
-64
lines changed

packages/react-native-codegen/src/parsers/__tests__/parsers-test.js

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,97 @@ describe('FlowParser', () => {
165165
).toEqual(expected);
166166
});
167167
});
168+
169+
describe('getTypeArgumentParamsFromDeclaration', () => {
170+
it('returns type arguments params from declaration', () => {
171+
const declaration = {
172+
type: 'TypeAlias',
173+
typeArguments: {
174+
type: 'TypeParameterDeclaration',
175+
params: [
176+
{
177+
type: 'TypeParameter',
178+
name: 'T',
179+
},
180+
],
181+
},
182+
};
183+
184+
const expected = [
185+
{
186+
type: 'TypeParameter',
187+
name: 'T',
188+
},
189+
];
190+
191+
expect(parser.getTypeArgumentParamsFromDeclaration(declaration)).toEqual(
192+
expected,
193+
);
194+
});
195+
196+
it('returns undefined if declaration type argument params is Invalid', () => {
197+
const declaration = {
198+
type: 'TypeAlias',
199+
typeArguments: {
200+
type: 'TypeParameterDeclaration',
201+
},
202+
};
203+
204+
expect(parser.getTypeArgumentParamsFromDeclaration(declaration)).toEqual(
205+
undefined,
206+
);
207+
});
208+
});
209+
210+
describe('getNativeComponentType', () => {
211+
it('returns native component type when typeArgumentParams & funcArgumentParams are valid', () => {
212+
const typeArgumentParams = [
213+
{
214+
type: 'TypeParameter',
215+
name: 'T',
216+
id: {
217+
name: 'T',
218+
},
219+
},
220+
];
221+
222+
const funcArgumentParams = [
223+
{
224+
type: 'StringLiteral',
225+
value: 'componentName',
226+
},
227+
];
228+
229+
const expected = {
230+
propsTypeName: 'T' /* typeArgumentParams[0].id.name */,
231+
componentName: 'componentName' /* funcArgumentParams[0].value */,
232+
};
233+
234+
expect(
235+
parser.getNativeComponentType(typeArgumentParams, funcArgumentParams),
236+
).toEqual(expected);
237+
});
238+
239+
it('returns undefined when typeArgumentParams & funcArgumentParams are invalid', () => {
240+
const typeArgumentParams = [
241+
{
242+
type: 'TypeParameter',
243+
name: 'T',
244+
id: {},
245+
},
246+
];
247+
const funcArgumentParams = [{}];
248+
249+
const expected = {
250+
propsTypeName: undefined /* typeArgumentParams[0].id.name */,
251+
componentName: undefined /* funcArgumentParams[0].value */,
252+
};
253+
254+
expect(
255+
parser.getNativeComponentType(typeArgumentParams, funcArgumentParams),
256+
).toEqual(expected);
257+
});
258+
});
168259
});
169260

170261
describe('TypeScriptParser', () => {
@@ -326,4 +417,92 @@ describe('TypeScriptParser', () => {
326417
).toEqual(expected);
327418
});
328419
});
420+
421+
describe('getTypeArgumentParamsFromDeclaration', () => {
422+
it('returns type argument params from declaration', () => {
423+
const declaration = {
424+
type: 'TypeAlias',
425+
typeParameters: {
426+
type: 'TypeParameterDeclaration',
427+
params: [
428+
{
429+
type: 'TypeParameter',
430+
name: 'T',
431+
},
432+
],
433+
},
434+
};
435+
436+
const expected = [
437+
{
438+
type: 'TypeParameter',
439+
name: 'T',
440+
},
441+
];
442+
443+
expect(parser.getTypeArgumentParamsFromDeclaration(declaration)).toEqual(
444+
expected,
445+
);
446+
});
447+
448+
it('returns undefined if declaration type arguments params is Invalid', () => {
449+
const declaration = {
450+
type: 'TypeAlias',
451+
typeParameters: {},
452+
};
453+
454+
expect(parser.getTypeArgumentParamsFromDeclaration(declaration)).toEqual(
455+
undefined,
456+
);
457+
});
458+
});
459+
460+
describe('getNativeComponentType', () => {
461+
it('returns native component type when typeArgumentParams & funcArgumentParams are valid', () => {
462+
const typeArgumentParams = [
463+
{
464+
typeName: {
465+
type: 'Identifier',
466+
name: 'T',
467+
},
468+
},
469+
];
470+
471+
const funcArgumentParams = [
472+
{
473+
type: 'ObjectTypeAnnotation',
474+
value: 'StringTypeAnnotation',
475+
},
476+
];
477+
478+
const expected = {
479+
propsTypeName: 'T' /* typeArgumentParams[0].typeName.name */,
480+
componentName: 'StringTypeAnnotation' /* funcArgumentParams[0].value */,
481+
};
482+
483+
expect(
484+
parser.getNativeComponentType(typeArgumentParams, funcArgumentParams),
485+
).toEqual(expected);
486+
});
487+
488+
it('returns undefined when typeArgumentParams & funcArgumentParams are invalid', () => {
489+
const typeArgumentParams = [
490+
{
491+
typeName: {
492+
type: 'Invalid',
493+
},
494+
},
495+
];
496+
const funcArgumentParams = [{}];
497+
498+
const expected = {
499+
propsTypeName: undefined /* typeArgumentParams[0].typeName.name */,
500+
componentName: undefined /* funcArgumentParams[0].value */,
501+
};
502+
503+
expect(
504+
parser.getNativeComponentType(typeArgumentParams, funcArgumentParams),
505+
).toEqual(expected);
506+
});
507+
});
329508
});

packages/react-native-codegen/src/parsers/flow/components/index.js

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,22 @@ const {getExtendsProps, removeKnownExtends} = require('./extends');
2020
const {getCommandOptions, getOptions} = require('./options');
2121
const {getProps} = require('./props');
2222
const {getProperties} = require('./componentsUtils.js');
23-
const {createComponentConfig} = require('../../parsers-commons');
2423
const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils');
24+
const {
25+
createComponentConfig,
26+
findNativeComponentType,
27+
} = require('../../parsers-commons');
2528

26-
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
27-
* LTI update could not be added via codemod */
28-
function findComponentConfig(ast) {
29-
const foundConfigs = [];
29+
// $FlowFixMe[signature-verification-failure] there's no flowtype for AST
30+
function findComponentConfig(ast: $FlowFixMe, parser: Parser) {
31+
const foundConfigs: Array<{[string]: string}> = [];
3032

3133
const defaultExports = ast.body.filter(
3234
node => node.type === 'ExportDefaultDeclaration',
3335
);
3436

3537
defaultExports.forEach(statement => {
36-
let declaration = statement.declaration;
37-
38-
// codegenNativeComponent can be nested inside a cast
39-
// expression so we need to go one level deeper
40-
if (declaration.type === 'TypeCastExpression') {
41-
declaration = declaration.expression;
42-
}
43-
44-
try {
45-
if (declaration.callee.name === 'codegenNativeComponent') {
46-
const typeArgumentParams = declaration.typeArguments.params;
47-
const funcArgumentParams = declaration.arguments;
48-
49-
const nativeComponentType: {[string]: string} = {
50-
propsTypeName: typeArgumentParams[0].id.name,
51-
componentName: funcArgumentParams[0].value,
52-
};
53-
if (funcArgumentParams.length > 1) {
54-
nativeComponentType.optionsExpression = funcArgumentParams[1];
55-
}
56-
foundConfigs.push(nativeComponentType);
57-
}
58-
} catch (e) {
59-
// ignore
60-
}
38+
findNativeComponentType(statement, foundConfigs, parser);
6139
});
6240

6341
if (foundConfigs.length === 0) {
@@ -180,7 +158,7 @@ function buildComponentSchema(
180158
commandTypeName,
181159
commandOptionsExpression,
182160
optionsExpression,
183-
} = findComponentConfig(ast);
161+
} = findComponentConfig(ast, parser);
184162

185163
const types = parser.getTypes(ast);
186164

packages/react-native-codegen/src/parsers/flow/parser.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,24 @@ class FlowParser implements Parser {
295295
functionTypeAnnotation(propertyValueType: string): boolean {
296296
return propertyValueType === 'FunctionTypeAnnotation';
297297
}
298+
299+
getTypeArgumentParamsFromDeclaration(declaration: $FlowFixMe): $FlowFixMe {
300+
return declaration.typeArguments.params;
301+
}
302+
303+
/**
304+
* This FlowFixMe is supposed to refer to typeArgumentParams and
305+
* funcArgumentParams of generated AST.
306+
*/
307+
getNativeComponentType(
308+
typeArgumentParams: $FlowFixMe,
309+
funcArgumentParams: $FlowFixMe,
310+
): {[string]: string} {
311+
return {
312+
propsTypeName: typeArgumentParams[0].id.name,
313+
componentName: funcArgumentParams[0].value,
314+
};
315+
}
298316
}
299317

300318
module.exports = {

packages/react-native-codegen/src/parsers/parser.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,22 @@ export interface Parser {
211211
* @returns: a boolean specifying if the property is a function type annotation.
212212
*/
213213
functionTypeAnnotation(propertyValueType: string): boolean;
214+
215+
/**
216+
* Given a declaration, it returns the typeArgumentParams of the declaration.
217+
* @parameter declaration: the declaration.
218+
* @returns: the typeArgumentParams of the declaration.
219+
*/
220+
getTypeArgumentParamsFromDeclaration(declaration: $FlowFixMe): $FlowFixMe;
221+
222+
/**
223+
* Given a typeArgumentParams and funcArgumentParams it returns a native component type.
224+
* @parameter typeArgumentParams: the typeArgumentParams.
225+
* @parameter funcArgumentParams: the funcArgumentParams.
226+
* @returns: a native component type.
227+
*/
228+
getNativeComponentType(
229+
typeArgumentParams: $FlowFixMe,
230+
funcArgumentParams: $FlowFixMe,
231+
): {[string]: string};
214232
}

packages/react-native-codegen/src/parsers/parserMock.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,18 @@ export class MockedParser implements Parser {
213213
functionTypeAnnotation(propertyValueType: string): boolean {
214214
return propertyValueType === 'FunctionTypeAnnotation';
215215
}
216+
217+
getTypeArgumentParamsFromDeclaration(declaration: $FlowFixMe): $FlowFixMe {
218+
return declaration.typeArguments.params;
219+
}
220+
221+
getNativeComponentType(
222+
typeArgumentParams: $FlowFixMe,
223+
funcArgumentParams: $FlowFixMe,
224+
): {[string]: string} {
225+
return {
226+
propsTypeName: typeArgumentParams[0].id.name,
227+
componentName: funcArgumentParams[0].value,
228+
};
229+
}
216230
}

packages/react-native-codegen/src/parsers/parsers-commons.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,48 @@ const buildModuleSchema = (
657657
);
658658
};
659659

660+
/**
661+
* This function is used to find the type of a native component
662+
* provided the default exports statement from generated AST.
663+
* @param statement The statement to be parsed.
664+
* @param foundConfigs The 'mutable' array of configs that have been found.
665+
* @param parser The language parser to be used.
666+
* @returns void
667+
*/
668+
function findNativeComponentType(
669+
statement: $FlowFixMe,
670+
foundConfigs: Array<{[string]: string}>,
671+
parser: Parser,
672+
): void {
673+
let declaration = statement.declaration;
674+
675+
// codegenNativeComponent can be nested inside a cast
676+
// expression so we need to go one level deeper
677+
if (
678+
declaration.type === 'TSAsExpression' ||
679+
declaration.type === 'TypeCastExpression'
680+
) {
681+
declaration = declaration.expression;
682+
}
683+
684+
try {
685+
if (declaration.callee.name === 'codegenNativeComponent') {
686+
const typeArgumentParams =
687+
parser.getTypeArgumentParamsFromDeclaration(declaration);
688+
const funcArgumentParams = declaration.arguments;
689+
690+
const nativeComponentType: {[string]: string} =
691+
parser.getNativeComponentType(typeArgumentParams, funcArgumentParams);
692+
if (funcArgumentParams.length > 1) {
693+
nativeComponentType.optionsExpression = funcArgumentParams[1];
694+
}
695+
foundConfigs.push(nativeComponentType);
696+
}
697+
} catch (e) {
698+
// ignore
699+
}
700+
}
701+
660702
module.exports = {
661703
wrapModuleSchema,
662704
unwrapNullable,
@@ -671,4 +713,5 @@ module.exports = {
671713
createComponentConfig,
672714
parseModuleName,
673715
buildModuleSchema,
716+
findNativeComponentType,
674717
};

0 commit comments

Comments
 (0)