Skip to content

Commit 5113323

Browse files
elicwhitefacebook-github-bot
authored andcommitted
Add failure tests for duplicate props with the same name
Summary: There are a couple of cases where props can conflict which would cause undefined behavior. We'll throw to protect against that. Now that we support type spread this is more possible without someone realizing. Reviewed By: JoshuaGross Differential Revision: D16813884 fbshipit-source-id: 1a8fce365ab315198abdff0de6006cfe34e84fb9
1 parent ac6c747 commit 5113323

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

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

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,104 @@ export default (codegenNativeComponent<ModuleProps>(
305305
): NativeComponent<ModuleProps>);
306306
`;
307307

308+
const PROPS_CONFLICT_NAMES = `
309+
/**
310+
* Copyright (c) Facebook, Inc. and its affiliates.
311+
*
312+
* This source code is licensed under the MIT license found in the
313+
* LICENSE file in the root directory of this source tree.
314+
*
315+
* @format
316+
* @flow
317+
*/
318+
319+
'use strict';
320+
321+
import type {ViewProps} from 'ViewPropTypes';
322+
import type {NativeComponent} from 'codegenNativeComponent';
323+
324+
const codegenNativeComponent = require('codegenNativeComponent');
325+
326+
export type ModuleProps = $ReadOnly<{|
327+
...ViewProps,
328+
isEnabled: string,
329+
330+
isEnabled: boolean,
331+
|}>;
332+
333+
export default (codegenNativeComponent<ModuleProps>(
334+
'Module',
335+
): NativeComponent<ModuleProps>);
336+
`;
337+
338+
const PROPS_CONFLICT_WITH_SPREAD_PROPS = `
339+
/**
340+
* Copyright (c) Facebook, Inc. and its affiliates.
341+
*
342+
* This source code is licensed under the MIT license found in the
343+
* LICENSE file in the root directory of this source tree.
344+
*
345+
* @format
346+
* @flow
347+
*/
348+
349+
'use strict';
350+
351+
import type {ViewProps} from 'ViewPropTypes';
352+
import type {NativeComponent} from 'codegenNativeComponent';
353+
354+
const codegenNativeComponent = require('codegenNativeComponent');
355+
356+
type PropsInFile = $ReadOnly<{|
357+
isEnabled: boolean,
358+
|}>;
359+
360+
export type ModuleProps = $ReadOnly<{|
361+
...ViewProps,
362+
363+
...PropsInFile,
364+
isEnabled: boolean,
365+
|}>;
366+
367+
export default (codegenNativeComponent<ModuleProps>(
368+
'Module',
369+
): NativeComponent<ModuleProps>);
370+
`;
371+
372+
const PROPS_SPREAD_CONFLICTS_WITH_PROPS = `
373+
/**
374+
* Copyright (c) Facebook, Inc. and its affiliates.
375+
*
376+
* This source code is licensed under the MIT license found in the
377+
* LICENSE file in the root directory of this source tree.
378+
*
379+
* @format
380+
* @flow
381+
*/
382+
383+
'use strict';
384+
385+
import type {ViewProps} from 'ViewPropTypes';
386+
import type {NativeComponent} from 'codegenNativeComponent';
387+
388+
const codegenNativeComponent = require('codegenNativeComponent');
389+
390+
type PropsInFile = $ReadOnly<{|
391+
isEnabled: boolean,
392+
|}>;
393+
394+
export type ModuleProps = $ReadOnly<{|
395+
...ViewProps,
396+
397+
isEnabled: boolean,
398+
...PropsInFile,
399+
|}>;
400+
401+
export default (codegenNativeComponent<ModuleProps>(
402+
'Module',
403+
): NativeComponent<ModuleProps>);
404+
`;
405+
308406
module.exports = {
309407
COMMANDS_DEFINED_INLINE,
310408
COMMANDS_DEFINED_MULTIPLE_TIMES,
@@ -314,4 +412,7 @@ module.exports = {
314412
COMMANDS_DEFINED_WITH_NULLABLE_REF,
315413
NULLABLE_WITH_DEFAULT,
316414
NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE,
415+
PROPS_CONFLICT_NAMES,
416+
PROPS_CONFLICT_WITH_SPREAD_PROPS,
417+
PROPS_SPREAD_CONFLICTS_WITH_PROPS,
317418
};

packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ exports[`RN Codegen Flow Parser Fails with error message NON_OPTIONAL_KEY_WITH_D
1616

1717
exports[`RN Codegen Flow Parser Fails with error message NULLABLE_WITH_DEFAULT 1`] = `"WithDefault<> is optional and does not need to be marked as optional. Please remove the ? annotation in front of it."`;
1818

19+
exports[`RN Codegen Flow Parser Fails with error message PROPS_CONFLICT_NAMES 1`] = `"A prop was already defined with the name isEnabled"`;
20+
21+
exports[`RN Codegen Flow Parser Fails with error message PROPS_CONFLICT_WITH_SPREAD_PROPS 1`] = `"A prop was already defined with the name isEnabled"`;
22+
23+
exports[`RN Codegen Flow Parser Fails with error message PROPS_SPREAD_CONFLICTS_WITH_PROPS 1`] = `"A prop was already defined with the name isEnabled"`;
24+
1925
exports[`RN Codegen Flow Parser can generate fixture ALL_PROP_TYPES_NO_EVENTS 1`] = `
2026
Object {
2127
"modules": Object {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,17 @@ function buildPropSchema(property, types: TypeMap): ?PropTypeShape {
302302
// $FlowFixMe there's no flowtype for ASTs
303303
type PropAST = Object;
304304

305+
function verifyPropNotAlreadyDefined(
306+
props: $ReadOnlyArray<PropAST>,
307+
needleProp: PropAST,
308+
) {
309+
const propName = needleProp.key.name;
310+
const foundProp = props.some(prop => prop.key.name === propName);
311+
if (foundProp) {
312+
throw new Error(`A prop was already defined with the name ${propName}`);
313+
}
314+
}
315+
305316
function flattenProperties(
306317
typeDefinition: $ReadOnlyArray<PropAST>,
307318
types: TypeMap,
@@ -319,8 +330,12 @@ function flattenProperties(
319330
})
320331
.reduce((acc, item) => {
321332
if (Array.isArray(item)) {
333+
item.forEach(prop => {
334+
verifyPropNotAlreadyDefined(acc, prop);
335+
});
322336
return acc.concat(item);
323337
} else {
338+
verifyPropNotAlreadyDefined(acc, item);
324339
acc.push(item);
325340
return acc;
326341
}

0 commit comments

Comments
 (0)