Initial Open Sourcing of React Native Compatibility Check (#49311)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49311

This tool enables checking the boundary between JavaScript and Native for
backwards incompatible changes to protect against crashes.

This is useful for:

- Local Development
- Over the Air updates on platforms that support it
- Theoretically: Server Components with React Native

Check out the Readme for more information

Changelog: [General][Added] Open Sourcing React Native's Compatibility Check

Reviewed By: yungsters

Differential Revision: D69277991

fbshipit-source-id: 886a983d4b17609ce771cdd93b75f34bbd8417dc
This commit is contained in:
Eli White
2025-02-11 08:23:16 -08:00
committed by Facebook GitHub Bot
parent 28945c68da
commit 6590bb3e14
79 changed files with 10315 additions and 0 deletions
@@ -0,0 +1 @@
lib
@@ -0,0 +1,36 @@
This tool is essentially a type checker, and as such it can be difficult to
understand the data flow. Luckily, there are fairly extensive tests which can
aid in ramping up.
This tool is made up of 3 primary stages: TypeDiffing, VersionDiffing, and
ErrorFormatting.
At a high level, the schemas are passed to TypeDiffing which is the pure
typechecker. It returns all differences between the types. VersionDiffing then
interprets these results and decides if some of those changes are actually safe
in the context of React Natives JS/Native boundary.
For example, if you have a NativeModule method that returns a string union
`small | medium | large`. Any changes to that union would be flagged by
TypeDiffing as incompatible. However, adding a value to that union is safe
because it ensures your JS code handles more cases than native returns. Removing
a value from that union isnt safe though because it means your JS no longer
handles something native might return which could cause an exception.
VersionDiffing encodes the logic of what is safe and what isnt;
property/union/enum additions and removals, changing something from optional to
required and vice versa, etc. VersionDiffing has knowledge of components and
modules.
VersionDiffing returns a set of incompatible changes, which then gets passed to
ErrorFormatting. ErrorFormatting does as youd expect, converting these deep
objects into nicely formatted strings.
When contributing, some principles:
- Keep TypeDiffing and ErrorFormatting pure. They should only know about
JavaScript types, not React Native specific concepts
- Add tests for every case you can think of. This codebase can be complex and
hard to reason about when making changes. The only way to stay sane is to be
able to rely on the tests to catch anything bad youve done. Do yourself and
future contributors a favor.
@@ -0,0 +1,245 @@
# **React Native compatibility-check**
Status: Experimental (stage 1)
Work In Progress. Documentation is lacking, and intended to be used by power
users at this point.
This tool enables checking the boundary between JavaScript and Native for
backwards incompatible changes to protect against crashes.
This is useful for:
- Local Development
- Over the Air updates on platforms that support it
- Theoretically: Server Components with React Native
## **Motivating Problems**
Lets look at some motivating examples for this project.
> [!NOTE]
> The examples below are written with Flow, but the compatibility-check
> tool is agnostic to the types you write. The compatibility-check runs on JSON
> schema files, most commonly generated by the
> [@react-native/codegen](https://www.npmjs.com/package/@react-native/codegen)
> tool which supports both TypeScript and Flow.
### **Adding new methods**
You might have an Analytics Native Module in your app, and you last built the
native client a couple of days ago:
```javascript
export interface Spec extends TurboModule {
log: (eventName: string, content: string) => void;
}
```
And you are working on a change to add a new method to this Native Module:
```javascript
export interface Spec extends TurboModule {
log: (eventName: string, content: string) => void;
logError: (message: string) => void;
}
```
```
NativeAnalytics.logError('Oh No! We hit a crash')
```
Since you are working on this, youve built a new native client and tested the
change on your computer and everything works.
However, when your colleague pulls your latest changes and tries to run it,
theyll get a crash `logError is not a function`. They need to rebuild their
native client\!
Using this tool, you can detect this incompatibility at build time, getting an
error that looks like:
```
NativeAnalytics: Object added required properties, which native will not provide
-- logError
```
Errors like this can occur for much more nuanced reasons than adding a method.
For example:
### **Sending native new union values**
```javascript
export interface Spec extends TurboModule {
// You add 'system' to this union
+setColorScheme: (color: 'light' | 'dark') => void;
}
```
If you add a new option of `system` and add native support for that option, when
you call this method with `system` on your commit it would work but on an older
build not expecting `system` it will crash. This tool will give you the error
message:
```
ColorManager.setColorScheme parameter 0: Union added items, but native will not expect/support them
-- position 3 system
```
### **Changing an enum value sent from native**
As another example, say you are getting the color scheme from the system as an
integer value, used in JavaScript as an enum:
```javascript
enum TestEnum {
LIGHT = 1,
DARK = 2,
SYSTEM = 3,
}
export interface Spec extends TurboModule {
getColorScheme: () => TestEnum;
}
```
And you realize you actually need native to send `-1` for System instead of 3\.
```javascript
enum TestEnum {
LIGHT = 1,
DARK = 2,
SYSTEM = -1,
}
```
If you make this change and run the JavaScript on an old build, it might still
send JavaScript the value 3, which your JavaScript isnt handling anymore\!
This tool gives an error:
```javascript
ColorManager: Object contained a property with a type mismatch
-- getColorScheme: has conflicting type changes
--new: ()=>Enum<number>
--old: ()=>Enum<number>
Function return types do not match
--new: ()=>Enum<number>
--old: ()=>Enum<number>
Enum types do not match
--new: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = -1}
--old: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = 3}
Enum contained a member with a type mismatch
-- Member SYSTEM: has conflicting changes
--new: -1
--old: 3
Numeric literals are not equal
--new: -1
--old: 3
```
## **Avoiding Breaking Changes**
You can use this tool to either detect changes locally to warn that you need to
install a new native build, or when doing OTA you might need to guarantee that
the changes in your PR are compatible with the native client theyll be running
in.
### **Example 1**
In example 1, when adding logError, it needs to be optional to be safe:
```javascript
export interface Spec extends TurboModule {
log: (eventName: string, content: string) => void;
logError?: (message: string) => void;
}
```
That will enforce if you are using TypeScript or Flow that you check if the
native client supports logError before calling it:
```javascript
if (NativeAnalytics.logError) {
NativeAnalytics.logError('Oh No! We hit a crash');
}
```
### **Example 2**
When you want to add '`system'` as a value to the union, modifying the existing
union is not safe. You would need to add a new optional method that has that
change. You can clean up the old method when you know that all of the builds you
ever want to run this JavaScript on have native support.
```javascript
export interface Spec extends TurboModule {
+setColorScheme: (color: 'light' | 'dark') => void
+setColorSchemeWithSystem?: (color: 'light' | 'dark' | 'system') => void
}
```
### **Example 3**
Changing a union case is similar to Example 2, you would either need a new
method, or support the existing value and the new `-1`.
```
enum TestEnum {
LIGHT = 1,
DARK = 2,
SYSTEM = 3,
SYSTEM_ALSO = -1,
}
```
## **Installation**
```
yarn add @react-native/compatibility-check
```
## **Usage**
To use this package, youll need a script that works something like this:
This script checks the compatibility of a React Native app's schema between two
versions. It takes into account the changes made to the schema and determines
whether they are compatible or not.
```javascript
import {compareSchemas} from '@react-native/compatibility-check';
const util = require('util');
async function run(argv: Argv, STDERR: string) {
const debug = (log: mixed) => {
argv.debug &&
console.info(util.inspect(log, {showHidden: false, depth: null}));
};
const currentSchema =
JSON.parse(/*you'll read the file generated by codegen wherever it is in your app*/);
const previousSchema =
JSON.parse(/*you'll read the schema file that you persisted from when your native app was built*/);
const safetyResult = compareSchemas(currentSchema, previousSchema);
const summary = safetyResult.getSummary();
switch (summary.status) {
case 'ok':
debug('No changes in boundary');
console.log(JSON.stringify(summary));
break;
case 'patchable':
debug('Changes in boundary, but are compatible');
debug(result.getDebugInfo());
console.log(JSON.stringify(summary));
break;
default:
debug(result.getDebugInfo());
console.error(JSON.stringify(result.getErrors()));
throw new Error(`Incompatible changes in boundary`);
}
}
```
@@ -0,0 +1,38 @@
{
"name": "@react-native/compatibility-check",
"version": "0.0.1",
"description": "Check a React Native app's boundary between JS and Native for incompatibilities",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react-native.git",
"directory": "packages/react-native-compatibility-check"
},
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-compatibility-check#readme",
"keywords": [
"boundary",
"crashes",
"native",
"codegen",
"tools",
"react-native"
],
"bugs": "https://github.com/facebook/react-native/issues",
"engines": {
"node": ">=18"
},
"exports": {
".": "./src/index.js",
"./package.json": "./package.json"
},
"files": [
"dist"
],
"dependencies": {
"@react-native/codegen": "0.79.0-main"
},
"devDependencies": {
"flow-remove-types": "^2.237.2",
"rimraf": "^3.0.2"
}
}
@@ -0,0 +1,239 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {
CompleteTypeAnnotation,
NamedShape,
NativeModuleEnumMember,
} from '@react-native/codegen/src/CodegenSchema';
type TypeAnnotationComparisonError = {
type: 'TypeAnnotationComparisonError',
message: string,
newerAnnotation: CompleteTypeAnnotation,
olderAnnotation: CompleteTypeAnnotation,
previousError?: TypeComparisonError,
};
type TypeInformationComparisonError = {
type: 'TypeInformationComparisonError',
message: string,
newerType: CompleteTypeAnnotation,
olderType: CompleteTypeAnnotation,
previousError?: TypeComparisonError,
};
type PropertyComparisonError = {
type: 'PropertyComparisonError',
message: string,
mismatchedProperties: Array<{
property: string,
fault?: TypeComparisonError,
...
}>,
previousError?: TypeComparisonError,
};
type PositionalComparisonError = {
type: 'PositionalComparisonError',
message: string,
erroneousItems: Array<[number, CompleteTypeAnnotation]>,
previousError?: TypeComparisonError,
};
type MemberComparisonError = {
type: 'MemberComparisonError',
message: string,
mismatchedMembers: Array<{
member: string,
fault?: TypeComparisonError,
}>,
previousError?: TypeComparisonError,
};
export type TypeComparisonError =
| TypeAnnotationComparisonError
| TypeInformationComparisonError
| PropertyComparisonError
| PositionalComparisonError
| MemberComparisonError;
// Collects changes that may be type safe within parameters, unions, intersections, and tuples
export type PositionalComparisonResult = {
typeKind: 'stringUnion' | 'union' | 'intersection' | 'parameter' | 'tuple',
// Nested changes stores the position of the old type followed by new
// Except for union and intersection, new position === old position
nestedChanges: Array<[number, number, ComparisonResult]>,
// These properties should never occur for a tuple
addedElements?: Array<[number, CompleteTypeAnnotation]>,
removedElements?: Array<[number, CompleteTypeAnnotation]>,
...
};
export type FunctionComparisonResult = {
returnType?: ComparisonResult,
// The following should always have typeKind 'parameter'
parameterTypes?: PositionalComparisonResult,
...
};
// Array<NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>>
export type PropertiesComparisonResult = {
addedProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
missingProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
errorProperties?: Array<{
property: string,
fault?: TypeComparisonError,
...
}>,
madeStrict?: Array<{
property: string,
furtherChanges?: ComparisonResult,
...
}>,
madeOptional?: Array<{
property: string,
furtherChanges?: ComparisonResult,
...
}>,
nestedPropertyChanges?: Array<[string, ComparisonResult]>,
...
};
export type MembersComparisonResult = {
addedMembers?: Array<NativeModuleEnumMember>,
missingMembers?: Array<NativeModuleEnumMember>,
errorMembers?: Array<{
member: string,
fault?: TypeComparisonError,
}>,
};
export type NullableComparisonResult = {
/* Four possible cases of change:
void goes to T? :: typeRefined !optionsReduced
T? goes to void :: typeRefined optionsReduced
T goes to T? :: !typeRefined !optionsReduced
T? goes to T :: !typeRefined optionsReduced
*/
typeRefined: boolean,
optionsReduced: boolean,
// interiorLog not available if either type is void
interiorLog: ?ComparisonResult,
newType: ?CompleteTypeAnnotation,
oldType: ?CompleteTypeAnnotation,
...
};
export type ComparisonResult =
| {status: 'matching'}
| {status: 'skipped'}
| {status: 'nullableChange', nullableLog: NullableComparisonResult}
| {status: 'properties', propertyLog: PropertiesComparisonResult}
| {status: 'members', memberLog: MembersComparisonResult}
| {status: 'functionChange', functionChangeLog: FunctionComparisonResult}
| {status: 'positionalTypeChange', changeLog: PositionalComparisonResult}
| {status: 'error', errorLog: TypeComparisonError};
export function isPropertyLogEmpty(
result: PropertiesComparisonResult,
): boolean {
return !(
result.addedProperties ||
result.missingProperties ||
result.nestedPropertyChanges ||
result.madeStrict ||
result.madeOptional ||
result.errorProperties
);
}
export function isMemberLogEmpty(result: MembersComparisonResult): boolean {
return !(result.addedMembers || result.missingMembers || result.errorMembers);
}
export function isFunctionLogEmpty(result: FunctionComparisonResult): boolean {
return !(result.returnType || result.parameterTypes);
}
export function makeError(error: TypeComparisonError): ComparisonResult {
return {
status: 'error',
errorLog: error,
};
}
export function typeInformationComparisonError(
message: string,
newerType: CompleteTypeAnnotation,
olderType: CompleteTypeAnnotation,
previousError?: TypeComparisonError,
): TypeComparisonError {
return {
type: 'TypeInformationComparisonError',
message,
newerType,
olderType,
previousError,
};
}
export function typeAnnotationComparisonError(
message: string,
newerAnnotation: CompleteTypeAnnotation,
olderAnnotation: CompleteTypeAnnotation,
previousError?: TypeComparisonError,
): TypeComparisonError {
return {
type: 'TypeAnnotationComparisonError',
message,
newerAnnotation,
olderAnnotation,
previousError,
};
}
export function propertyComparisonError(
message: string,
mismatchedProperties: Array<{
property: string,
fault?: TypeComparisonError,
...
}>,
previousError?: TypeComparisonError,
): TypeComparisonError {
return {
type: 'PropertyComparisonError',
message,
mismatchedProperties,
previousError,
};
}
export function memberComparisonError(
message: string,
mismatchedMembers: Array<{
member: string,
fault?: TypeComparisonError,
}>,
previousError?: TypeComparisonError,
): TypeComparisonError {
return {
type: 'MemberComparisonError',
message,
mismatchedMembers,
previousError,
};
}
export function positionalComparisonError(
message: string,
erroneousItems: Array<[number, CompleteTypeAnnotation]>,
previousError?: TypeComparisonError,
): TypeComparisonError {
return {
type: 'PositionalComparisonError',
message,
erroneousItems,
previousError,
};
}
@@ -0,0 +1,207 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {
PropertiesComparisonResult,
TypeComparisonError,
} from './ComparisonResult';
import type {CompleteTypeAnnotation} from '@react-native/codegen/src/CodegenSchema';
export type ErrorCode =
| 'addedProps'
| 'removedProps'
| 'changedParams'
| 'incompatibleTypes'
| 'requiredProps'
| 'optionalProps'
| 'nonNullableOfNull'
| 'nullableOfNonNull'
| 'removedUnionCases'
| 'addedUnionCases'
| 'addedEnumCases'
| 'removedEnumCases'
| 'removedIntersectCases'
| 'addedIntersectCases'
| 'removedModule'
| 'removedComponent';
export type TypeStore = {
typeName: string,
typeInformation: CompleteTypeAnnotation,
...
};
// Stores object properties that are added or removed which could be patchable
export type ObjectTypeChangeStore = {
typeName: string,
newType: CompleteTypeAnnotation,
oldType: CompleteTypeAnnotation,
propertyChange: PropertiesComparisonResult,
};
export type ErrorStore = {
typeName: string,
errorCode: ErrorCode,
errorInformation: TypeComparisonError,
};
export type FormattedErrorStore = {
message: string,
errorCode: ErrorCode,
};
export type NativeSpecErrorStore = {
nativeSpecName: string,
omitted: boolean,
errorCode: ErrorCode,
errorInformation?: TypeComparisonError,
changeInformation?: DiffSet,
};
export type ExportableNativeSpecErrorStore = {
nativeSpecName: string,
omitted: boolean,
errorCode: ErrorCode,
errorInformation?: TypeComparisonError,
changeInformation?: ExportableDiffSet,
};
export type DiffSet = {
newTypes: Set<TypeStore>,
deprecatedTypes: Set<TypeStore>,
objectTypeChanges: Set<ObjectTypeChangeStore>,
incompatibleChanges: Set<ErrorStore>,
};
type ExportableDiffSet = {
newTypes: Array<TypeStore>,
deprecatedTypes: Array<TypeStore>,
objectTypeChanges: Array<ObjectTypeChangeStore>,
incompatibleChanges: Array<ErrorStore>,
};
export type Framework = 'ReactNative';
export type SchemaDiffers = {
incompatibleSpecs: ?Set<NativeSpecErrorStore>,
};
type ExportableSchemaDiffers = {
incompatibleSpecs: ?Array<ExportableNativeSpecErrorStore>,
};
export type SchemaDiffCategory = 'new' | 'deprecated' | SchemaDiffers;
type ExportableSchemaDiffCategory =
| 'new'
| 'deprecated'
| ExportableSchemaDiffers;
export type SchemaDiff = {
name: string,
framework: Framework,
status: SchemaDiffCategory,
};
export type ExportableSchemaDiff = {
name: string,
framework: Framework,
status: ExportableSchemaDiffCategory,
};
export type Version = {
device: 'android' | 'ios',
number: string,
...
};
export type Incompatible = {
framework: Framework,
incompatibleSpecs?: Array<NativeSpecErrorStore>,
};
export type IncompatiblityReport = {
[hasteModuleName: string]: Incompatible,
};
export type DiffSummary = {
/** status records how the diff compares against older versions
* ok: there are no changes that impact older versions
* patchable: there are additions (or modifications) that are not suported
* in older versions but is safe with an auto-generated patch
* incompatible: there are modifications that are not safe for use with older
* versions and are not fixable with an auto-generated patchable
*/
status: 'ok' | 'patchable' | 'incompatible',
// If there are incompatible changes, provide a record of them, otherwise {}
incompatibilityReport: IncompatiblityReport,
};
export type FormattedIncompatible = {
framework: Framework,
incompatibleSpecs?: Array<FormattedErrorStore>,
};
export type FormattedIncompatiblityReport = {
[hasteModuleName: string]: FormattedIncompatible,
};
export type FormattedDiffSummary = {
/** status records how the diff compares against older versions
* ok: there are no changes that impact older versions
* patchable: there are additions (or modifications) that are not suported
* in older versions but is safe with an auto-generated patch
* incompatible: there are modifications that are not safe for use with older
* versions and are not fixable with an auto-generated patchable
*/
status: 'ok' | 'patchable' | 'incompatible',
// If there are incompatible changes, provide a record of them, otherwise {}
incompatibilityReport: FormattedIncompatiblityReport,
};
function diffSetExporter(diffSet: DiffSet): ExportableDiffSet {
return {
newTypes: Array.from(diffSet.newTypes),
deprecatedTypes: Array.from(diffSet.deprecatedTypes),
objectTypeChanges: Array.from(diffSet.objectTypeChanges),
incompatibleChanges: Array.from(diffSet.incompatibleChanges),
};
}
export function nativeSpecErrorExporter(
nativeSpecError: NativeSpecErrorStore,
): ExportableNativeSpecErrorStore {
if (nativeSpecError.changeInformation) {
return {
nativeSpecName: nativeSpecError.nativeSpecName,
omitted: nativeSpecError.omitted,
errorCode: nativeSpecError.errorCode,
errorInformation: nativeSpecError.errorInformation,
changeInformation: diffSetExporter(nativeSpecError.changeInformation),
};
}
return {
nativeSpecName: nativeSpecError.nativeSpecName,
omitted: nativeSpecError.omitted,
errorCode: nativeSpecError.errorCode,
errorInformation: nativeSpecError.errorInformation,
};
}
function schemaDiffCategoryExporter(
status: SchemaDiffCategory,
): ExportableSchemaDiffCategory {
switch (status) {
case 'new':
case 'deprecated':
return status;
default:
return {
incompatibleSpecs: status.incompatibleSpecs
? Array.from(status.incompatibleSpecs).map(nativeSpecErrorExporter)
: undefined,
};
}
}
export function schemaDiffExporter(
schemaDiff: SchemaDiff,
): ExportableSchemaDiff {
return {
name: schemaDiff.name,
framework: schemaDiff.framework,
status: schemaDiffCategoryExporter(schemaDiff.status),
};
}
@@ -0,0 +1,309 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {TypeComparisonError} from './ComparisonResult';
import type {
DiffSummary,
ErrorStore,
FormattedDiffSummary,
FormattedErrorStore,
FormattedIncompatible,
FormattedIncompatiblityReport,
NativeSpecErrorStore,
} from './DiffResults';
import type {CompleteTypeAnnotation} from '@react-native/codegen/src/CodegenSchema';
function indentedLineStart(indent: number): string {
return '\n' + ' '.repeat(indent);
}
export function formatErrorMessage(
error: TypeComparisonError,
indent: number = 0,
): string {
switch (error.type) {
case 'PropertyComparisonError':
const formattedProperties = error.mismatchedProperties.map(
individualPropertyError =>
indentedLineStart(indent + 1) +
'-- ' +
individualPropertyError.property +
(individualPropertyError.fault
? ': ' +
formatErrorMessage(individualPropertyError.fault, indent + 2)
: ''),
);
return error.message + formattedProperties.join('');
case 'PositionalComparisonError':
const formattedPositionalChanges = error.erroneousItems.map(
([index, type]) =>
indentedLineStart(indent + 1) +
'-- position ' +
index +
' ' +
formatTypeAnnotation(type),
);
return error.message + formattedPositionalChanges.join('');
case 'TypeAnnotationComparisonError':
const previousError = error.previousError;
return (
error.message +
indentedLineStart(indent + 1) +
'--new: ' +
formatTypeAnnotation(error.newerAnnotation) +
indentedLineStart(indent + 1) +
'--old: ' +
formatTypeAnnotation(error.olderAnnotation) +
(previousError != null
? indentedLineStart(indent + 1) +
'' +
formatErrorMessage(previousError, indent + 2)
: '')
);
case 'TypeInformationComparisonError':
// I'm not sure that this error type is possible with the codegen
return (
error.message +
indentedLineStart(indent + 1) +
'-- new: ' +
formatTypeAnnotation(error.newerType) +
indentedLineStart(indent + 1) +
'-- old: ' +
formatTypeAnnotation(error.olderType)
);
case 'MemberComparisonError':
const formattedMembers = error.mismatchedMembers.map(
individualMemberError =>
indentedLineStart(indent + 1) +
'-- Member ' +
individualMemberError.member +
(individualMemberError.fault
? ': ' + formatErrorMessage(individualMemberError.fault, indent + 2)
: ''),
);
return error.message + formattedMembers.join('');
default:
(error.type: empty);
return '';
}
}
function formatTypeAnnotation(annotation: CompleteTypeAnnotation): string {
switch (annotation.type) {
case 'AnyTypeAnnotation':
return 'any';
case 'ArrayTypeAnnotation':
return 'Array<' + formatTypeAnnotation(annotation.elementType) + '>';
case 'BooleanTypeAnnotation':
return 'boolean';
case 'EnumDeclaration': {
let shortHandType = '';
switch (annotation.memberType) {
case 'StringTypeAnnotation':
shortHandType = 'string';
break;
case 'NumberTypeAnnotation':
shortHandType = 'number';
break;
default:
(annotation.memberType: empty);
throw new Error('Unexpected enum memberType');
}
return `Enum<${shortHandType}>` + '';
}
case 'EnumDeclarationWithMembers': {
let shortHandType = '';
switch (annotation.memberType) {
case 'StringTypeAnnotation':
shortHandType = 'string';
break;
case 'NumberTypeAnnotation':
shortHandType = 'number';
break;
default:
(annotation.memberType: empty);
throw new Error('Unexptected enum memberType');
}
return (
`Enum<${shortHandType}> {` +
annotation.members
.map(
member => `${member.name} = ${formatTypeAnnotation(member.value)}`,
)
.join(', ') +
'}'
);
}
case 'FunctionTypeAnnotation':
return (
'(' +
annotation.params
.map(
param =>
param.name +
(param.optional ? '?' : '') +
': ' +
formatTypeAnnotation(param.typeAnnotation),
)
.join(', ') +
')' +
'=>' +
formatTypeAnnotation(annotation.returnTypeAnnotation)
);
case 'NullableTypeAnnotation':
return '?' + formatTypeAnnotation(annotation.typeAnnotation);
case 'NumberTypeAnnotation':
return 'number';
case 'DoubleTypeAnnotation':
return 'double';
case 'FloatTypeAnnotation':
return 'float';
case 'Int32TypeAnnotation':
return 'int';
case 'NumberLiteralTypeAnnotation':
return annotation.value.toString();
case 'ObjectTypeAnnotation':
return (
'{' +
annotation.properties
.map(
property =>
property.name +
(property.optional ? '?' : '') +
': ' +
formatTypeAnnotation(property.typeAnnotation),
)
.join(', ') +
'}'
);
case 'StringLiteralTypeAnnotation':
// If the string is a number, disambiguate from a number literal by adding quotes
// Other things are obviously strings so quotes unconditionally would just add noise
return parseInt(annotation.value, 10).toString() === annotation.value ||
annotation.value.includes(' ')
? `'${annotation.value}'`
: annotation.value;
case 'StringLiteralUnionTypeAnnotation':
return (
'(' +
annotation.types
.map(stringLit => formatTypeAnnotation(stringLit))
.join(' | ') +
')'
);
case 'StringTypeAnnotation':
return 'string';
case 'UnionTypeAnnotation': {
const shortHandType =
annotation.memberType === 'StringTypeAnnotation'
? 'string'
: annotation.memberType === 'ObjectTypeAnnotation'
? 'Object'
: 'number';
return `Union<${shortHandType}>`;
}
case 'PromiseTypeAnnotation':
return 'Promise<' + formatTypeAnnotation(annotation.elementType) + '>';
case 'EventEmitterTypeAnnotation':
return (
'EventEmitter<' + formatTypeAnnotation(annotation.typeAnnotation) + '>'
);
case 'TypeAliasTypeAnnotation':
case 'ReservedTypeAnnotation':
return annotation.name;
case 'VoidTypeAnnotation':
return 'void';
case 'MixedTypeAnnotation':
return 'mixed';
case 'GenericObjectTypeAnnotation':
if (annotation.dictionaryValueType) {
return `{[string]: ${formatTypeAnnotation(annotation.dictionaryValueType)}`;
}
return 'Object';
default:
(annotation.type: empty);
return JSON.stringify(annotation);
}
}
export function formatErrorStore(errorStore: ErrorStore): FormattedErrorStore {
return {
message:
errorStore.typeName +
': ' +
formatErrorMessage(errorStore.errorInformation),
errorCode: errorStore.errorCode,
};
}
export function formatNativeSpecErrorStore(
specError: NativeSpecErrorStore,
): Array<FormattedErrorStore> {
if (specError.errorInformation) {
return [
{
message:
specError.nativeSpecName +
': ' +
formatErrorMessage(specError.errorInformation),
errorCode: specError.errorCode,
},
];
}
if (specError.changeInformation?.incompatibleChanges != null) {
return Array.from(specError.changeInformation.incompatibleChanges).map(
errorStore => formatErrorStore(errorStore),
);
}
// changeInformation does not contain incompatible changes
return [];
}
export function formatDiffSet(summary: DiffSummary): FormattedDiffSummary {
const summaryStatus = summary.status;
if (summaryStatus === 'ok' || summaryStatus === 'patchable') {
// $FlowFixMe I don't think we can ever get in this branch
return summary;
}
const hasteModules = Object.keys(summary.incompatibilityReport);
const incompatibles = summary.incompatibilityReport;
const formattedIncompatibilities: FormattedIncompatiblityReport = {};
hasteModules.forEach(hasteModule => {
const incompat = incompatibles[hasteModule];
const formattedIncompat: FormattedIncompatible = {
framework: incompat.framework,
};
if (incompat.incompatibleSpecs) {
// nested errors
formattedIncompat.incompatibleSpecs = incompat.incompatibleSpecs.reduce(
(
formattedModuleErrors: $ReadOnlyArray<FormattedErrorStore>,
specErrorStore,
) =>
formattedModuleErrors.concat(
formatNativeSpecErrorStore(specErrorStore),
),
[],
);
}
formattedIncompatibilities[hasteModule] = formattedIncompat;
});
return {
status: (summaryStatus: 'incompatible'),
incompatibilityReport: formattedIncompatibilities,
};
}
@@ -0,0 +1,290 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {CompleteTypeAnnotation} from '@react-native/codegen/src/CodegenSchema';
import invariant from 'invariant';
export function sortTypeAnnotations(
annotations: $ReadOnlyArray<CompleteTypeAnnotation>,
): Array<[number, CompleteTypeAnnotation]> {
const sortableArray = annotations.map(
(a, i): [number, CompleteTypeAnnotation] => [i, a],
);
return sortableArray.sort(compareTypeAnnotationForSorting);
}
const EQUALITY_MSG = 'typeA and typeB differ despite check';
export function compareTypeAnnotationForSorting(
[originalPositionA, typeA]: [number, CompleteTypeAnnotation],
[originalPositionB, typeB]: [number, CompleteTypeAnnotation],
): number {
if (typeA.type !== typeB.type) {
if (typeA.type === 'NullableTypeAnnotation') {
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.typeAnnotation],
[originalPositionB, typeB],
);
}
if (typeB.type === 'NullableTypeAnnotation') {
return compareTypeAnnotationForSorting(
[originalPositionA, typeA],
[originalPositionB, typeB.typeAnnotation],
);
}
return (
typeAnnotationArbitraryOrder(typeA) - typeAnnotationArbitraryOrder(typeB)
);
}
switch (typeA.type) {
case 'AnyTypeAnnotation':
return 0;
case 'ArrayTypeAnnotation':
invariant(typeB.type === 'ArrayTypeAnnotation', EQUALITY_MSG);
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.elementType],
[originalPositionB, typeB.elementType],
);
case 'BooleanTypeAnnotation':
return originalPositionA - originalPositionB;
case 'EnumDeclaration':
invariant(typeB.type === 'EnumDeclaration', EQUALITY_MSG);
return typeA.memberType.localeCompare(typeB.memberType);
case 'EnumDeclarationWithMembers':
invariant(typeB.type === 'EnumDeclarationWithMembers', EQUALITY_MSG);
return compareNameAnnotationArraysForSorting(
[originalPositionA, typeA.members.map(m => [m.name, m.value])],
[originalPositionB, typeB.members.map(m => [m.name, m.value])],
);
case 'FunctionTypeAnnotation':
invariant(typeB.type === 'FunctionTypeAnnotation', EQUALITY_MSG);
const parmComparison = compareAnnotationArraysForSorting(
[originalPositionA, typeA.params.map(p => p.typeAnnotation)],
[originalPositionB, typeB.params.map(p => p.typeAnnotation)],
);
if (parmComparison === 0) {
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.returnTypeAnnotation],
[originalPositionB, typeB.returnTypeAnnotation],
);
}
return parmComparison;
case 'EventEmitterTypeAnnotation':
invariant(typeB.type === 'EventEmitterTypeAnnotation', EQUALITY_MSG);
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.typeAnnotation],
[originalPositionB, typeB.typeAnnotation],
);
case 'GenericObjectTypeAnnotation':
invariant(typeB.type === 'GenericObjectTypeAnnotation', EQUALITY_MSG);
if (
typeA.dictionaryValueType == null &&
typeB.dictionaryValueType == null
) {
return 0;
} else if (
typeA.dictionaryValueType != null &&
typeB.dictionaryValueType != null
) {
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.dictionaryValueType],
[originalPositionB, typeB.dictionaryValueType],
);
} else {
return typeA.dictionaryValueType == null ? -1 : 1;
}
case 'NullableTypeAnnotation':
invariant(typeB.type === 'NullableTypeAnnotation', EQUALITY_MSG);
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.typeAnnotation],
[originalPositionB, typeB.typeAnnotation],
);
case 'NumberTypeAnnotation':
case 'Int32TypeAnnotation':
case 'FloatTypeAnnotation':
case 'DoubleTypeAnnotation':
return 0;
case 'NumberLiteralTypeAnnotation':
invariant(typeB.type === 'NumberLiteralTypeAnnotation', EQUALITY_MSG);
return typeA.value - typeB.value;
case 'ObjectTypeAnnotation':
invariant(typeB.type === 'ObjectTypeAnnotation', EQUALITY_MSG);
return compareNameAnnotationArraysForSorting(
[
originalPositionA,
typeA.properties.map(p => [p.name, p.typeAnnotation]),
],
[
originalPositionB,
typeB.properties.map(p => [p.name, p.typeAnnotation]),
],
);
case 'StringTypeAnnotation':
return originalPositionA - originalPositionB;
case 'StringLiteralTypeAnnotation':
invariant(typeB.type === 'StringLiteralTypeAnnotation', EQUALITY_MSG);
return typeA.value.localeCompare(typeB.value);
case 'StringLiteralUnionTypeAnnotation':
invariant(
typeB.type === 'StringLiteralUnionTypeAnnotation',
EQUALITY_MSG,
);
return compareAnnotationArraysForSorting(
[originalPositionA, typeA.types],
[originalPositionB, typeB.types],
);
case 'UnionTypeAnnotation':
invariant(typeB.type === 'UnionTypeAnnotation', EQUALITY_MSG);
return 0;
case 'VoidTypeAnnotation':
return 0;
case 'ReservedTypeAnnotation':
return 0;
case 'PromiseTypeAnnotation':
invariant(typeB.type === 'PromiseTypeAnnotation', EQUALITY_MSG);
return compareTypeAnnotationForSorting(
[originalPositionA, typeA.elementType],
[originalPositionB, typeB.elementType],
);
case 'TypeAliasTypeAnnotation':
return 0;
case 'MixedTypeAnnotation':
return 0;
default:
(typeA.type: empty);
return -1;
}
}
function nameComparison(
[nameA]: [string, CompleteTypeAnnotation],
[nameB]: [string, CompleteTypeAnnotation],
) {
if (nameA === nameB) {
return 0;
} else if (nameA < nameB) {
return -1;
}
return 1;
}
function compareNameAnnotationArraysForSorting(
[originalPositionA, arrayA]: [
number,
Array<[string, CompleteTypeAnnotation]>,
],
[originalPositionB, arrayB]: [
number,
Array<[string, CompleteTypeAnnotation]>,
],
) {
if (arrayA.length - arrayB.length !== 0) {
return arrayA.length - arrayB.length;
}
const nameSortedA = arrayA.sort(nameComparison);
const nameSortedB = arrayB.sort(nameComparison);
for (let i = 0; i < nameSortedA.length; i++) {
if (nameSortedA[i][0] === nameSortedB[i][0]) {
const compared = compareTypeAnnotationForSorting(
[originalPositionA, nameSortedA[i][1]],
[originalPositionB, nameSortedB[i][1]],
);
if (compared !== 0) {
return compared;
}
continue;
}
if (nameSortedA[i][0] < nameSortedB[i][0]) {
return -1;
}
return 1;
}
return 0;
}
function compareAnnotationArraysForSorting(
[originalPositionA, arrayA]: [number, $ReadOnlyArray<CompleteTypeAnnotation>],
[originalPositionB, arrayB]: [number, $ReadOnlyArray<CompleteTypeAnnotation>],
) {
if (arrayA.length - arrayB.length !== 0) {
return arrayA.length - arrayB.length;
}
for (let i = 0; i < arrayA.length; i++) {
const compared = compareTypeAnnotationForSorting(
[originalPositionA, arrayA[i]],
[originalPositionB, arrayB[i]],
);
if (compared !== 0) {
return compared;
}
continue;
}
return 0;
}
function typeAnnotationArbitraryOrder(annotation: CompleteTypeAnnotation) {
switch (annotation.type) {
case 'AnyTypeAnnotation':
return 0;
case 'ArrayTypeAnnotation':
return 1;
case 'BooleanTypeAnnotation':
return 2;
case 'FunctionTypeAnnotation':
return 3;
case 'EventEmitterTypeAnnotation':
return 4;
case 'PromiseTypeAnnotation':
return 5;
case 'GenericObjectTypeAnnotation':
return 6;
case 'NullableTypeAnnotation':
return 9;
case 'NumberTypeAnnotation':
return 10;
case 'Int32TypeAnnotation':
return 11;
case 'DoubleTypeAnnotation':
return 12;
case 'FloatTypeAnnotation':
return 13;
case 'NumberLiteralTypeAnnotation':
return 14;
case 'ObjectTypeAnnotation':
return 15;
case 'StringLiteralUnionTypeAnnotation':
return 17;
case 'StringTypeAnnotation':
return 18;
case 'StringLiteralTypeAnnotation':
return 19;
case 'VoidTypeAnnotation':
return 20;
case 'EnumDeclaration':
return 21;
case 'EnumDeclarationWithMembers':
return 22;
case 'GenericObjectTypeAnnotation':
return 25;
case 'TypeAliasTypeAnnotation':
return 26;
case 'MixedTypeAnnotation':
return 27;
case 'ReservedTypeAnnotation':
return 28;
case 'UnionTypeAnnotation':
return 30;
default:
(annotation.type: empty);
return -1;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
import {formatDiffSet} from '../ErrorFormatting.js';
import {buildSchemaDiff, summarizeDiffSet} from '../VersionDiffing.js';
import {incompatibleChanges, okayChanges} from './ErrorFormattingTests.js';
import {getTestSchema} from './utilities/getTestSchema.js';
describe('codegen formattedSummarizeDiffSet', () => {
okayChanges.forEach(([after, before]) => {
it(`allows a diff from ${before} to ${after}`, () => {
const beforeObj = getTestSchema(
__dirname,
'__fixtures__',
before + '.js.flow',
);
const afterObj = getTestSchema(
__dirname,
'__fixtures__',
after + '.js.flow',
);
const result = formatDiffSet(
summarizeDiffSet(buildSchemaDiff(afterObj, beforeObj)),
);
expect(result.status).toEqual('ok');
expect(result).toMatchSnapshot();
});
});
incompatibleChanges.forEach(([after, before]) => {
it(`reports a diff from ${before} to ${after}`, () => {
const beforeObj = getTestSchema(
__dirname,
'__fixtures__',
before + '.js.flow',
);
const afterObj = getTestSchema(
__dirname,
'__fixtures__',
after + '.js.flow',
);
const result = formatDiffSet(
summarizeDiffSet(buildSchemaDiff(afterObj, beforeObj)),
);
expect(result.status).toEqual('incompatible');
expect(result).toMatchSnapshot();
});
});
});
@@ -0,0 +1,150 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
export const okayChanges = [
[
'native-module-before-after-types-removed/NativeModuleBeforeAfterTypes',
'native-module-before-after-types/NativeModuleBeforeAfterTypes',
],
[
'native-module-get-constants/NativeModule',
'native-module-get-constants-added-optional-constant/NativeModule',
],
[
'native-module-with-enum-from-native-changes/NativeModule',
'native-module-with-enum-from-native/NativeModule',
],
[
'native-module-with-union/NativeModule',
'native-module-with-union-changes/NativeModule',
],
[
'native-component-with-command/NativeComponent',
'native-component-with-command/NativeComponent',
],
[
'native-component-with-props/NativeComponent',
'native-component-with-props-default-change/NativeComponent',
],
];
export const incompatibleChanges = [
[
'native-module-before-after-types/NativeModuleBeforeAfterTypes',
'native-module-before-after-types-removed/NativeModuleBeforeAfterTypes',
],
[
'native-module-before-after-types/NativeModuleBeforeAfterTypes',
'native-module-before-after-types-type-changed/NativeModuleBeforeAfterTypes',
],
['native-module/NativeModule', 'native-module-changed/NativeModule'],
[
'native-module-nested/NativeModule',
'native-module-nested-changed/NativeModule',
],
[
'native-module-nested-optional/NativeModule',
'native-module-nested/NativeModule',
],
[
'native-module-nested-nullable/NativeModule',
'native-module-nested-optional/NativeModule',
],
[
'native-module-nested-optional/NativeModule',
'native-module-nested-changed/NativeModule',
],
[
'native-module-nested-alias/NativeModule',
'native-module-nested-alias-changed/NativeModule',
],
[
'native-module-with-dictionary/NativeModule',
'native-module-with-dictionary-changed/NativeModule',
],
[
'native-module-with-enum-changes/NativeModule',
'native-module-with-enum/NativeModule',
],
[
'native-module-with-enum/NativeModule',
'native-module-with-enum-type-changes/NativeModule',
],
[
'native-module-with-enum/NativeModule',
'native-module-with-enum-value-changes/NativeModule',
],
[
'native-module-with-enum-from-native/NativeModule',
'native-module-with-enum-from-native-changes/NativeModule',
],
[
'native-module-with-enum-from-native/NativeModule',
'native-module-with-enum-from-native-type-changes/NativeModule',
],
[
'native-module-with-enum-from-native/NativeModule',
'native-module-with-enum-from-native-value-changes/NativeModule',
],
[
'native-module-with-eventemitter/NativeModule',
'native-module-with-eventemitter-changes/NativeModule',
],
[
'native-module/NativeModule',
'native-module-with-optional-argument/NativeModule',
],
[
'native-module-with-union/NativeModule',
'native-module-with-union-type-changes/NativeModule',
],
[
'native-module-with-union-changes/NativeModule',
'native-module-with-union/NativeModule',
],
[
'native-module-with-union-from-native/NativeModule',
'native-module-with-union-from-native-changes/NativeModule',
],
[
'native-module-with-union/NativeModule',
'native-module-with-union-confusing-string-literals/NativeModule',
],
[
'native-component-with-command/NativeComponent',
'native-component-with-command-changed/NativeComponent',
],
[
'native-component-with-command-all-basic-types-arrays/NativeComponent',
'native-component-with-command-all-basic-types/NativeComponent',
],
[
'native-component-with-command-extra-arg/NativeComponent',
'native-component-with-command/NativeComponent',
],
[
'native-component-with-props/NativeComponent',
'native-component-with-props-changes/NativeComponent',
],
[
'native-component-with-props/NativeComponent',
'native-component-with-props-added-required-prop/NativeComponent',
],
[
'native-component-with-props-union-added/NativeComponent',
'native-component-with-props-union/NativeComponent',
],
[
'native-component-with-props-array-union-added/NativeComponent',
'native-component-with-props-array-union/NativeComponent',
],
];
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,169 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {ColorValue} from 'react-native/Libraries/StyleSheet/StyleSheet';
import type {
EdgeInsetsValue,
PointValue,
} from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
import type {RootTag} from 'react-native/Libraries/TurboModule/RCTExport';
import type {
Double,
Float,
Int32,
UnsafeMixed,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
bool: boolean,
string: string,
double: Double,
float: Float,
int: Int32,
mixed: UnsafeMixed,
optionalBool?: WithDefault<boolean, false>,
optionalString?: WithDefault<string, ''>,
optionalStringDiffDefault?: WithDefault<string, 'default'>,
optionalDouble?: WithDefault<Double, 0.0>,
optionalFloat?: WithDefault<Float, 0.0>,
optionalInt?: WithDefault<Int32, 0>,
reserverdEdgeInsets: EdgeInsetsValue,
reservedPointValue: PointValue,
stringUnion?: WithDefault<'foo' | 'bar', 'bar'>,
intUnion?: WithDefault<1 | 2, 1>,
nestedObject: $ReadOnly<{
string: string,
color: ColorValue,
}>,
nestedObjectChanged: $ReadOnly<{
string: boolean,
color: ColorValue,
}>,
arrayStringUnion?: WithDefault<$ReadOnlyArray<'foo' | 'bar'>, 'foo'>,
arrayStringUnionExtra?: WithDefault<
$ReadOnlyArray<'foo' | 'bar' | 'baz'>,
'bar',
>,
arrayNestedObject: $ReadOnlyArray<
$ReadOnly<{
string: string,
color: ColorValue,
}>,
>,
arrayNestedObjectChange: $ReadOnlyArray<
$ReadOnly<{
string: boolean,
color: ColorValue,
}>,
>,
}>;
type NativeType = HostComponent<NativeProps>;
type Int = Int32;
type Str = string;
type Bool = boolean;
type Fl = Float;
type Dbl = Double;
type CustomObj = {foo: string, bar: number};
type CustomObj2 = {a: Int32, b: string};
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: Int32) => void;
+methodIntString: (
viewRef: React.ElementRef<NativeType>,
a: Int32,
b: string,
) => void;
+methodString: (viewRef: React.ElementRef<NativeType>, a: string) => void;
+methodBool: (viewRef: React.ElementRef<NativeType>, a: boolean) => void;
+methodFloat: (viewRef: React.ElementRef<NativeType>, a: Float) => void;
+methodDouble: (viewRef: React.ElementRef<NativeType>, a: Double) => void;
+methodIntAlias: (viewRef: React.ElementRef<NativeType>, a: Int) => void;
+methodStringAlias: (viewRef: React.ElementRef<NativeType>, a: Str) => void;
+methodBoolAlias: (viewRef: React.ElementRef<NativeType>, a: Bool) => void;
+methodFloatAlias: (viewRef: React.ElementRef<NativeType>, a: Fl) => void;
+methodDoubleAlias: (viewRef: React.ElementRef<NativeType>, a: Dbl) => void;
+methodIntArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<Int32>,
) => void;
+methodStringArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<string>,
) => void;
+methodBoolArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<boolean>,
) => void;
+methodFloatArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<Float>,
) => void;
+methodDoubleArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<Double>,
) => void;
+methodCustomObjArray: (
viewRef: React.ElementRef<NativeType>,
a: Array<CustomObj>,
) => void;
+methodCustomObj2Array: (
viewRef: React.ElementRef<NativeType>,
a: Array<CustomObj2>,
) => void;
+methodRootTag: (viewRef: React.ElementRef<NativeType>, a: RootTag) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: [
'methodInt',
'methodIntString',
'methodString',
'methodBool',
'methodFloat',
'methodDouble',
'methodIntAlias',
'methodStringAlias',
'methodBoolAlias',
'methodFloatAlias',
'methodDoubleAlias',
'methodIntArray',
'methodStringArray',
'methodBoolArray',
'methodFloatArray',
'methodDoubleArray',
'methodCustomObjArray',
'methodCustomObj2Array',
'methodRootTag',
],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,60 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Double,
Float,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: Array<Int32>) => void;
+methodString: (
viewRef: React.ElementRef<NativeType>,
a: Array<string>,
) => void;
+methodBool: (
viewRef: React.ElementRef<NativeType>,
a: Array<boolean>,
) => void;
+methodFloat: (
viewRef: React.ElementRef<NativeType>,
a: Array<Float>,
) => void;
+methodDouble: (
viewRef: React.ElementRef<NativeType>,
a: Array<Double>,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: [
'methodInt',
'methodString',
'methodBool',
'methodFloat',
'methodDouble',
],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,48 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Double,
Float,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: Int32) => void;
+methodString: (viewRef: React.ElementRef<NativeType>, a: string) => void;
+methodBool: (viewRef: React.ElementRef<NativeType>, a: boolean) => void;
+methodFloat: (viewRef: React.ElementRef<NativeType>, a: Float) => void;
+methodDouble: (viewRef: React.ElementRef<NativeType>, a: Double) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: [
'methodInt',
'methodString',
'methodBool',
'methodFloat',
'methodDouble',
],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: string) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['methodInt'],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,38 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {Int32} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (
viewRef: React.ElementRef<NativeType>,
a: Int32,
b: string,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['methodInt'],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {Int32} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: Int32) => void;
+methodString: (viewRef: React.ElementRef<NativeType>, a: string) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['methodInt', 'methodString'],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,34 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {Int32} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{
...ViewProps,
}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+methodInt: (viewRef: React.ElementRef<NativeType>, a: Int32) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['methodInt'],
});
export default codegenNativeComponent<NativeProps>(
'NativeComponent',
) as NativeType;
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
width?: WithDefault<Int32, 100>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
width: Int32,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,39 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Double,
Float,
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
bool: boolean,
string: string,
double: Double,
float: Float,
int: Int32,
stringUnion: WithDefault<'foo' | 'bar', 'bar'>,
intUnion: WithDefault<1 | 2, 1>,
mixed: mixed,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
sizes?: WithDefault<$ReadOnlyArray<'small' | 'large' | 'huge'>, 'small'>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
sizes?: WithDefault<$ReadOnlyArray<'small' | 'large'>, 'small'>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,29 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: Int32,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,29 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'white'>,
height?: WithDefault<Int32, 100>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Float,
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
pins: $ReadOnly<{
x: Float,
y: Float,
color?: WithDefault<string, 'red'>,
}>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Float,
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
pins: $ReadOnly<{
x: Float,
y: Float,
color: string,
}>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,34 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Float,
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
pins: $ReadOnly<{
x: Float,
y: Float,
}>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
size?: WithDefault<'small' | 'large' | 'huge', 'small'>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {WithDefault} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
size?: WithDefault<'small' | 'large', 'small'>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,29 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {
Int32,
WithDefault,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
text: string,
backgroundColor?: WithDefault<string, 'transparent'>,
height?: WithDefault<Int32, 100>,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {HostComponent} from 'react-native';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export type Props = $ReadOnly<{
...ViewProps,
}>;
export default (codegenNativeComponent<Props>(
'NativeComponent',
): HostComponent<Props>);
@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-unused-vars */
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type SimpleObject = {||};
type BeforeMismatchGeneric<T> = {||};
type BeforeMatchingGeneric<T> = {||};
type AfterMatchingGeneric<T> = {||};
export interface Spec extends TurboModule {
+simpleObject: (a: SimpleObject) => void;
+beforeMismatchGeneric: <T>(a: BeforeMismatchGeneric<T>) => void;
+beforeMatchingGeneric: <T>(a: BeforeMatchingGeneric<T>) => void;
+afterMatchingGeneric: <T>(a: AfterMatchingGeneric<T>) => void;
}
(TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,73 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-unused-vars */
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type SimpleObject = {||};
type BeforeMismatchGeneric<T> = {||};
type AfterMismatchGeneric<Foo> = {||};
type BeforeMatchingGeneric<T> = {||};
type AfterMatchingGeneric<T> = {||};
type BooleanType = boolean;
type StringType = string;
type SimpleFunction = (a: string) => string;
type SimpleFunction2 = (a: string) => number;
type SimpleFunction3 = (foo: string) => string;
type SimpleFunction4 = (a: number) => string;
type SimpleUnion = 'str1' | 'str2';
type SimpleUnionLonger = 'str1' | 'str2' | 'str3';
type SimpleUnion2 = 4 | 5;
type SimpleUnion3 = {} | {key: 'value'};
type SimpleUnion4 = BooleanType | StringType | SimpleObject;
type FunctionReferencingUnion = (a: SimpleUnion) => void;
type FunctionReferencingUnion2 = (a: SimpleUnion2) => void;
type SimpleArray = Array<string>;
// changed from Array<number> to Array<string>
type SimpleArrayChange = Array<string>;
export interface Spec extends TurboModule {
+exampleFunction: (a: SimpleObject) => void;
+simpleObject: (a: SimpleObject) => void;
+beforeMismatchGeneric: <T>(a: BeforeMismatchGeneric<T>) => void;
+afterMismatchGeneric: <Foo>(a: AfterMismatchGeneric<Foo>) => void;
+beforeMatchingGeneric: <T>(a: BeforeMatchingGeneric<T>) => void;
+afterMatchingGeneric: <T>(a: AfterMatchingGeneric<T>) => void;
+booleanType: (a: BooleanType) => void;
+stringType: (a: StringType) => void;
+simpleFunction: (a: string) => string;
+simpleFunction2: (a: string) => number;
+simpleFunction3: (foo: string) => string;
+simpleFunction4: (a: number) => string;
+simpleUnion: (a: SimpleUnion) => void;
+simpleUnionLonger: (a: SimpleUnionLonger) => void;
+simpleUnion2: (a: SimpleUnion2) => void;
+simpleUnion3: (a: SimpleUnion3) => void;
+simpleUnion4: (a: SimpleUnion4) => void;
+simpleArray: (a: SimpleArray) => void;
+simpleArrayChange: (a: SimpleArrayChange) => void;
}
(TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,66 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-unused-vars */
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type SimpleObject = {};
type BeforeMismatchGeneric<T> = {};
type AfterMismatchGeneric<Foo> = {};
type BeforeMatchingGeneric<T> = {};
type AfterMatchingGeneric<T> = {};
type BooleanType = boolean;
type StringType = string;
type SimpleUnion = 'str1' | 'str2';
type SimpleUnionLonger = 'str1' | 'str2' | 'str3';
type SimpleUnion2 = 4 | 5;
type SimpleUnion3 = {} | {key: 'value'};
type SimpleUnion4 = BooleanType | StringType | SimpleObject;
type SimpleArray = Array<string>;
type SimpleArrayChange = Array<number>;
export interface Spec extends TurboModule {
+exampleFunction: (a: SimpleObject) => void;
+simpleObject: (a: SimpleObject) => void;
+beforeMismatchGeneric: <T>(a: BeforeMismatchGeneric<T>) => void;
+afterMismatchGeneric: <Foo>(a: AfterMismatchGeneric<Foo>) => void;
+beforeMatchingGeneric: <T>(a: BeforeMatchingGeneric<T>) => void;
+afterMatchingGeneric: <T>(a: AfterMatchingGeneric<T>) => void;
+booleanType: (a: BooleanType) => void;
+stringType: (a: StringType) => void;
+simpleFunction: (a: string) => string;
+simpleFunction2: (a: string) => number;
+simpleFunction3: (foo: string) => string;
+simpleFunction4: (a: number) => string;
+simpleUnion: (a: SimpleUnion) => void;
+simpleUnionLonger: (a: SimpleUnionLonger) => void;
+simpleUnion2: (a: SimpleUnion2) => void;
+simpleUnion3: (a: SimpleUnion3) => void;
+simpleUnion4: (a: SimpleUnion4) => void;
+simpleArray: (a: SimpleArray) => void;
+simpleArrayChange: (a: SimpleArrayChange) => void;
}
(TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => $ReadOnly<{
constant?: string,
}>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+constant?: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => $ReadOnly<{
constant: string,
}>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+constant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => $ReadOnly<{}>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,23 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type MyType = () => Promise<number>;
export interface Spec extends TurboModule {
+exampleFunction: (a: MyType, b: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,23 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type MyType = () => Promise<string>;
export interface Spec extends TurboModule {
+exampleFunction: (a: MyType, b: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,32 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (
a: {
a1: string,
a2: number,
a3: string,
...
},
b: number,
) => void;
+getConstants: () => {
+exampleConstant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,32 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (
a: ?{
a1: string,
a2?: number,
a3: string,
...
},
b: number,
) => void;
+getConstants: () => {
+exampleConstant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,32 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (
a: {
a1: string,
a2?: number,
a3: string,
...
},
b: number,
) => void;
+getConstants: () => {
+exampleConstant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (
a: {
a1: string,
a2: number,
...
},
b: number,
) => void;
+getConstants: () => {
+exampleConstant: string,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,218 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/* eslint-disable no-unused-vars */
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import type {UnsafeObject} from 'react-native/Libraries/Types/CodegenTypes';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type StringLiteral0 = 'foo';
type StringLiteral1 = 'bar';
type NumericLiteral0 = 1;
type NumericLiteral1 = 2;
type StringLiteralUnion0 = 'a' | 'b' | 'c';
type StringLiteralUnion1 = 'a' | 'b' | 'c' | 'd';
type StringLiteralUnion2 = 'a' | 'x' | 'c';
type Tuple0 = [string, number];
type Tuple1 = [string, number, number];
type Tuple2 = [number, number];
type ReferencedType = {...};
type ReferencedType2 = {...};
type ReferencedType3 = {prop0: string, ...};
type ReferenceType = ReferencedType;
type ReferenceType2 = ReferencedType2;
type ReferenceType3 = ReferencedType3;
type ReferenceGeneric<T> = ReferencedType;
type ReferenceGeneric2<T, X> = ReferencedType;
type ObjectTypeWithProps = {
prop1: string,
prop2: number,
prop3: boolean,
...
};
type ObjectTypeLessProps = {
prop1: string,
prop3: boolean,
...
};
type ObjectTypeWithDifferentProps = {
prop0: string,
prop4: number,
prop5: boolean,
...
};
type ObjectTypeWithNesting = {
prop1: {
subprop1: string,
subprop2: number,
...
},
prop2: number,
...
};
type ObjectTypeWithChanges = {
prop1: number,
prop2: {
subprop1: string,
subprp2: number,
...
},
...
};
type ObjectTypeWithNestedChanges = {
prop1: {
subprop1: string,
subprop2: string,
...
},
prop2: number,
...
};
type ObjectTypeWithTwoOptionals = {
prop1?: string,
prop2: number,
prop3?: boolean,
...
};
type ObjectTypeWithOptionalNestedChange = {
prop1?: {
subprop1: string,
subprop2: number,
subprop3: string,
...
},
prop2: number,
...
};
type NonNullableType = Object;
type NullableType = ?Object;
type GenericObjectType = Object;
type UnsafeObjectType = UnsafeObject;
type OptionalTypeLessProps = ?{
prop1: string,
prop3: boolean,
...
};
type ObjectTypeLiteral1 = {
prop1: number,
prop2: {
subprop1: string,
subprp2: number,
},
};
type ObjectTypeLiteral2 = {
prop1: number,
prop2: {
subprop1: string,
subprp2: number,
},
};
type ObjectTypeLiteral1TypeAlias = ObjectTypeLiteral1;
type ObjectTypeLiteral2TypeAlias = ObjectTypeLiteral2;
type MapWithKey = {[a: string]: ?number};
type MapWithKey2 = {[a: string]: ?string};
enum Enum {
A = 1,
B = 2,
C = 3,
D = 4,
}
enum EnumWithTypeChange {
A = '1',
B = '2',
C = '3',
D = '4',
}
enum EnumWithRemoval {
A = 1,
B = 2,
C = 3,
}
enum EnumWithValueChange {
A = 1,
B = 2,
C = 3,
D = 14,
}
enum EnumUnsorted {
C = 3,
D = 4,
B = 2,
A = 1,
}
export interface Spec extends TurboModule {
+stringLiteral0: (a: StringLiteral0) => void;
+stringLiteral1: (a: StringLiteral1) => void;
+numericLiteral0: (a: NumericLiteral0) => void;
+numericLiteral1: (a: NumericLiteral1) => void;
+stringLiteralUnion0: (a: StringLiteralUnion0) => void;
+stringLiteralUnion1: (a: StringLiteralUnion1) => void;
+stringLiteralUnion2: (a: StringLiteralUnion2) => void;
+referenceType: (a: ReferenceType) => void;
+referenceType2: (a: ReferenceType2) => void;
+referenceType3: (a: ReferenceType3) => void;
+referenceGeneric: <T>(a: ReferenceGeneric<T>) => void;
+referenceGeneric2: <T, X>(a: ReferenceGeneric2<T, X>) => void;
+objectTypeWithProps: (a: ObjectTypeWithProps) => void;
+objectTypeLessProps: (a: ObjectTypeLessProps) => void;
+objectTypeWithDifferentProps: (a: ObjectTypeWithDifferentProps) => void;
+objectTypeWithNesting: (a: ObjectTypeWithNesting) => void;
+objectTypeWithChanges: (a: ObjectTypeWithChanges) => void;
+objectTypeWithNestedChanges: (a: ObjectTypeWithNestedChanges) => void;
+objectTypeWithTwoOptionals: (a: ObjectTypeWithTwoOptionals) => void;
+objectTypeWithOptionalNestedChange: (a: ObjectTypeWithOptionalNestedChange) => void;
+nonNullableType: (a: NonNullableType) => void;
+nullableType: (a: NullableType) => void;
+genericObjectType: (a: GenericObjectType) => void;
+unsafeObjectType: (a: UnsafeObjectType) => void;
+optionalTypeLessProps: (a: OptionalTypeLessProps) => void;
+objectTypeLiteral1: (a: ObjectTypeLiteral1) => void;
+objectTypeLiteral2: (a: ObjectTypeLiteral2) => void;
+objectTypeLiteral1TypeAlias: (a: ObjectTypeLiteral1TypeAlias) => void;
+objectTypeLiteral2TypeAlias: (a: ObjectTypeLiteral2TypeAlias) => void;
+genericObjectType: (a: Object) => void;
+mapWithKey: (a: MapWithKey) => void;
+mapWithKey2: (a: MapWithKey2) => void;
+enum: (a: Enum) => void;
+enumWithTypeChange: (a: EnumWithTypeChange) => void;
+enumWithRemoval: (a: EnumWithRemoval) => void;
+enumWithValueChange: (a: EnumWithValueChange) => void;
+enumUnsorted: (a: EnumUnsorted) => void;
}
(TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: {[key: string]: string}, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: {[key: string]: number}, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 2,
C = 3,
D = 4,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: TestEnum, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 2,
C = 3,
D = 4,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: TestEnum,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = '1',
B = '2',
C = '3',
}
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: TestEnum,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 13,
C = 3,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: TestEnum,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 2,
C = 3,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: TestEnum,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = '1',
B = '2',
C = '3',
D = '4',
}
export interface Spec extends TurboModule {
+exampleFunction: (a: TestEnum, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 13,
C = 3,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: TestEnum, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
enum TestEnum {
A = 1,
B = 2,
C = 3,
}
export interface Spec extends TurboModule {
+exampleFunction: (a: TestEnum, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import type {EventEmitter} from 'react-native/Libraries/Types/CodegenTypes';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export type ObjectStruct = {
a: number,
b: string,
c?: ?string,
};
export interface Spec extends TurboModule {
onPress: EventEmitter<string>;
onClick: EventEmitter<number>;
onChange: EventEmitter<ObjectStruct[]>;
onSubmit: EventEmitter<ObjectStruct>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import type {EventEmitter} from 'react-native/Libraries/Types/CodegenTypes';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export type ObjectStruct = {
a: number,
b: string,
c?: ?string,
};
export interface Spec extends TurboModule {
onPress: EventEmitter<void>;
onClick: EventEmitter<string>;
onChange: EventEmitter<ObjectStruct>;
onSubmit: EventEmitter<ObjectStruct[]>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number, c?: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 'a' | 'b' | 'c' | 'd';
export interface Spec extends TurboModule {
+exampleFunction: (a: testUnion, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 'a' | '0' | '1' | 'a long string';
export interface Spec extends TurboModule {
+exampleFunction: (a: testUnion, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 'a' | 'b' | 'c' | 'd';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: testUnion,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 'a' | 'b' | 'c';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: testUnion,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 1 | 2 | 3;
export interface Spec extends TurboModule {
+exampleFunction: (a: testUnion, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
type testUnion = 'a' | 'b' | 'c';
export interface Spec extends TurboModule {
+exampleFunction: (a: testUnion, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+exampleFunction: (a: string, b: number) => void;
+getConstants: () => {
+exampleConstant: number,
};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'NativeModuleTest',
): Spec);
@@ -0,0 +1,792 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`codegen formattedSummarizeDiffSet allows a diff from native-component-with-command/NativeComponent to native-component-with-command/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet allows a diff from native-component-with-props-default-change/NativeComponent to native-component-with-props/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet allows a diff from native-module-before-after-types/NativeModuleBeforeAfterTypes to native-module-before-after-types-removed/NativeModuleBeforeAfterTypes 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet allows a diff from native-module-get-constants-added-optional-constant/NativeModule to native-module-get-constants/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet allows a diff from native-module-with-enum-from-native/NativeModule to native-module-with-enum-from-native-changes/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet allows a diff from native-module-with-union-changes/NativeModule to native-module-with-union/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {},
"status": "ok",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-command/NativeComponent to native-component-with-command-extra-arg/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodInt: has conflicting type changes
--new: (a: int, b: string)=>void
--old: (a: int)=>void
Function types have differing length of arguments
--new: (a: int, b: string)=>void
--old: (a: int)=>void",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-command-all-basic-types/NativeComponent to native-component-with-command-all-basic-types-arrays/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodInt: has conflicting type changes
--new: (a: Array<int>)=>void
--old: (a: int)=>void
Parameter at index 0 did not match
--new: (a: Array<int>)=>void
--old: (a: int)=>void
Type annotations are not the same.
--new: Array<int>
--old: int",
},
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodString: has conflicting type changes
--new: (a: Array<string>)=>void
--old: (a: string)=>void
Parameter at index 0 did not match
--new: (a: Array<string>)=>void
--old: (a: string)=>void
Type annotations are not the same.
--new: Array<string>
--old: string",
},
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodBool: has conflicting type changes
--new: (a: Array<boolean>)=>void
--old: (a: boolean)=>void
Parameter at index 0 did not match
--new: (a: Array<boolean>)=>void
--old: (a: boolean)=>void
Type annotations are not the same.
--new: Array<boolean>
--old: boolean",
},
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodFloat: has conflicting type changes
--new: (a: Array<float>)=>void
--old: (a: float)=>void
Parameter at index 0 did not match
--new: (a: Array<float>)=>void
--old: (a: float)=>void
Type annotations are not the same.
--new: Array<float>
--old: float",
},
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodDouble: has conflicting type changes
--new: (a: Array<double>)=>void
--old: (a: double)=>void
Parameter at index 0 did not match
--new: (a: Array<double>)=>void
--old: (a: double)=>void
Type annotations are not the same.
--new: Array<double>
--old: double",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-command-changed/NativeComponent to native-component-with-command/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- methodInt: has conflicting type changes
--new: (a: int)=>void
--old: (a: string)=>void
Parameter at index 0 did not match
--new: (a: int)=>void
--old: (a: string)=>void
Type annotations are not the same.
--new: int
--old: string",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-props-added-required-prop/NativeComponent to native-component-with-props/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "removedProps",
"message": "NativeComponent: Object removed required properties expected by native
-- width",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-props-array-union/NativeComponent to native-component-with-props-array-union-added/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "addedUnionCases",
"message": "NativeComponent.sizes: Union added items, but native will not expect/support them
-- position 3 huge",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-props-changes/NativeComponent to native-component-with-props/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeComponent: Object contained a property with a type mismatch
-- text: has conflicting type changes
--new: string
--old: int
Type annotations are not the same.
--new: string
--old: int",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-component-with-props-union/NativeComponent to native-component-with-props-union-added/NativeComponent 1`] = `
Object {
"incompatibilityReport": Object {
"NativeComponent": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "addedUnionCases",
"message": "NativeComponent.size: Union added items, but native will not expect/support them
-- position 3 huge",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-before-after-types-removed/NativeModuleBeforeAfterTypes to native-module-before-after-types/NativeModuleBeforeAfterTypes 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModuleBeforeAfterTypes": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "addedProps",
"message": "NativeModuleTest: Object added required properties, which native will not provide
-- afterMismatchGeneric
-- booleanType
-- exampleFunction
-- simpleArray
-- simpleArrayChange
-- simpleFunction
-- simpleFunction2
-- simpleFunction3
-- simpleFunction4
-- simpleUnion
-- simpleUnion2
-- simpleUnion3
-- simpleUnion4
-- simpleUnionLonger
-- stringType",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-before-after-types-type-changed/NativeModuleBeforeAfterTypes to native-module-before-after-types/NativeModuleBeforeAfterTypes 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModuleBeforeAfterTypes": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- simpleArrayChange: has conflicting type changes
--new: (a: Array<number>)=>void
--old: (a: Array<string>)=>void
Parameter at index 0 did not match
--new: (a: Array<number>)=>void
--old: (a: Array<string>)=>void
Type annotations are not the same.
--new: number
--old: string",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-changed/NativeModule to native-module/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- getConstants: has conflicting type changes
--new: ()=>{exampleConstant: number}
--old: ()=>{exampleConstant: string}
Function return types do not match
--new: ()=>{exampleConstant: number}
--old: ()=>{exampleConstant: string}
Object contained a property with a type mismatch
-- exampleConstant: has conflicting type changes
--new: number
--old: string
Type annotations are not the same.
--new: number
--old: string",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-nested/NativeModule to native-module-nested-optional/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "optionalProps",
"message": "NativeModuleTest.exampleFunction parameter 0: Property made optional, but native requires it
-- a2",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-nested-alias-changed/NativeModule to native-module-nested-alias/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: ()=>Promise<string>, b: number)=>void
--old: (a: ()=>Promise<number>, b: number)=>void
Parameter at index 0 did not match
--new: (a: ()=>Promise<string>, b: number)=>void
--old: (a: ()=>Promise<number>, b: number)=>void
Function return types do not match
--new: ()=>Promise<string>
--old: ()=>Promise<number>
Type annotations are not the same.
--new: string
--old: number",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-nested-changed/NativeModule to native-module-nested/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "removedProps",
"message": "NativeModuleTest.exampleFunction parameter 0: Object removed required properties expected by native
-- a3",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-nested-changed/NativeModule to native-module-nested-optional/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "optionalProps",
"message": "NativeModuleTest.exampleFunction parameter 0: Property made optional, but native requires it
-- a2",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-nested-optional/NativeModule to native-module-nested-nullable/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "nullableOfNonNull",
"message": "NativeModuleTest.exampleFunction parameter 0: Type made nullable, but native requires it
--new: ?{a1: string, a2?: number, a3: string}
--old: {a1: string, a2?: number, a3: string}",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-dictionary-changed/NativeModule to native-module-with-dictionary/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: {[string]: number, b: number)=>void
--old: (a: {[string]: string, b: number)=>void
Parameter at index 0 did not match
--new: (a: {[string]: number, b: number)=>void
--old: (a: {[string]: string, b: number)=>void
Type annotations are not the same.
--new: number
--old: string",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum/NativeModule to native-module-with-enum-changes/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "addedEnumCases",
"message": "NativeModuleTest.exampleFunction parameter 0: Enum added items, but native will not expect/support them
-- Member D",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum-from-native-changes/NativeModule to native-module-with-enum-from-native/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "removedEnumCases",
"message": "NativeModuleTest.getConstants.exampleConstant: Enum removed items, but native may still provide them
-- Member D",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum-from-native-type-changes/NativeModule to native-module-with-enum-from-native/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- getConstants: has conflicting type changes
--new: ()=>{exampleConstant: Enum<number>}
--old: ()=>{exampleConstant: Enum<string>}
Function return types do not match
--new: ()=>{exampleConstant: Enum<number>}
--old: ()=>{exampleConstant: Enum<string>}
Object contained a property with a type mismatch
-- exampleConstant: has conflicting type changes
--new: Enum<number>
--old: Enum<string>
EnumDeclaration member types are not the same
--new: Enum<number>
--old: Enum<string>",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum-from-native-value-changes/NativeModule to native-module-with-enum-from-native/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- getConstants: has conflicting type changes
--new: ()=>{exampleConstant: Enum<number>}
--old: ()=>{exampleConstant: Enum<number>}
Function return types do not match
--new: ()=>{exampleConstant: Enum<number>}
--old: ()=>{exampleConstant: Enum<number>}
Object contained a property with a type mismatch
-- exampleConstant: has conflicting type changes
--new: Enum<number>
--old: Enum<number>
Enum types do not match
--new: Enum<number> {A = 1, B = 2, C = 3}
--old: Enum<number> {A = 1, B = 13, C = 3}
Enum contained a member with a type mismatch
-- Member B: has conflicting changes
--new: 2
--old: 13
Numeric literals are not equal
--new: 2
--old: 13",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum-type-changes/NativeModule to native-module-with-enum/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: Enum<number>, b: number)=>void
--old: (a: Enum<string>, b: number)=>void
Parameter at index 0 did not match
--new: (a: Enum<number>, b: number)=>void
--old: (a: Enum<string>, b: number)=>void
EnumDeclaration member types are not the same
--new: Enum<number>
--old: Enum<string>",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-enum-value-changes/NativeModule to native-module-with-enum/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: Enum<number>, b: number)=>void
--old: (a: Enum<number>, b: number)=>void
Parameter at index 0 did not match
--new: (a: Enum<number>, b: number)=>void
--old: (a: Enum<number>, b: number)=>void
Enum types do not match
--new: Enum<number> {A = 1, B = 2, C = 3}
--old: Enum<number> {A = 1, B = 13, C = 3}
Enum contained a member with a type mismatch
-- Member B: has conflicting changes
--new: 2
--old: 13
Numeric literals are not equal
--new: 2
--old: 13",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-eventemitter-changes/NativeModule to native-module-with-eventemitter/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained properties with type mismatches
-- onChange: has conflicting type changes
--new: EventEmitter<ObjectStruct>
--old: EventEmitter<Array<ObjectStruct>>
EventEmitter eventTypes are not equivalent
--new: EventEmitter<ObjectStruct>
--old: EventEmitter<Array<ObjectStruct>>
Type annotations are not the same.
--new: {a: number, b: string, c?: ?string}
--old: Array<ObjectStruct>
-- onClick: has conflicting type changes
--new: EventEmitter<string>
--old: EventEmitter<number>
EventEmitter eventTypes are not equivalent
--new: EventEmitter<string>
--old: EventEmitter<number>
Type annotations are not the same.
--new: string
--old: number
-- onPress: has conflicting type changes
--new: EventEmitter<void>
--old: EventEmitter<string>
EventEmitter eventTypes are not equivalent
--new: EventEmitter<void>
--old: EventEmitter<string>
Type annotations are not the same.
--new: void
--old: string
-- onSubmit: has conflicting type changes
--new: EventEmitter<Array<ObjectStruct>>
--old: EventEmitter<ObjectStruct>
EventEmitter eventTypes are not equivalent
--new: EventEmitter<Array<ObjectStruct>>
--old: EventEmitter<ObjectStruct>
Type annotations are not the same.
--new: Array<ObjectStruct>
--old: {a: number, b: string, c?: ?string}",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-optional-argument/NativeModule to native-module/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: string, b: number)=>void
--old: (a: string, b: number, c?: number)=>void
Function types have differing length of arguments
--new: (a: string, b: number)=>void
--old: (a: string, b: number, c?: number)=>void",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-union/NativeModule to native-module-with-union-changes/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "addedUnionCases",
"message": "NativeModuleTest.exampleFunction parameter 0: Union added items, but native will not expect/support them
-- position 4 d",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-union-confusing-string-literals/NativeModule to native-module-with-union/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: (a | b | c), b: number)=>void
--old: (a: (a | '0' | '1' | 'a long string'), b: number)=>void
Parameter at index 0 did not match
--new: (a: (a | b | c), b: number)=>void
--old: (a: (a | '0' | '1' | 'a long string'), b: number)=>void
Subtype of union at position 1 did not match
--new: (a | b | c)
--old: (a | '0' | '1' | 'a long string')
String literals are not equal
--new: b
--old: '0'",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-union-from-native-changes/NativeModule to native-module-with-union-from-native/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "removedUnionCases",
"message": "NativeModuleTest.getConstants.exampleConstant: Union removed items, but native may still provide them
-- position 4 d",
},
],
},
},
"status": "incompatible",
}
`;
exports[`codegen formattedSummarizeDiffSet reports a diff from native-module-with-union-type-changes/NativeModule to native-module-with-union/NativeModule 1`] = `
Object {
"incompatibilityReport": Object {
"NativeModule": Object {
"framework": "ReactNative",
"incompatibleSpecs": Array [
Object {
"errorCode": "incompatibleTypes",
"message": "NativeModuleTest: Object contained a property with a type mismatch
-- exampleFunction: has conflicting type changes
--new: (a: (a | b | c), b: number)=>void
--old: (a: Union<number>, b: number)=>void
Parameter at index 0 did not match
--new: (a: (a | b | c), b: number)=>void
--old: (a: Union<number>, b: number)=>void
Type annotations are not the same.
--new: (a | b | c)
--old: Union<number>",
},
],
},
},
"status": "incompatible",
}
`;
@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
* @oncall react_native
*/
import type {SchemaType} from '@react-native/codegen/src/CodegenSchema';
import {FlowParser} from '@react-native/codegen/src/parsers/flow/parser';
import path from 'path';
const flowParser = new FlowParser();
export function getTestSchema(
...filenameComponents: Array<string>
): SchemaType {
const filename = path.join(...filenameComponents);
const schema = flowParser.parseFile(filename);
return schema;
}
@@ -0,0 +1,104 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {
ArrayTypeAnnotation,
CompleteTypeAnnotation,
ComponentArrayTypeAnnotation,
ObjectTypeAnnotation,
PropTypeAnnotation,
} from '@react-native/codegen/src/CodegenSchema';
export default function convertPropToBasicTypes(
inputType: PropTypeAnnotation | ComponentArrayTypeAnnotation['elementType'],
): CompleteTypeAnnotation {
let resultingType: CompleteTypeAnnotation;
switch (inputType.type) {
case 'BooleanTypeAnnotation':
resultingType = {
type: 'BooleanTypeAnnotation',
};
break;
case 'StringTypeAnnotation':
resultingType = {
type: 'StringTypeAnnotation',
};
break;
case 'DoubleTypeAnnotation':
resultingType = {
type: 'DoubleTypeAnnotation',
};
break;
case 'FloatTypeAnnotation':
resultingType = {
type: 'FloatTypeAnnotation',
};
break;
case 'Int32TypeAnnotation':
resultingType = {
type: 'Int32TypeAnnotation',
};
break;
case 'StringEnumTypeAnnotation':
resultingType = {
type: 'StringLiteralUnionTypeAnnotation',
types: inputType.options.map(option => {
return {
type: 'StringLiteralTypeAnnotation',
value: option,
};
}),
};
break;
case 'Int32EnumTypeAnnotation':
// Compat check doesn't yet have support for
// NumberLiteralUnionTypeAnnotation
resultingType = {
type: 'AnyTypeAnnotation',
};
break;
case 'ReservedPropTypeAnnotation':
resultingType = {
type: 'ReservedTypeAnnotation',
name: inputType.name,
};
break;
case 'MixedTypeAnnotation':
resultingType = inputType;
break;
case 'ObjectTypeAnnotation':
resultingType = ({
type: 'ObjectTypeAnnotation',
...(inputType.baseTypes != null
? {baseTypes: inputType.baseTypes}
: {}),
properties: inputType.properties.map(property => ({
name: property.name,
optional: property.optional,
typeAnnotation: convertPropToBasicTypes(property.typeAnnotation),
})),
}: ObjectTypeAnnotation<CompleteTypeAnnotation>);
break;
case 'ArrayTypeAnnotation':
resultingType = ({
type: 'ArrayTypeAnnotation',
elementType: convertPropToBasicTypes(inputType.elementType),
}: ArrayTypeAnnotation<CompleteTypeAnnotation>);
break;
default:
(inputType.type: empty);
throw new Error('Unexpected type ' + inputType.type);
}
return resultingType;
}
@@ -0,0 +1,12 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
export {compareSchemas} from './index.js';
+54
View File
@@ -0,0 +1,54 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {
DiffSummary,
ExportableSchemaDiff,
FormattedDiffSummary,
SchemaDiff,
} from './DiffResults';
import type {SchemaType} from '@react-native/codegen/src/CodegenSchema';
import {schemaDiffExporter} from './DiffResults.js';
import {formatDiffSet} from './ErrorFormatting.js';
import {buildSchemaDiff, summarizeDiffSet} from './VersionDiffing.js';
class CompatCheckResult {
#schemaDiff: Set<SchemaDiff>;
#summary: ?DiffSummary;
constructor(schemaDiff: Set<SchemaDiff>) {
this.#schemaDiff = schemaDiff;
}
getSummary(): DiffSummary {
if (this.#summary == null) {
this.#summary = summarizeDiffSet(this.#schemaDiff);
}
return this.#summary;
}
getErrors(): FormattedDiffSummary {
return formatDiffSet(this.getSummary());
}
getDebugInfo(): Array<ExportableSchemaDiff> {
return Array.from(this.#schemaDiff, schemaDiffExporter);
}
}
export function compareSchemas(
newSchema: SchemaType,
oldSchema: SchemaType,
): CompatCheckResult {
return new CompatCheckResult(buildSchemaDiff(newSchema, oldSchema));
}
+4
View File
@@ -54,6 +54,10 @@ const buildConfig: BuildConfig = {
emitTypeScriptDefs: true,
target: 'node',
},
'react-native-compatibility-check': {
emitTypeScriptDefs: true,
target: 'node',
},
},
};
+26
View File
@@ -4438,6 +4438,15 @@ flow-parser@0.*:
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.245.0.tgz#d8ad7e706d280ce6d4189a206768c32f552b5099"
integrity sha512-xUBkkpIDfDZHAebnDEX65FCVitJUctab82KFmtP5SY4cGly1vbuYNe6Muyp0NLXrgmBChVdoC2T+3/RUHi4Mww==
flow-remove-types@^2.237.2:
version "2.259.1"
resolved "https://registry.yarnpkg.com/flow-remove-types/-/flow-remove-types-2.259.1.tgz#ee78962cbd73d85f0e94183b354c43399903c734"
integrity sha512-H+ww7Q6c4xXFAoZGZnC37FJmA9Zzu3UpQ96q3/geCQiaZiTXmM7ZeN53DYpu4be8cvPEp15K0SZTOtaiGoWU5A==
dependencies:
hermes-parser "0.25.1"
pirates "^3.0.2"
vlq "^0.2.1"
for-each@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@@ -6773,6 +6782,11 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
node-modules-regexp@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
integrity sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ==
node-releases@^2.0.18:
version "2.0.18"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
@@ -7170,6 +7184,13 @@ pinpoint@^1.1.0:
resolved "https://registry.yarnpkg.com/pinpoint/-/pinpoint-1.1.0.tgz#0cf7757a6977f1bf7f6a32207b709e377388e874"
integrity sha512-+04FTD9x7Cls2rihLlo57QDCcHoLBGn5Dk51SwtFBWkUWLxZaBXyNVpCw1S+atvE7GmnFjeaRZ0WLq3UYuqAdg==
pirates@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-3.0.2.tgz#7e6f85413fd9161ab4e12b539b06010d85954bb9"
integrity sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q==
dependencies:
node-modules-regexp "^1.0.0"
pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5, pirates@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
@@ -8744,6 +8765,11 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vlq@^0.2.1:
version "0.2.3"
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
vlq@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468"