@react-native/compatibility-check 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -1
- package/dist/ComparisonResult.d.ts +135 -0
- package/dist/ComparisonResult.js +88 -0
- package/dist/ComparisonResult.js.flow +188 -0
- package/dist/DiffResults.d.ts +137 -0
- package/dist/DiffResults.js +52 -0
- package/dist/DiffResults.js.flow +160 -0
- package/dist/ErrorFormatting.d.ts +31 -0
- package/dist/ErrorFormatting.js +272 -0
- package/dist/ErrorFormatting.js.flow +34 -0
- package/dist/SortTypeAnnotations.d.ts +18 -0
- package/dist/SortTypeAnnotations.js +300 -0
- package/dist/SortTypeAnnotations.js.flow +20 -0
- package/dist/TypeDiffing.d.ts +86 -0
- package/dist/TypeDiffing.js +1253 -0
- package/dist/TypeDiffing.js.flow +99 -0
- package/dist/VersionDiffing.d.ts +59 -0
- package/dist/VersionDiffing.js +1235 -0
- package/dist/VersionDiffing.js.flow +71 -0
- package/dist/convertPropToBasicTypes.d.ts +20 -0
- package/dist/convertPropToBasicTypes.js +86 -0
- package/dist/convertPropToBasicTypes.js.flow +20 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/index.js.flow +12 -0
- package/package.json +31 -3
package/README.md
CHANGED
|
@@ -1 +1,245 @@
|
|
|
1
|
-
|
|
1
|
+
# **React Native compatibility-check**
|
|
2
|
+
|
|
3
|
+
Status: Experimental (stage 1)
|
|
4
|
+
|
|
5
|
+
Work In Progress. Documentation is lacking, and intended to be used by power
|
|
6
|
+
users at this point.
|
|
7
|
+
|
|
8
|
+
This tool enables checking the boundary between JavaScript and Native for
|
|
9
|
+
backwards incompatible changes to protect against crashes.
|
|
10
|
+
|
|
11
|
+
This is useful for:
|
|
12
|
+
|
|
13
|
+
- Local Development
|
|
14
|
+
- Over the Air updates on platforms that support it
|
|
15
|
+
- Theoretically: Server Components with React Native
|
|
16
|
+
|
|
17
|
+
## **Motivating Problems**
|
|
18
|
+
|
|
19
|
+
Let’s look at some motivating examples for this project.
|
|
20
|
+
|
|
21
|
+
> [!NOTE]
|
|
22
|
+
> The examples below are written with Flow, but the compatibility-check
|
|
23
|
+
> tool is agnostic to the types you write. The compatibility-check runs on JSON
|
|
24
|
+
> schema files, most commonly generated by the
|
|
25
|
+
> [@react-native/codegen](https://www.npmjs.com/package/@react-native/codegen)
|
|
26
|
+
> tool which supports both TypeScript and Flow.
|
|
27
|
+
|
|
28
|
+
### **Adding new methods**
|
|
29
|
+
|
|
30
|
+
You might have an Analytics Native Module in your app, and you last built the
|
|
31
|
+
native client a couple of days ago:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
export interface Spec extends TurboModule {
|
|
35
|
+
log: (eventName: string, content: string) => void;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
And you are working on a change to add a new method to this Native Module:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
export interface Spec extends TurboModule {
|
|
43
|
+
log: (eventName: string, content: string) => void;
|
|
44
|
+
logError: (message: string) => void;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
NativeAnalytics.logError('Oh No! We hit a crash')
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Since you are working on this, you’ve built a new native client and tested the
|
|
53
|
+
change on your computer and everything works.
|
|
54
|
+
|
|
55
|
+
However, when your colleague pulls your latest changes and tries to run it,
|
|
56
|
+
they’ll get a crash `logError is not a function`. They need to rebuild their
|
|
57
|
+
native client\!
|
|
58
|
+
|
|
59
|
+
Using this tool, you can detect this incompatibility at build time, getting an
|
|
60
|
+
error that looks like:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
NativeAnalytics: Object added required properties, which native will not provide
|
|
64
|
+
-- logError
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Errors like this can occur for much more nuanced reasons than adding a method.
|
|
68
|
+
For example:
|
|
69
|
+
|
|
70
|
+
### **Sending native new union values**
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
export interface Spec extends TurboModule {
|
|
74
|
+
// You add 'system' to this union
|
|
75
|
+
+setColorScheme: (color: 'light' | 'dark') => void;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
If you add a new option of `system` and add native support for that option, when
|
|
80
|
+
you call this method with `system` on your commit it would work but on an older
|
|
81
|
+
build not expecting `system` it will crash. This tool will give you the error
|
|
82
|
+
message:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
ColorManager.setColorScheme parameter 0: Union added items, but native will not expect/support them
|
|
86
|
+
-- position 3 system
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### **Changing an enum value sent from native**
|
|
90
|
+
|
|
91
|
+
As another example, say you are getting the color scheme from the system as an
|
|
92
|
+
integer value, used in JavaScript as an enum:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
enum TestEnum {
|
|
96
|
+
LIGHT = 1,
|
|
97
|
+
DARK = 2,
|
|
98
|
+
SYSTEM = 3,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface Spec extends TurboModule {
|
|
102
|
+
getColorScheme: () => TestEnum;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
And you realize you actually need native to send `-1` for System instead of 3\.
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
enum TestEnum {
|
|
110
|
+
LIGHT = 1,
|
|
111
|
+
DARK = 2,
|
|
112
|
+
SYSTEM = -1,
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If you make this change and run the JavaScript on an old build, it might still
|
|
117
|
+
send JavaScript the value 3, which your JavaScript isn’t handling anymore\!
|
|
118
|
+
|
|
119
|
+
This tool gives an error:
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
ColorManager: Object contained a property with a type mismatch
|
|
123
|
+
-- getColorScheme: has conflicting type changes
|
|
124
|
+
--new: ()=>Enum<number>
|
|
125
|
+
--old: ()=>Enum<number>
|
|
126
|
+
Function return types do not match
|
|
127
|
+
--new: ()=>Enum<number>
|
|
128
|
+
--old: ()=>Enum<number>
|
|
129
|
+
Enum types do not match
|
|
130
|
+
--new: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = -1}
|
|
131
|
+
--old: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = 3}
|
|
132
|
+
Enum contained a member with a type mismatch
|
|
133
|
+
-- Member SYSTEM: has conflicting changes
|
|
134
|
+
--new: -1
|
|
135
|
+
--old: 3
|
|
136
|
+
Numeric literals are not equal
|
|
137
|
+
--new: -1
|
|
138
|
+
--old: 3
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## **Avoiding Breaking Changes**
|
|
143
|
+
|
|
144
|
+
You can use this tool to either detect changes locally to warn that you need to
|
|
145
|
+
install a new native build, or when doing OTA you might need to guarantee that
|
|
146
|
+
the changes in your PR are compatible with the native client they’ll be running
|
|
147
|
+
in.
|
|
148
|
+
|
|
149
|
+
### **Example 1**
|
|
150
|
+
|
|
151
|
+
In example 1, when adding logError, it needs to be optional to be safe:
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
export interface Spec extends TurboModule {
|
|
155
|
+
log: (eventName: string, content: string) => void;
|
|
156
|
+
logError?: (message: string) => void;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
That will enforce if you are using TypeScript or Flow that you check if the
|
|
161
|
+
native client supports logError before calling it:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
if (NativeAnalytics.logError) {
|
|
165
|
+
NativeAnalytics.logError('Oh No! We hit a crash');
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### **Example 2**
|
|
170
|
+
|
|
171
|
+
When you want to add '`system'` as a value to the union, modifying the existing
|
|
172
|
+
union is not safe. You would need to add a new optional method that has that
|
|
173
|
+
change. You can clean up the old method when you know that all of the builds you
|
|
174
|
+
ever want to run this JavaScript on have native support.
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
export interface Spec extends TurboModule {
|
|
178
|
+
+setColorScheme: (color: 'light' | 'dark') => void
|
|
179
|
+
+setColorSchemeWithSystem?: (color: 'light' | 'dark' | 'system') => void
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### **Example 3**
|
|
184
|
+
|
|
185
|
+
Changing a union case is similar to Example 2, you would either need a new
|
|
186
|
+
method, or support the existing value and the new `-1`.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
enum TestEnum {
|
|
190
|
+
LIGHT = 1,
|
|
191
|
+
DARK = 2,
|
|
192
|
+
SYSTEM = 3,
|
|
193
|
+
SYSTEM_ALSO = -1,
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## **Installation**
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
yarn add @react-native/compatibility-check
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## **Usage**
|
|
204
|
+
|
|
205
|
+
To use this package, you’ll need a script that works something like this:
|
|
206
|
+
|
|
207
|
+
This script checks the compatibility of a React Native app's schema between two
|
|
208
|
+
versions. It takes into account the changes made to the schema and determines
|
|
209
|
+
whether they are compatible or not.
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
import {compareSchemas} from '@react-native/compatibility-check';
|
|
213
|
+
const util = require('util');
|
|
214
|
+
|
|
215
|
+
async function run(argv: Argv, STDERR: string) {
|
|
216
|
+
const debug = (log: mixed) => {
|
|
217
|
+
argv.debug &&
|
|
218
|
+
console.info(util.inspect(log, {showHidden: false, depth: null}));
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const currentSchema =
|
|
222
|
+
JSON.parse(/*you'll read the file generated by codegen wherever it is in your app*/);
|
|
223
|
+
const previousSchema =
|
|
224
|
+
JSON.parse(/*you'll read the schema file that you persisted from when your native app was built*/);
|
|
225
|
+
|
|
226
|
+
const safetyResult = compareSchemas(currentSchema, previousSchema);
|
|
227
|
+
|
|
228
|
+
const summary = safetyResult.getSummary();
|
|
229
|
+
switch (summary.status) {
|
|
230
|
+
case 'ok':
|
|
231
|
+
debug('No changes in boundary');
|
|
232
|
+
console.log(JSON.stringify(summary));
|
|
233
|
+
break;
|
|
234
|
+
case 'patchable':
|
|
235
|
+
debug('Changes in boundary, but are compatible');
|
|
236
|
+
debug(result.getDebugInfo());
|
|
237
|
+
console.log(JSON.stringify(summary));
|
|
238
|
+
break;
|
|
239
|
+
default:
|
|
240
|
+
debug(result.getDebugInfo());
|
|
241
|
+
console.error(JSON.stringify(result.getErrors()));
|
|
242
|
+
throw new Error(`Incompatible changes in boundary`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
CompleteTypeAnnotation,
|
|
13
|
+
NamedShape,
|
|
14
|
+
NativeModuleEnumMember,
|
|
15
|
+
} from "@react-native/codegen/src/CodegenSchema";
|
|
16
|
+
type TypeAnnotationComparisonError = {
|
|
17
|
+
type: "TypeAnnotationComparisonError";
|
|
18
|
+
message: string;
|
|
19
|
+
newerAnnotation: CompleteTypeAnnotation;
|
|
20
|
+
olderAnnotation: CompleteTypeAnnotation;
|
|
21
|
+
previousError?: TypeComparisonError;
|
|
22
|
+
};
|
|
23
|
+
type TypeInformationComparisonError = {
|
|
24
|
+
type: "TypeInformationComparisonError";
|
|
25
|
+
message: string;
|
|
26
|
+
newerType: CompleteTypeAnnotation;
|
|
27
|
+
olderType: CompleteTypeAnnotation;
|
|
28
|
+
previousError?: TypeComparisonError;
|
|
29
|
+
};
|
|
30
|
+
type PropertyComparisonError = {
|
|
31
|
+
type: "PropertyComparisonError";
|
|
32
|
+
message: string;
|
|
33
|
+
mismatchedProperties: Array<{
|
|
34
|
+
property: string;
|
|
35
|
+
fault?: TypeComparisonError;
|
|
36
|
+
}>;
|
|
37
|
+
previousError?: TypeComparisonError;
|
|
38
|
+
};
|
|
39
|
+
type PositionalComparisonError = {
|
|
40
|
+
type: "PositionalComparisonError";
|
|
41
|
+
message: string;
|
|
42
|
+
erroneousItems: Array<[number, CompleteTypeAnnotation]>;
|
|
43
|
+
previousError?: TypeComparisonError;
|
|
44
|
+
};
|
|
45
|
+
type MemberComparisonError = {
|
|
46
|
+
type: "MemberComparisonError";
|
|
47
|
+
message: string;
|
|
48
|
+
mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>;
|
|
49
|
+
previousError?: TypeComparisonError;
|
|
50
|
+
};
|
|
51
|
+
export type TypeComparisonError =
|
|
52
|
+
| TypeAnnotationComparisonError
|
|
53
|
+
| TypeInformationComparisonError
|
|
54
|
+
| PropertyComparisonError
|
|
55
|
+
| PositionalComparisonError
|
|
56
|
+
| MemberComparisonError;
|
|
57
|
+
export type PositionalComparisonResult = {
|
|
58
|
+
typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple";
|
|
59
|
+
nestedChanges: Array<[number, number, ComparisonResult]>;
|
|
60
|
+
addedElements?: Array<[number, CompleteTypeAnnotation]>;
|
|
61
|
+
removedElements?: Array<[number, CompleteTypeAnnotation]>;
|
|
62
|
+
};
|
|
63
|
+
export type FunctionComparisonResult = {
|
|
64
|
+
returnType?: ComparisonResult;
|
|
65
|
+
parameterTypes?: PositionalComparisonResult;
|
|
66
|
+
};
|
|
67
|
+
export type PropertiesComparisonResult = {
|
|
68
|
+
addedProperties?: ReadonlyArray<NamedShape<CompleteTypeAnnotation>>;
|
|
69
|
+
missingProperties?: ReadonlyArray<NamedShape<CompleteTypeAnnotation>>;
|
|
70
|
+
errorProperties?: Array<{ property: string; fault?: TypeComparisonError }>;
|
|
71
|
+
madeStrict?: Array<{ property: string; furtherChanges?: ComparisonResult }>;
|
|
72
|
+
madeOptional?: Array<{ property: string; furtherChanges?: ComparisonResult }>;
|
|
73
|
+
nestedPropertyChanges?: Array<[string, ComparisonResult]>;
|
|
74
|
+
};
|
|
75
|
+
export type MembersComparisonResult = {
|
|
76
|
+
addedMembers?: Array<NativeModuleEnumMember>;
|
|
77
|
+
missingMembers?: Array<NativeModuleEnumMember>;
|
|
78
|
+
errorMembers?: Array<{ member: string; fault?: TypeComparisonError }>;
|
|
79
|
+
};
|
|
80
|
+
export type NullableComparisonResult = {
|
|
81
|
+
typeRefined: boolean;
|
|
82
|
+
optionsReduced: boolean;
|
|
83
|
+
interiorLog: null | undefined | ComparisonResult;
|
|
84
|
+
newType: null | undefined | CompleteTypeAnnotation;
|
|
85
|
+
oldType: null | undefined | CompleteTypeAnnotation;
|
|
86
|
+
};
|
|
87
|
+
export type ComparisonResult =
|
|
88
|
+
| { status: "matching" }
|
|
89
|
+
| { status: "skipped" }
|
|
90
|
+
| { status: "nullableChange"; nullableLog: NullableComparisonResult }
|
|
91
|
+
| { status: "properties"; propertyLog: PropertiesComparisonResult }
|
|
92
|
+
| { status: "members"; memberLog: MembersComparisonResult }
|
|
93
|
+
| { status: "functionChange"; functionChangeLog: FunctionComparisonResult }
|
|
94
|
+
| { status: "positionalTypeChange"; changeLog: PositionalComparisonResult }
|
|
95
|
+
| { status: "error"; errorLog: TypeComparisonError };
|
|
96
|
+
export declare function isPropertyLogEmpty(
|
|
97
|
+
result: PropertiesComparisonResult
|
|
98
|
+
): boolean;
|
|
99
|
+
export declare function isMemberLogEmpty(
|
|
100
|
+
result: MembersComparisonResult
|
|
101
|
+
): boolean;
|
|
102
|
+
export declare function isFunctionLogEmpty(
|
|
103
|
+
result: FunctionComparisonResult
|
|
104
|
+
): boolean;
|
|
105
|
+
export declare function makeError(error: TypeComparisonError): ComparisonResult;
|
|
106
|
+
export declare function typeInformationComparisonError(
|
|
107
|
+
message: string,
|
|
108
|
+
newerType: CompleteTypeAnnotation,
|
|
109
|
+
olderType: CompleteTypeAnnotation,
|
|
110
|
+
previousError?: TypeComparisonError
|
|
111
|
+
): TypeComparisonError;
|
|
112
|
+
export declare function typeAnnotationComparisonError(
|
|
113
|
+
message: string,
|
|
114
|
+
newerAnnotation: CompleteTypeAnnotation,
|
|
115
|
+
olderAnnotation: CompleteTypeAnnotation,
|
|
116
|
+
previousError?: TypeComparisonError
|
|
117
|
+
): TypeComparisonError;
|
|
118
|
+
export declare function propertyComparisonError(
|
|
119
|
+
message: string,
|
|
120
|
+
mismatchedProperties: Array<{
|
|
121
|
+
property: string;
|
|
122
|
+
fault?: TypeComparisonError;
|
|
123
|
+
}>,
|
|
124
|
+
previousError?: TypeComparisonError
|
|
125
|
+
): TypeComparisonError;
|
|
126
|
+
export declare function memberComparisonError(
|
|
127
|
+
message: string,
|
|
128
|
+
mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>,
|
|
129
|
+
previousError?: TypeComparisonError
|
|
130
|
+
): TypeComparisonError;
|
|
131
|
+
export declare function positionalComparisonError(
|
|
132
|
+
message: string,
|
|
133
|
+
erroneousItems: Array<[number, CompleteTypeAnnotation]>,
|
|
134
|
+
previousError?: TypeComparisonError
|
|
135
|
+
): TypeComparisonError;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true,
|
|
5
|
+
});
|
|
6
|
+
exports.isFunctionLogEmpty = isFunctionLogEmpty;
|
|
7
|
+
exports.isMemberLogEmpty = isMemberLogEmpty;
|
|
8
|
+
exports.isPropertyLogEmpty = isPropertyLogEmpty;
|
|
9
|
+
exports.makeError = makeError;
|
|
10
|
+
exports.memberComparisonError = memberComparisonError;
|
|
11
|
+
exports.positionalComparisonError = positionalComparisonError;
|
|
12
|
+
exports.propertyComparisonError = propertyComparisonError;
|
|
13
|
+
exports.typeAnnotationComparisonError = typeAnnotationComparisonError;
|
|
14
|
+
exports.typeInformationComparisonError = typeInformationComparisonError;
|
|
15
|
+
function isPropertyLogEmpty(result) {
|
|
16
|
+
return !(
|
|
17
|
+
result.addedProperties ||
|
|
18
|
+
result.missingProperties ||
|
|
19
|
+
result.nestedPropertyChanges ||
|
|
20
|
+
result.madeStrict ||
|
|
21
|
+
result.madeOptional ||
|
|
22
|
+
result.errorProperties
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
function isMemberLogEmpty(result) {
|
|
26
|
+
return !(result.addedMembers || result.missingMembers || result.errorMembers);
|
|
27
|
+
}
|
|
28
|
+
function isFunctionLogEmpty(result) {
|
|
29
|
+
return !(result.returnType || result.parameterTypes);
|
|
30
|
+
}
|
|
31
|
+
function makeError(error) {
|
|
32
|
+
return {
|
|
33
|
+
status: "error",
|
|
34
|
+
errorLog: error,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function typeInformationComparisonError(
|
|
38
|
+
message,
|
|
39
|
+
newerType,
|
|
40
|
+
olderType,
|
|
41
|
+
previousError
|
|
42
|
+
) {
|
|
43
|
+
return {
|
|
44
|
+
type: "TypeInformationComparisonError",
|
|
45
|
+
message,
|
|
46
|
+
newerType,
|
|
47
|
+
olderType,
|
|
48
|
+
previousError,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function typeAnnotationComparisonError(
|
|
52
|
+
message,
|
|
53
|
+
newerAnnotation,
|
|
54
|
+
olderAnnotation,
|
|
55
|
+
previousError
|
|
56
|
+
) {
|
|
57
|
+
return {
|
|
58
|
+
type: "TypeAnnotationComparisonError",
|
|
59
|
+
message,
|
|
60
|
+
newerAnnotation,
|
|
61
|
+
olderAnnotation,
|
|
62
|
+
previousError,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function propertyComparisonError(message, mismatchedProperties, previousError) {
|
|
66
|
+
return {
|
|
67
|
+
type: "PropertyComparisonError",
|
|
68
|
+
message,
|
|
69
|
+
mismatchedProperties,
|
|
70
|
+
previousError,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function memberComparisonError(message, mismatchedMembers, previousError) {
|
|
74
|
+
return {
|
|
75
|
+
type: "MemberComparisonError",
|
|
76
|
+
message,
|
|
77
|
+
mismatchedMembers,
|
|
78
|
+
previousError,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function positionalComparisonError(message, erroneousItems, previousError) {
|
|
82
|
+
return {
|
|
83
|
+
type: "PositionalComparisonError",
|
|
84
|
+
message,
|
|
85
|
+
erroneousItems,
|
|
86
|
+
previousError,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
CompleteTypeAnnotation,
|
|
13
|
+
NamedShape,
|
|
14
|
+
NativeModuleEnumMember,
|
|
15
|
+
} from "@react-native/codegen/src/CodegenSchema";
|
|
16
|
+
|
|
17
|
+
type TypeAnnotationComparisonError = {
|
|
18
|
+
type: "TypeAnnotationComparisonError",
|
|
19
|
+
message: string,
|
|
20
|
+
newerAnnotation: CompleteTypeAnnotation,
|
|
21
|
+
olderAnnotation: CompleteTypeAnnotation,
|
|
22
|
+
previousError?: TypeComparisonError,
|
|
23
|
+
};
|
|
24
|
+
type TypeInformationComparisonError = {
|
|
25
|
+
type: "TypeInformationComparisonError",
|
|
26
|
+
message: string,
|
|
27
|
+
newerType: CompleteTypeAnnotation,
|
|
28
|
+
olderType: CompleteTypeAnnotation,
|
|
29
|
+
previousError?: TypeComparisonError,
|
|
30
|
+
};
|
|
31
|
+
type PropertyComparisonError = {
|
|
32
|
+
type: "PropertyComparisonError",
|
|
33
|
+
message: string,
|
|
34
|
+
mismatchedProperties: Array<{
|
|
35
|
+
property: string,
|
|
36
|
+
fault?: TypeComparisonError,
|
|
37
|
+
...
|
|
38
|
+
}>,
|
|
39
|
+
previousError?: TypeComparisonError,
|
|
40
|
+
};
|
|
41
|
+
type PositionalComparisonError = {
|
|
42
|
+
type: "PositionalComparisonError",
|
|
43
|
+
message: string,
|
|
44
|
+
erroneousItems: Array<[number, CompleteTypeAnnotation]>,
|
|
45
|
+
previousError?: TypeComparisonError,
|
|
46
|
+
};
|
|
47
|
+
type MemberComparisonError = {
|
|
48
|
+
type: "MemberComparisonError",
|
|
49
|
+
message: string,
|
|
50
|
+
mismatchedMembers: Array<{
|
|
51
|
+
member: string,
|
|
52
|
+
fault?: TypeComparisonError,
|
|
53
|
+
}>,
|
|
54
|
+
previousError?: TypeComparisonError,
|
|
55
|
+
};
|
|
56
|
+
export type TypeComparisonError =
|
|
57
|
+
| TypeAnnotationComparisonError
|
|
58
|
+
| TypeInformationComparisonError
|
|
59
|
+
| PropertyComparisonError
|
|
60
|
+
| PositionalComparisonError
|
|
61
|
+
| MemberComparisonError;
|
|
62
|
+
|
|
63
|
+
// Collects changes that may be type safe within parameters, unions, intersections, and tuples
|
|
64
|
+
export type PositionalComparisonResult = {
|
|
65
|
+
typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple",
|
|
66
|
+
// Nested changes stores the position of the old type followed by new
|
|
67
|
+
// Except for union and intersection, new position === old position
|
|
68
|
+
nestedChanges: Array<[number, number, ComparisonResult]>,
|
|
69
|
+
// These properties should never occur for a tuple
|
|
70
|
+
addedElements?: Array<[number, CompleteTypeAnnotation]>,
|
|
71
|
+
removedElements?: Array<[number, CompleteTypeAnnotation]>,
|
|
72
|
+
...
|
|
73
|
+
};
|
|
74
|
+
export type FunctionComparisonResult = {
|
|
75
|
+
returnType?: ComparisonResult,
|
|
76
|
+
// The following should always have typeKind 'parameter'
|
|
77
|
+
parameterTypes?: PositionalComparisonResult,
|
|
78
|
+
...
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Array<NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>>
|
|
82
|
+
|
|
83
|
+
export type PropertiesComparisonResult = {
|
|
84
|
+
addedProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
|
|
85
|
+
missingProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
|
|
86
|
+
errorProperties?: Array<{
|
|
87
|
+
property: string,
|
|
88
|
+
fault?: TypeComparisonError,
|
|
89
|
+
...
|
|
90
|
+
}>,
|
|
91
|
+
madeStrict?: Array<{
|
|
92
|
+
property: string,
|
|
93
|
+
furtherChanges?: ComparisonResult,
|
|
94
|
+
...
|
|
95
|
+
}>,
|
|
96
|
+
madeOptional?: Array<{
|
|
97
|
+
property: string,
|
|
98
|
+
furtherChanges?: ComparisonResult,
|
|
99
|
+
...
|
|
100
|
+
}>,
|
|
101
|
+
nestedPropertyChanges?: Array<[string, ComparisonResult]>,
|
|
102
|
+
...
|
|
103
|
+
};
|
|
104
|
+
export type MembersComparisonResult = {
|
|
105
|
+
addedMembers?: Array<NativeModuleEnumMember>,
|
|
106
|
+
missingMembers?: Array<NativeModuleEnumMember>,
|
|
107
|
+
errorMembers?: Array<{
|
|
108
|
+
member: string,
|
|
109
|
+
fault?: TypeComparisonError,
|
|
110
|
+
}>,
|
|
111
|
+
};
|
|
112
|
+
export type NullableComparisonResult = {
|
|
113
|
+
/* Four possible cases of change:
|
|
114
|
+
void goes to T? :: typeRefined !optionsReduced
|
|
115
|
+
T? goes to void :: typeRefined optionsReduced
|
|
116
|
+
T goes to T? :: !typeRefined !optionsReduced
|
|
117
|
+
T? goes to T :: !typeRefined optionsReduced
|
|
118
|
+
*/
|
|
119
|
+
typeRefined: boolean,
|
|
120
|
+
optionsReduced: boolean,
|
|
121
|
+
// interiorLog not available if either type is void
|
|
122
|
+
interiorLog: ?ComparisonResult,
|
|
123
|
+
newType: ?CompleteTypeAnnotation,
|
|
124
|
+
oldType: ?CompleteTypeAnnotation,
|
|
125
|
+
...
|
|
126
|
+
};
|
|
127
|
+
export type ComparisonResult =
|
|
128
|
+
| { status: "matching" }
|
|
129
|
+
| { status: "skipped" }
|
|
130
|
+
| { status: "nullableChange", nullableLog: NullableComparisonResult }
|
|
131
|
+
| { status: "properties", propertyLog: PropertiesComparisonResult }
|
|
132
|
+
| { status: "members", memberLog: MembersComparisonResult }
|
|
133
|
+
| { status: "functionChange", functionChangeLog: FunctionComparisonResult }
|
|
134
|
+
| { status: "positionalTypeChange", changeLog: PositionalComparisonResult }
|
|
135
|
+
| { status: "error", errorLog: TypeComparisonError };
|
|
136
|
+
|
|
137
|
+
declare export function isPropertyLogEmpty(
|
|
138
|
+
result: PropertiesComparisonResult
|
|
139
|
+
): boolean;
|
|
140
|
+
|
|
141
|
+
declare export function isMemberLogEmpty(
|
|
142
|
+
result: MembersComparisonResult
|
|
143
|
+
): boolean;
|
|
144
|
+
|
|
145
|
+
declare export function isFunctionLogEmpty(
|
|
146
|
+
result: FunctionComparisonResult
|
|
147
|
+
): boolean;
|
|
148
|
+
|
|
149
|
+
declare export function makeError(error: TypeComparisonError): ComparisonResult;
|
|
150
|
+
|
|
151
|
+
declare export function typeInformationComparisonError(
|
|
152
|
+
message: string,
|
|
153
|
+
newerType: CompleteTypeAnnotation,
|
|
154
|
+
olderType: CompleteTypeAnnotation,
|
|
155
|
+
previousError?: TypeComparisonError
|
|
156
|
+
): TypeComparisonError;
|
|
157
|
+
|
|
158
|
+
declare export function typeAnnotationComparisonError(
|
|
159
|
+
message: string,
|
|
160
|
+
newerAnnotation: CompleteTypeAnnotation,
|
|
161
|
+
olderAnnotation: CompleteTypeAnnotation,
|
|
162
|
+
previousError?: TypeComparisonError
|
|
163
|
+
): TypeComparisonError;
|
|
164
|
+
|
|
165
|
+
declare export function propertyComparisonError(
|
|
166
|
+
message: string,
|
|
167
|
+
mismatchedProperties: Array<{
|
|
168
|
+
property: string,
|
|
169
|
+
fault?: TypeComparisonError,
|
|
170
|
+
...
|
|
171
|
+
}>,
|
|
172
|
+
previousError?: TypeComparisonError
|
|
173
|
+
): TypeComparisonError;
|
|
174
|
+
|
|
175
|
+
declare export function memberComparisonError(
|
|
176
|
+
message: string,
|
|
177
|
+
mismatchedMembers: Array<{
|
|
178
|
+
member: string,
|
|
179
|
+
fault?: TypeComparisonError,
|
|
180
|
+
}>,
|
|
181
|
+
previousError?: TypeComparisonError
|
|
182
|
+
): TypeComparisonError;
|
|
183
|
+
|
|
184
|
+
declare export function positionalComparisonError(
|
|
185
|
+
message: string,
|
|
186
|
+
erroneousItems: Array<[number, CompleteTypeAnnotation]>,
|
|
187
|
+
previousError?: TypeComparisonError
|
|
188
|
+
): TypeComparisonError;
|