From ad271a94366f4ff091771ab71631fce71ec0ccd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:02:54 +0000 Subject: [PATCH 1/8] Initial plan From 2199b77cbd872096f9f90ef240a054dc04376d1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:22:50 +0000 Subject: [PATCH 2/8] Attempt fix for TextInput border rendering by setting masksToBounds Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- packages/community-cli-plugin/package.json | 2 +- packages/core-cli-utils/package.json | 6 +- packages/dev-middleware/package.json | 2 +- packages/metro-config/package.json | 2 +- .../dist/ComparisonResult.d.ts | 135 ++ .../dist/ComparisonResult.js | 88 ++ .../dist/ComparisonResult.js.flow | 188 +++ .../dist/DiffResults.d.ts | 137 ++ .../dist/DiffResults.js | 52 + .../dist/DiffResults.js.flow | 160 +++ .../dist/ErrorFormatting.d.ts | 31 + .../dist/ErrorFormatting.js | 272 ++++ .../dist/ErrorFormatting.js.flow | 34 + .../dist/SortTypeAnnotations.d.ts | 18 + .../dist/SortTypeAnnotations.js | 300 ++++ .../dist/SortTypeAnnotations.js.flow | 20 + .../dist/TypeDiffing.d.ts | 86 ++ .../dist/TypeDiffing.js | 1253 +++++++++++++++++ .../dist/TypeDiffing.js.flow | 99 ++ .../dist/VersionDiffing.d.ts | 59 + .../dist/VersionDiffing.js | 1235 ++++++++++++++++ .../dist/VersionDiffing.js.flow | 71 + .../dist/convertPropToBasicTypes.d.ts | 20 + .../dist/convertPropToBasicTypes.js | 86 ++ .../dist/convertPropToBasicTypes.js.flow | 20 + .../dist/index.d.ts | 12 + .../dist/index.js | 12 + .../dist/index.js.flow | 12 + .../package.json | 2 +- .../TextInput/RCTTextInputComponentView.mm | 159 ++- 30 files changed, 4495 insertions(+), 78 deletions(-) create mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.d.ts create mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.js create mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.js.flow create mode 100644 packages/react-native-compatibility-check/dist/DiffResults.d.ts create mode 100644 packages/react-native-compatibility-check/dist/DiffResults.js create mode 100644 packages/react-native-compatibility-check/dist/DiffResults.js.flow create mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts create mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.js create mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow create mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts create mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.js create mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow create mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.d.ts create mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.js create mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.js.flow create mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.d.ts create mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.js create mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.js.flow create mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts create mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js create mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow create mode 100644 packages/react-native-compatibility-check/dist/index.d.ts create mode 100644 packages/react-native-compatibility-check/dist/index.js create mode 100644 packages/react-native-compatibility-check/dist/index.js.flow diff --git a/packages/community-cli-plugin/package.json b/packages/community-cli-plugin/package.json index 48d57288558183..c1699033894e42 100644 --- a/packages/community-cli-plugin/package.json +++ b/packages/community-cli-plugin/package.json @@ -16,7 +16,7 @@ }, "license": "MIT", "exports": { - ".": "./src/index.js", + ".": "./dist/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/core-cli-utils/package.json b/packages/core-cli-utils/package.json index f62b62d39b024b..273f4e2de7eebf 100644 --- a/packages/core-cli-utils/package.json +++ b/packages/core-cli-utils/package.json @@ -4,16 +4,16 @@ "private": true, "description": "React Native CLI library for Frameworks to build on", "license": "MIT", - "main": "./src/index.flow.js", + "main": "./dist/index.flow.js", "repository": { "type": "git", "url": "git+https://github.com/facebook/react-native.git", "directory": "packages/core-cli-utils" }, "exports": { - ".": "./src/index.js", + ".": "./dist/index.js", "./package.json": "./package.json", - "./version.js": "./src/public/version.js" + "./version.js": "./dist/public/version.js" }, "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/core-cli-utils#readme", "keywords": [ diff --git a/packages/dev-middleware/package.json b/packages/dev-middleware/package.json index bf4a792ee40541..92a8e008bea887 100644 --- a/packages/dev-middleware/package.json +++ b/packages/dev-middleware/package.json @@ -16,7 +16,7 @@ }, "license": "MIT", "exports": { - ".": "./src/index.js", + ".": "./dist/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 73076dccd42462..fe336e01362666 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -20,7 +20,7 @@ "node": ">=18" }, "exports": { - ".": "./src/index.js", + ".": "./dist/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts b/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts new file mode 100644 index 00000000000000..6e13ad67a8844d --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts @@ -0,0 +1,135 @@ +/** + * 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 + */ + +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; +export type PositionalComparisonResult = { + typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple"; + nestedChanges: Array<[number, number, ComparisonResult]>; + addedElements?: Array<[number, CompleteTypeAnnotation]>; + removedElements?: Array<[number, CompleteTypeAnnotation]>; +}; +export type FunctionComparisonResult = { + returnType?: ComparisonResult; + parameterTypes?: PositionalComparisonResult; +}; +export type PropertiesComparisonResult = { + addedProperties?: ReadonlyArray>; + missingProperties?: ReadonlyArray>; + 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; + missingMembers?: Array; + errorMembers?: Array<{ member: string; fault?: TypeComparisonError }>; +}; +export type NullableComparisonResult = { + typeRefined: boolean; + optionsReduced: boolean; + interiorLog: null | undefined | ComparisonResult; + newType: null | undefined | CompleteTypeAnnotation; + oldType: null | undefined | 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 declare function isPropertyLogEmpty( + result: PropertiesComparisonResult +): boolean; +export declare function isMemberLogEmpty( + result: MembersComparisonResult +): boolean; +export declare function isFunctionLogEmpty( + result: FunctionComparisonResult +): boolean; +export declare function makeError(error: TypeComparisonError): ComparisonResult; +export declare function typeInformationComparisonError( + message: string, + newerType: CompleteTypeAnnotation, + olderType: CompleteTypeAnnotation, + previousError?: TypeComparisonError +): TypeComparisonError; +export declare function typeAnnotationComparisonError( + message: string, + newerAnnotation: CompleteTypeAnnotation, + olderAnnotation: CompleteTypeAnnotation, + previousError?: TypeComparisonError +): TypeComparisonError; +export declare function propertyComparisonError( + message: string, + mismatchedProperties: Array<{ + property: string; + fault?: TypeComparisonError; + }>, + previousError?: TypeComparisonError +): TypeComparisonError; +export declare function memberComparisonError( + message: string, + mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>, + previousError?: TypeComparisonError +): TypeComparisonError; +export declare function positionalComparisonError( + message: string, + erroneousItems: Array<[number, CompleteTypeAnnotation]>, + previousError?: TypeComparisonError +): TypeComparisonError; diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.js b/packages/react-native-compatibility-check/dist/ComparisonResult.js new file mode 100644 index 00000000000000..835217ea999220 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ComparisonResult.js @@ -0,0 +1,88 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.isFunctionLogEmpty = isFunctionLogEmpty; +exports.isMemberLogEmpty = isMemberLogEmpty; +exports.isPropertyLogEmpty = isPropertyLogEmpty; +exports.makeError = makeError; +exports.memberComparisonError = memberComparisonError; +exports.positionalComparisonError = positionalComparisonError; +exports.propertyComparisonError = propertyComparisonError; +exports.typeAnnotationComparisonError = typeAnnotationComparisonError; +exports.typeInformationComparisonError = typeInformationComparisonError; +function isPropertyLogEmpty(result) { + return !( + result.addedProperties || + result.missingProperties || + result.nestedPropertyChanges || + result.madeStrict || + result.madeOptional || + result.errorProperties + ); +} +function isMemberLogEmpty(result) { + return !(result.addedMembers || result.missingMembers || result.errorMembers); +} +function isFunctionLogEmpty(result) { + return !(result.returnType || result.parameterTypes); +} +function makeError(error) { + return { + status: "error", + errorLog: error, + }; +} +function typeInformationComparisonError( + message, + newerType, + olderType, + previousError +) { + return { + type: "TypeInformationComparisonError", + message, + newerType, + olderType, + previousError, + }; +} +function typeAnnotationComparisonError( + message, + newerAnnotation, + olderAnnotation, + previousError +) { + return { + type: "TypeAnnotationComparisonError", + message, + newerAnnotation, + olderAnnotation, + previousError, + }; +} +function propertyComparisonError(message, mismatchedProperties, previousError) { + return { + type: "PropertyComparisonError", + message, + mismatchedProperties, + previousError, + }; +} +function memberComparisonError(message, mismatchedMembers, previousError) { + return { + type: "MemberComparisonError", + message, + mismatchedMembers, + previousError, + }; +} +function positionalComparisonError(message, erroneousItems, previousError) { + return { + type: "PositionalComparisonError", + message, + erroneousItems, + previousError, + }; +} diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow b/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow new file mode 100644 index 00000000000000..9188eddfa79c1c --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow @@ -0,0 +1,188 @@ +/** + * 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>> + +export type PropertiesComparisonResult = { + addedProperties?: $ReadOnlyArray>, + missingProperties?: $ReadOnlyArray>, + 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, + missingMembers?: Array, + 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 }; + +declare export function isPropertyLogEmpty( + result: PropertiesComparisonResult +): boolean; + +declare export function isMemberLogEmpty( + result: MembersComparisonResult +): boolean; + +declare export function isFunctionLogEmpty( + result: FunctionComparisonResult +): boolean; + +declare export function makeError(error: TypeComparisonError): ComparisonResult; + +declare export function typeInformationComparisonError( + message: string, + newerType: CompleteTypeAnnotation, + olderType: CompleteTypeAnnotation, + previousError?: TypeComparisonError +): TypeComparisonError; + +declare export function typeAnnotationComparisonError( + message: string, + newerAnnotation: CompleteTypeAnnotation, + olderAnnotation: CompleteTypeAnnotation, + previousError?: TypeComparisonError +): TypeComparisonError; + +declare export function propertyComparisonError( + message: string, + mismatchedProperties: Array<{ + property: string, + fault?: TypeComparisonError, + ... + }>, + previousError?: TypeComparisonError +): TypeComparisonError; + +declare export function memberComparisonError( + message: string, + mismatchedMembers: Array<{ + member: string, + fault?: TypeComparisonError, + }>, + previousError?: TypeComparisonError +): TypeComparisonError; + +declare export function positionalComparisonError( + message: string, + erroneousItems: Array<[number, CompleteTypeAnnotation]>, + previousError?: TypeComparisonError +): TypeComparisonError; diff --git a/packages/react-native-compatibility-check/dist/DiffResults.d.ts b/packages/react-native-compatibility-check/dist/DiffResults.d.ts new file mode 100644 index 00000000000000..e4179054afafa4 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/DiffResults.d.ts @@ -0,0 +1,137 @@ +/** + * 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 + */ + +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; +}; +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; + deprecatedTypes: Set; + objectTypeChanges: Set; + incompatibleChanges: Set; +}; +type ExportableDiffSet = { + newTypes: Array; + deprecatedTypes: Array; + objectTypeChanges: Array; + incompatibleChanges: Array; +}; +export type Framework = "ReactNative"; +export type SchemaDiffers = { + incompatibleSpecs: null | undefined | Set; +}; +type ExportableSchemaDiffers = { + incompatibleSpecs: null | undefined | Array; +}; +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; +}; +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"; + incompatibilityReport: IncompatiblityReport; +}; +export type FormattedIncompatible = { + framework: Framework; + incompatibleSpecs?: Array; +}; +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"; + incompatibilityReport: FormattedIncompatiblityReport; +}; +export declare function nativeSpecErrorExporter( + nativeSpecError: NativeSpecErrorStore +): ExportableNativeSpecErrorStore; +export declare function schemaDiffExporter( + schemaDiff: SchemaDiff +): ExportableSchemaDiff; diff --git a/packages/react-native-compatibility-check/dist/DiffResults.js b/packages/react-native-compatibility-check/dist/DiffResults.js new file mode 100644 index 00000000000000..9f7dfbc736e521 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/DiffResults.js @@ -0,0 +1,52 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.nativeSpecErrorExporter = nativeSpecErrorExporter; +exports.schemaDiffExporter = schemaDiffExporter; +function diffSetExporter(diffSet) { + return { + newTypes: Array.from(diffSet.newTypes), + deprecatedTypes: Array.from(diffSet.deprecatedTypes), + objectTypeChanges: Array.from(diffSet.objectTypeChanges), + incompatibleChanges: Array.from(diffSet.incompatibleChanges), + }; +} +function nativeSpecErrorExporter(nativeSpecError) { + 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) { + switch (status) { + case "new": + case "deprecated": + return status; + default: + return { + incompatibleSpecs: status.incompatibleSpecs + ? Array.from(status.incompatibleSpecs).map(nativeSpecErrorExporter) + : undefined, + }; + } +} +function schemaDiffExporter(schemaDiff) { + return { + name: schemaDiff.name, + framework: schemaDiff.framework, + status: schemaDiffCategoryExporter(schemaDiff.status), + }; +} diff --git a/packages/react-native-compatibility-check/dist/DiffResults.js.flow b/packages/react-native-compatibility-check/dist/DiffResults.js.flow new file mode 100644 index 00000000000000..659eba6d6982d0 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/DiffResults.js.flow @@ -0,0 +1,160 @@ +/** + * 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, + deprecatedTypes: Set, + objectTypeChanges: Set, + incompatibleChanges: Set, +}; +type ExportableDiffSet = { + newTypes: Array, + deprecatedTypes: Array, + objectTypeChanges: Array, + incompatibleChanges: Array, +}; + +export type Framework = "ReactNative"; +export type SchemaDiffers = { + incompatibleSpecs: ?Set, +}; +type ExportableSchemaDiffers = { + incompatibleSpecs: ?Array, +}; +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, +}; +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, +}; + +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, +}; + +declare export function nativeSpecErrorExporter( + nativeSpecError: NativeSpecErrorStore +): ExportableNativeSpecErrorStore; + +declare export function schemaDiffExporter( + schemaDiff: SchemaDiff +): ExportableSchemaDiff; diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts b/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts new file mode 100644 index 00000000000000..27eaca66725d09 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts @@ -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. + * + * + * @format + */ + +import type { TypeComparisonError } from "./ComparisonResult"; +import type { + DiffSummary, + ErrorStore, + FormattedDiffSummary, + FormattedErrorStore, + NativeSpecErrorStore, +} from "./DiffResults"; +export declare function formatErrorMessage( + error: TypeComparisonError, + indent: number +): string; +export declare function formatErrorStore( + errorStore: ErrorStore +): FormattedErrorStore; +export declare function formatNativeSpecErrorStore( + specError: NativeSpecErrorStore +): Array; +export declare function formatDiffSet( + summary: DiffSummary +): FormattedDiffSummary; diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.js b/packages/react-native-compatibility-check/dist/ErrorFormatting.js new file mode 100644 index 00000000000000..8bb5e380d8d932 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ErrorFormatting.js @@ -0,0 +1,272 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.formatDiffSet = formatDiffSet; +exports.formatErrorMessage = formatErrorMessage; +exports.formatErrorStore = formatErrorStore; +exports.formatNativeSpecErrorStore = formatNativeSpecErrorStore; +function indentedLineStart(indent) { + return "\n" + " ".repeat(indent); +} +function formatErrorMessage(error, indent = 0) { + 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": + 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; + return ""; + } +} +function formatTypeAnnotation(annotation) { + 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; + 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; + 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": + 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; + return JSON.stringify(annotation); + } +} +function formatErrorStore(errorStore) { + return { + message: + errorStore.typeName + + ": " + + formatErrorMessage(errorStore.errorInformation), + errorCode: errorStore.errorCode, + }; +} +function formatNativeSpecErrorStore(specError) { + 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) + ); + } + return []; +} +function formatDiffSet(summary) { + const summaryStatus = summary.status; + if (summaryStatus === "ok" || summaryStatus === "patchable") { + return summary; + } + const hasteModules = Object.keys(summary.incompatibilityReport); + const incompatibles = summary.incompatibilityReport; + const formattedIncompatibilities = {}; + hasteModules.forEach((hasteModule) => { + const incompat = incompatibles[hasteModule]; + const formattedIncompat = { + framework: incompat.framework, + }; + if (incompat.incompatibleSpecs) { + formattedIncompat.incompatibleSpecs = incompat.incompatibleSpecs.reduce( + (formattedModuleErrors, specErrorStore) => + formattedModuleErrors.concat( + formatNativeSpecErrorStore(specErrorStore) + ), + [] + ); + } + formattedIncompatibilities[hasteModule] = formattedIncompat; + }); + return { + status: summaryStatus, + incompatibilityReport: formattedIncompatibilities, + }; +} diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow b/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow new file mode 100644 index 00000000000000..d132768e178a09 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow @@ -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 { TypeComparisonError } from "./ComparisonResult"; +import type { + DiffSummary, + ErrorStore, + FormattedDiffSummary, + FormattedErrorStore, + NativeSpecErrorStore, +} from "./DiffResults"; +declare export function formatErrorMessage( + error: TypeComparisonError, + indent: number +): string; + +declare export function formatErrorStore( + errorStore: ErrorStore +): FormattedErrorStore; + +declare export function formatNativeSpecErrorStore( + specError: NativeSpecErrorStore +): Array; + +declare export function formatDiffSet( + summary: DiffSummary +): FormattedDiffSummary; diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts new file mode 100644 index 00000000000000..bc295d80883322 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts @@ -0,0 +1,18 @@ +/** + * 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 + */ + +import type { CompleteTypeAnnotation } from "@react-native/codegen/src/CodegenSchema"; +export declare function sortTypeAnnotations( + annotations: ReadonlyArray +): Array<[number, CompleteTypeAnnotation]>; +export declare function compareTypeAnnotationForSorting( + $$PARAM_0$$: [number, CompleteTypeAnnotation], + $$PARAM_1$$: [number, CompleteTypeAnnotation] +): number; diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js new file mode 100644 index 00000000000000..d39e8402fca9ce --- /dev/null +++ b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js @@ -0,0 +1,300 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.compareTypeAnnotationForSorting = compareTypeAnnotationForSorting; +exports.sortTypeAnnotations = sortTypeAnnotations; +var _invariant = _interopRequireDefault(require("invariant")); +function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e }; +} +function sortTypeAnnotations(annotations) { + const sortableArray = annotations.map((a, i) => [i, a]); + return sortableArray.sort(compareTypeAnnotationForSorting); +} +const EQUALITY_MSG = "typeA and typeB differ despite check"; +function compareTypeAnnotationForSorting( + [originalPositionA, typeA], + [originalPositionB, typeB] +) { + 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": + (0, _invariant.default)( + typeB.type === "ArrayTypeAnnotation", + EQUALITY_MSG + ); + return compareTypeAnnotationForSorting( + [originalPositionA, typeA.elementType], + [originalPositionB, typeB.elementType] + ); + case "BooleanTypeAnnotation": + return originalPositionA - originalPositionB; + case "EnumDeclaration": + (0, _invariant.default)(typeB.type === "EnumDeclaration", EQUALITY_MSG); + return typeA.memberType.localeCompare(typeB.memberType); + case "EnumDeclarationWithMembers": + (0, _invariant.default)( + 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": + (0, _invariant.default)( + 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": + (0, _invariant.default)( + typeB.type === "EventEmitterTypeAnnotation", + EQUALITY_MSG + ); + return compareTypeAnnotationForSorting( + [originalPositionA, typeA.typeAnnotation], + [originalPositionB, typeB.typeAnnotation] + ); + case "GenericObjectTypeAnnotation": + (0, _invariant.default)( + 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": + (0, _invariant.default)( + 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": + (0, _invariant.default)( + typeB.type === "NumberLiteralTypeAnnotation", + EQUALITY_MSG + ); + return typeA.value - typeB.value; + case "ObjectTypeAnnotation": + (0, _invariant.default)( + 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": + (0, _invariant.default)( + typeB.type === "StringLiteralTypeAnnotation", + EQUALITY_MSG + ); + return typeA.value.localeCompare(typeB.value); + case "StringLiteralUnionTypeAnnotation": + (0, _invariant.default)( + typeB.type === "StringLiteralUnionTypeAnnotation", + EQUALITY_MSG + ); + return compareAnnotationArraysForSorting( + [originalPositionA, typeA.types], + [originalPositionB, typeB.types] + ); + case "UnionTypeAnnotation": + (0, _invariant.default)( + typeB.type === "UnionTypeAnnotation", + EQUALITY_MSG + ); + return 0; + case "VoidTypeAnnotation": + return 0; + case "ReservedTypeAnnotation": + return 0; + case "PromiseTypeAnnotation": + (0, _invariant.default)( + typeB.type === "PromiseTypeAnnotation", + EQUALITY_MSG + ); + return compareTypeAnnotationForSorting( + [originalPositionA, typeA.elementType], + [originalPositionB, typeB.elementType] + ); + case "TypeAliasTypeAnnotation": + return 0; + case "MixedTypeAnnotation": + return 0; + default: + typeA.type; + return -1; + } +} +function nameComparison([nameA], [nameB]) { + if (nameA === nameB) { + return 0; + } else if (nameA < nameB) { + return -1; + } + return 1; +} +function compareNameAnnotationArraysForSorting( + [originalPositionA, arrayA], + [originalPositionB, arrayB] +) { + 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], + [originalPositionB, arrayB] +) { + 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) { + 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; + return -1; + } +} diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow new file mode 100644 index 00000000000000..67a5fccc6692bf --- /dev/null +++ b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow @@ -0,0 +1,20 @@ +/** + * 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"; + +declare export function sortTypeAnnotations( + annotations: $ReadOnlyArray +): Array<[number, CompleteTypeAnnotation]>; + +declare export function compareTypeAnnotationForSorting( + [number, CompleteTypeAnnotation], + [number, CompleteTypeAnnotation] +): number; diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts b/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts new file mode 100644 index 00000000000000..053d56cdd9f9aa --- /dev/null +++ b/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts @@ -0,0 +1,86 @@ +/** + * 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 + */ + +import type { + ComparisonResult, + MembersComparisonResult, +} from "./ComparisonResult"; +import type { + CompleteTypeAnnotation, + NamedShape, + NativeModuleAliasMap, + NativeModuleEnumDeclaration, + NativeModuleEnumDeclarationWithMembers, + NativeModuleEnumMap, + NativeModuleEnumMember, + NativeModuleFunctionTypeAnnotation, + NativeModuleGenericObjectTypeAnnotation, + NativeModulePromiseTypeAnnotation, + NativeModuleUnionTypeAnnotation, + NumberLiteralTypeAnnotation, + StringLiteralTypeAnnotation, + StringLiteralUnionTypeAnnotation, +} from "@react-native/codegen/src/CodegenSchema"; +export declare function compareTypes( + newerType: CompleteTypeAnnotation, + olderType: null | undefined | CompleteTypeAnnotation, + newerTypesReg: null | undefined | NativeModuleAliasMap, + olderTypesReg: null | undefined | NativeModuleAliasMap, + newerEnumMap: null | undefined | NativeModuleEnumMap, + olderEnumMap: null | undefined | NativeModuleEnumMap +): ComparisonResult; +export declare function compareTypeAnnotation( + originalNewerAnnotation: CompleteTypeAnnotation, + originalOlderAnnotation: CompleteTypeAnnotation +): ComparisonResult; +export declare function compareObjectTypes( + newerPropertyTypes: ReadonlyArray>, + olderPropertyTypes: ReadonlyArray> +): ComparisonResult; +export declare function compareEnumDeclarations( + newerDeclaration: NativeModuleEnumDeclaration, + olderDeclaration: NativeModuleEnumDeclaration +): ComparisonResult; +export declare function compareEnumDeclarationMemberArrays( + newer: Array, + older: Array +): MembersComparisonResult; +export declare function compareEnumDeclarationWithMembers( + newerDeclaration: NativeModuleEnumDeclarationWithMembers, + olderDeclaration: NativeModuleEnumDeclarationWithMembers +): ComparisonResult; +export declare function compareUnionTypes( + newerType: NativeModuleUnionTypeAnnotation, + olderType: NativeModuleUnionTypeAnnotation +): ComparisonResult; +export declare function comparePromiseTypes( + newerType: NativeModulePromiseTypeAnnotation, + olderType: NativeModulePromiseTypeAnnotation +): ComparisonResult; +export declare function compareGenericObjectTypes( + newerType: NativeModuleGenericObjectTypeAnnotation, + olderType: NativeModuleGenericObjectTypeAnnotation +): ComparisonResult; +export declare function compareNumberLiteralTypes( + newerType: NumberLiteralTypeAnnotation, + olderType: NumberLiteralTypeAnnotation +): ComparisonResult; +export declare function compareStringLiteralTypes( + newerType: StringLiteralTypeAnnotation, + olderType: StringLiteralTypeAnnotation +): ComparisonResult; +export declare function compareStringLiteralUnionTypes( + newerType: StringLiteralUnionTypeAnnotation, + olderType: StringLiteralUnionTypeAnnotation +): ComparisonResult; +export declare function compareFunctionTypes( + newerType: NativeModuleFunctionTypeAnnotation, + olderType: NativeModuleFunctionTypeAnnotation +): ComparisonResult; diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.js b/packages/react-native-compatibility-check/dist/TypeDiffing.js new file mode 100644 index 00000000000000..aa0cfacb05a015 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/TypeDiffing.js @@ -0,0 +1,1253 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.compareEnumDeclarationMemberArrays = compareEnumDeclarationMemberArrays; +exports.compareEnumDeclarationWithMembers = compareEnumDeclarationWithMembers; +exports.compareEnumDeclarations = compareEnumDeclarations; +exports.compareFunctionTypes = compareFunctionTypes; +exports.compareGenericObjectTypes = compareGenericObjectTypes; +exports.compareNumberLiteralTypes = compareNumberLiteralTypes; +exports.compareObjectTypes = compareObjectTypes; +exports.comparePromiseTypes = comparePromiseTypes; +exports.compareStringLiteralTypes = compareStringLiteralTypes; +exports.compareStringLiteralUnionTypes = compareStringLiteralUnionTypes; +exports.compareTypeAnnotation = compareTypeAnnotation; +exports.compareTypes = compareTypes; +exports.compareUnionTypes = compareUnionTypes; +var _ComparisonResult = require("./ComparisonResult"); +var _SortTypeAnnotations = require("./SortTypeAnnotations.js"); +var _invariant = _interopRequireDefault(require("invariant")); +function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e }; +} +const EQUALITY_MSG = "previousType and afterType differ despite check"; +let _newerTypesReg, _olderTypesReg, _newerEnumMap, _olderEnumMap; +function compareTypes( + newerType, + olderType, + newerTypesReg, + olderTypesReg, + newerEnumMap, + olderEnumMap +) { + if (!olderType) { + return { + status: "skipped", + }; + } + _newerTypesReg = newerTypesReg; + _olderTypesReg = olderTypesReg; + _newerEnumMap = newerEnumMap; + _olderEnumMap = olderEnumMap; + const res = compareTypeAnnotation(newerType, olderType); + _newerTypesReg = undefined; + _olderTypesReg = undefined; + _newerEnumMap = undefined; + _olderEnumMap = undefined; + return res; +} +function removeNullableTypeAnnotations(annotation) { + if (annotation.type === "NullableTypeAnnotation") { + return removeNullableTypeAnnotations(annotation.typeAnnotation); + } + return annotation; +} +function lookupType(name, aliases) { + return aliases?.[name]; +} +function lookupEnum(name, enums) { + return enums?.[name]; +} +function compareTypeAnnotation( + originalNewerAnnotation, + originalOlderAnnotation +) { + const newerAnnotation = originalNewerAnnotation; + const olderAnnotation = originalOlderAnnotation; + if (newerAnnotation.type === "TypeAliasTypeAnnotation") { + const newerAnnotationDefinition = lookupType( + newerAnnotation.name, + _newerTypesReg + ); + if (newerAnnotationDefinition != null) { + return compareTypeAnnotation(newerAnnotationDefinition, olderAnnotation); + } + } + if (olderAnnotation.type === "TypeAliasTypeAnnotation") { + const olderAnnotationDefinition = lookupType( + olderAnnotation.name, + _olderTypesReg + ); + if (olderAnnotationDefinition != null) { + return compareTypeAnnotation(newerAnnotation, olderAnnotationDefinition); + } + } + (0, _invariant.default)( + newerAnnotation.type !== "TypeAliasTypeAnnotation" && + olderAnnotation.type !== "TypeAliasTypeAnnotation", + EQUALITY_MSG + ); + if (newerAnnotation.type !== olderAnnotation.type) { + if ( + newerAnnotation.type === "NullableTypeAnnotation" || + olderAnnotation.type === "NullableTypeAnnotation" + ) { + return compareNullableChange(newerAnnotation, olderAnnotation); + } + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Type annotations are not the same.", + newerAnnotation, + olderAnnotation + ) + ); + } + switch (newerAnnotation.type) { + case "AnyTypeAnnotation": + case "MixedTypeAnnotation": + case "DoubleTypeAnnotation": + case "FloatTypeAnnotation": + case "Int32TypeAnnotation": + case "BooleanTypeAnnotation": + case "NumberTypeAnnotation": + case "StringTypeAnnotation": + case "VoidTypeAnnotation": + return { + status: "matching", + }; + case "ArrayTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "ArrayTypeAnnotation", + EQUALITY_MSG + ); + return compareTypeAnnotation( + newerAnnotation.elementType, + olderAnnotation.elementType + ); + case "EnumDeclaration": + (0, _invariant.default)( + olderAnnotation.type === "EnumDeclaration", + EQUALITY_MSG + ); + return compareEnumDeclarations(newerAnnotation, olderAnnotation); + case "EnumDeclarationWithMembers": + (0, _invariant.default)( + olderAnnotation.type === "EnumDeclarationWithMembers", + EQUALITY_MSG + ); + return compareEnumDeclarationWithMembers( + newerAnnotation, + olderAnnotation + ); + case "FunctionTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "FunctionTypeAnnotation", + EQUALITY_MSG + ); + return compareFunctionTypes(newerAnnotation, olderAnnotation); + case "PromiseTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "PromiseTypeAnnotation", + EQUALITY_MSG + ); + return comparePromiseTypes(newerAnnotation, olderAnnotation); + case "GenericObjectTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "GenericObjectTypeAnnotation", + EQUALITY_MSG + ); + return compareGenericObjectTypes(newerAnnotation, olderAnnotation); + case "NullableTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "NullableTypeAnnotation", + EQUALITY_MSG + ); + return compareTypeAnnotation( + newerAnnotation.typeAnnotation, + olderAnnotation.typeAnnotation + ); + case "ObjectTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "ObjectTypeAnnotation", + EQUALITY_MSG + ); + return compareObjectTypes( + newerAnnotation.properties, + olderAnnotation.properties + ); + case "NumberLiteralTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "NumberLiteralTypeAnnotation", + EQUALITY_MSG + ); + return compareNumberLiteralTypes(newerAnnotation, olderAnnotation); + case "StringLiteralUnionTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "StringLiteralUnionTypeAnnotation", + EQUALITY_MSG + ); + return compareStringLiteralUnionTypes(newerAnnotation, olderAnnotation); + case "StringLiteralTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "StringLiteralTypeAnnotation", + EQUALITY_MSG + ); + return compareStringLiteralTypes(newerAnnotation, olderAnnotation); + case "UnionTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "UnionTypeAnnotation", + EQUALITY_MSG + ); + return compareUnionTypes(newerAnnotation, olderAnnotation); + case "EventEmitterTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "EventEmitterTypeAnnotation", + EQUALITY_MSG + ); + return compareEventEmitterTypes(newerAnnotation, olderAnnotation); + case "ReservedTypeAnnotation": + (0, _invariant.default)( + olderAnnotation.type === "ReservedTypeAnnotation", + EQUALITY_MSG + ); + return compareReservedTypeAnnotation(newerAnnotation, olderAnnotation); + default: + throw new Error(`Unsupported type annotation: ${newerAnnotation.type}`); + } +} +function compareObjectTypeProperty(first, second) { + if (first.name < second.name) { + return -1; + } else if (first.name > second.name) { + return 1; + } + return 0; +} +function compareEnumMember(first, second) { + if (first.name < second.name) { + return -1; + } else if (first.name > second.name) { + return 1; + } + return 0; +} +function updatePropertyError(name, newType, oldType, result) { + return (oldError) => { + const comparisonError = (0, + _ComparisonResult.typeAnnotationComparisonError)( + "has conflicting type changes", + newType, + oldType, + oldError + ); + const newFault = { + property: name, + fault: comparisonError, + }; + if (result.errorProperties) { + result.errorProperties.push(newFault); + } else { + result.errorProperties = [newFault]; + } + }; +} +function updateEnumMemberError(name, newType, oldType, result) { + return (oldError) => { + const comparisonError = (0, + _ComparisonResult.typeAnnotationComparisonError)( + "has conflicting changes", + newType, + oldType, + oldError + ); + const newFault = { + member: name, + fault: comparisonError, + }; + if (result.errorMembers) { + result.errorMembers.push(newFault); + } else { + result.errorMembers = [newFault]; + } + }; +} +function updateNestedProperties(name, propertyChange, result) { + if (result.nestedPropertyChanges) { + result.nestedPropertyChanges.push([name, propertyChange]); + } else { + result.nestedPropertyChanges = [[name, propertyChange]]; + } +} +function updateMadeOptional(name, result, furtherChange) { + if (result.madeOptional) { + result.madeOptional.push({ + property: name, + furtherChange, + }); + } else { + result.madeOptional = [ + { + property: name, + furtherChange, + }, + ]; + } +} +function updateMadeStrict(name, result, furtherChange) { + if (result.madeStrict) { + result.madeStrict.push({ + property: name, + furtherChange, + }); + } else { + result.madeStrict = [ + { + property: name, + furtherChange, + }, + ]; + } +} +function checkOptionalityChanges( + name, + newOptionality, + oldOptionality, + result, + furtherChange +) { + if (newOptionality === oldOptionality) { + if (furtherChange) { + updateNestedProperties(name, furtherChange, result); + } + return result; + } + if (newOptionality) { + updateMadeOptional(name, result, furtherChange); + } else { + updateMadeStrict(name, result, furtherChange); + } + return result; +} +function comparePropertyArrays(newerOriginal, olderOriginal) { + const newer = newerOriginal.slice(0); + const older = olderOriginal.slice(0); + if (newer.length === 0 && older.length === 0) { + return {}; + } + if (newer.length === 0) { + return { + missingProperties: older, + }; + } + if (older.length === 0) { + return { + addedProperties: newer, + }; + } + const newerHead = newer.pop(); + const olderHead = older.pop(); + (0, _invariant.default)( + newerHead != null && olderHead != null, + "Array is empty" + ); + const newerName = newerHead.name; + const olderName = olderHead.name; + if (newerName === olderName) { + const comparedTypes = compareTypeAnnotation( + newerHead.typeAnnotation, + olderHead.typeAnnotation + ); + const result = comparePropertyArrays(newer, older); + switch (comparedTypes.status) { + case "matching": + return checkOptionalityChanges( + newerName, + newerHead.optional, + olderHead.optional, + result + ); + case "skipped": + throw new Error( + "Internal error: returned 'skipped' for non-optional older type" + ); + case "nullableChange": + return checkOptionalityChanges( + newerName, + !comparedTypes.nullableLog.optionsReduced, + comparedTypes.nullableLog.optionsReduced, + result + ); + case "members": + case "properties": + case "functionChange": + case "positionalTypeChange": + return checkOptionalityChanges( + newerName, + newerHead.optional, + olderHead.optional, + result, + comparedTypes + ); + case "error": + updatePropertyError( + newerName, + newerHead.typeAnnotation, + olderHead.typeAnnotation, + result + )(comparedTypes.errorLog); + return result; + default: + throw new Error("Unsupported status " + comparedTypes.status); + } + } + if (newerName > olderName) { + older.push(olderHead); + const result = comparePropertyArrays(newer, older); + if (result.hasOwnProperty("addedProperties") && result.addedProperties) { + result.addedProperties = result.addedProperties.concat([newerHead]); + } else { + result.addedProperties = [newerHead]; + } + return result; + } + newer.push(newerHead); + const result = comparePropertyArrays(newer, older); + if (result.hasOwnProperty("missingProperties") && result.missingProperties) { + result.missingProperties = result.missingProperties.concat([olderHead]); + } else { + result.missingProperties = [olderHead]; + } + return result; +} +function compareObjectTypes(newerPropertyTypes, olderPropertyTypes) { + if (newerPropertyTypes.length === 0 && olderPropertyTypes.length === 0) { + return { + status: "matching", + }; + } + const sortedNewerTypes = []; + newerPropertyTypes.forEach((prop) => sortedNewerTypes.push(prop)); + if (sortedNewerTypes.length !== 0) { + sortedNewerTypes.sort(compareObjectTypeProperty); + } + const sortedOlderTypes = []; + olderPropertyTypes.forEach((prop) => sortedOlderTypes.push(prop)); + if (sortedOlderTypes.length !== 0) { + sortedOlderTypes.sort(compareObjectTypeProperty); + } + if (sortedNewerTypes.length === 0) { + return { + status: "properties", + propertyLog: { + missingProperties: sortedOlderTypes, + }, + }; + } + if (sortedOlderTypes.length === 0) { + return { + status: "properties", + propertyLog: { + addedProperties: sortedNewerTypes, + }, + }; + } + const result = comparePropertyArrays(sortedNewerTypes, sortedOlderTypes); + if ((0, _ComparisonResult.isPropertyLogEmpty)(result)) { + return { + status: "matching", + }; + } + if (result.errorProperties) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.propertyComparisonError)( + result.errorProperties.length > 1 + ? "Object contained properties with type mismatches" + : "Object contained a property with a type mismatch", + result.errorProperties + ) + ); + } + if ( + (result.addedProperties && + result.addedProperties.length > 0 && + result.addedProperties.length === newerPropertyTypes.length) || + (result.missingProperties && + result.missingProperties.length > 0 && + result.missingProperties.length === olderPropertyTypes.length) + ) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Object types do not match.", + objectTypeAnnotation(newerPropertyTypes), + objectTypeAnnotation(olderPropertyTypes) + ) + ); + } + return { + status: "properties", + propertyLog: result, + }; +} +function objectTypeAnnotation(properties) { + return { + type: "ObjectTypeAnnotation", + properties, + baseTypes: [], + }; +} +function compareEnumDeclarations(newerDeclaration, olderDeclaration) { + if (newerDeclaration.memberType !== olderDeclaration.memberType) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "EnumDeclaration member types are not the same", + newerDeclaration, + olderDeclaration + ) + ); + } + const newerAnnotationDefinition = lookupEnum( + newerDeclaration.name, + _newerEnumMap + ); + const olderAnnotationDefinition = lookupEnum( + olderDeclaration.name, + _olderEnumMap + ); + (0, _invariant.default)( + newerAnnotationDefinition != null && olderAnnotationDefinition != null, + "Could not find enum definition" + ); + return compareTypeAnnotation( + newerAnnotationDefinition, + olderAnnotationDefinition + ); +} +function compareEnumDeclarationMemberArrays(newer, older) { + if (newer.length === 0 && older.length === 0) { + return {}; + } else if (newer.length === 0) { + return { + missingMembers: older, + }; + } else if (older.length === 0) { + return { + addedMembers: newer, + }; + } + const newerHead = newer.pop(); + const olderHead = older.pop(); + (0, _invariant.default)( + newerHead != null && olderHead != null, + "Array is empty" + ); + const newerName = newerHead.name; + const olderName = olderHead.name; + if (newerName === olderName) { + const comparedTypes = compareTypeAnnotation( + newerHead.value, + olderHead.value + ); + const result = compareEnumDeclarationMemberArrays(newer, older); + switch (comparedTypes.status) { + case "matching": + return result; + case "error": + updateEnumMemberError( + newerName, + newerHead.value, + olderHead.value, + result + )(comparedTypes.errorLog); + return result; + case "skipped": + throw new Error( + "Internal error: returned 'skipped' for non-optional older type" + ); + case "nullableChange": + case "properties": + case "functionChange": + case "positionalTypeChange": + case "members": + break; + default: + throw new Error("Unsupported status " + comparedTypes.status); + } + } else if (newerName > olderName) { + older.push(olderHead); + const result = compareEnumDeclarationMemberArrays(newer, older); + if (result.hasOwnProperty("addedMembers") && result.addedMembers) { + result.addedMembers.push(newerHead); + } else { + result.addedMembers = [newerHead]; + } + return result; + } else if (newerName < olderName) { + newer.push(newerHead); + const result = compareEnumDeclarationMemberArrays(newer, older); + if (result.hasOwnProperty("missingMembers") && result.missingMembers) { + result.missingMembers.push(olderHead); + } else { + result.missingMembers = [olderHead]; + } + return result; + } + throw new Error("Internal error: should not reach here"); +} +function compareEnumDeclarationWithMembers(newerDeclaration, olderDeclaration) { + const sortedNewerTypes = Array.from(newerDeclaration.members).sort( + compareEnumMember + ); + const sortedOlderTypes = Array.from(olderDeclaration.members).sort( + compareEnumMember + ); + const result = compareEnumDeclarationMemberArrays( + sortedNewerTypes, + sortedOlderTypes + ); + if ((0, _ComparisonResult.isMemberLogEmpty)(result)) { + return { + status: "matching", + }; + } else if (result.errorMembers) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Enum types do not match", + newerDeclaration, + olderDeclaration, + (0, _ComparisonResult.memberComparisonError)( + result.errorMembers.length > 1 + ? "Enum contained members with type mismatches" + : "Enum contained a member with a type mismatch", + result.errorMembers + ) + ) + ); + } else if ( + (result.addedMembers && + result.addedMembers.length > 0 && + result.addedMembers.length === newerDeclaration.members.length) || + (result.missingMembers && + result.missingMembers.length > 0 && + result.missingMembers.length === olderDeclaration.members.length) + ) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Enum types do not match.", + newerDeclaration, + olderDeclaration + ) + ); + } + return { + status: "members", + memberLog: result, + }; +} +function compareNullableChange(newerAnnotation, olderAnnotation) { + const newVoidRemoved = + newerAnnotation.type === "NullableTypeAnnotation" + ? removeNullableTypeAnnotations(newerAnnotation) + : newerAnnotation; + const oldVoidRemoved = + olderAnnotation.type === "NullableTypeAnnotation" + ? removeNullableTypeAnnotations(olderAnnotation) + : olderAnnotation; + const optionalNew = newVoidRemoved.type !== newerAnnotation.type; + const optionalOld = oldVoidRemoved.type !== olderAnnotation.type; + (0, _invariant.default)( + optionalNew !== optionalOld, + "compareNullableChange called with both being nullable" + ); + const optionsReduced = !optionalNew && optionalOld; + if ( + newVoidRemoved.type === "VoidTypeAnnotation" || + oldVoidRemoved.type === "VoidTypeAnnotation" + ) { + return { + status: "nullableChange", + nullableLog: { + typeRefined: true, + optionsReduced, + interiorLog: null, + newType: newerAnnotation, + oldType: olderAnnotation, + }, + }; + } + const interiorLog = compareTypeAnnotation(newVoidRemoved, oldVoidRemoved); + switch (interiorLog.status) { + case "error": + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Type annotations are not the same.", + newerAnnotation, + olderAnnotation + ) + ); + case "matching": + return { + status: "nullableChange", + nullableLog: { + typeRefined: false, + optionsReduced, + interiorLog, + newType: newerAnnotation, + oldType: olderAnnotation, + }, + }; + default: + return { + status: "nullableChange", + nullableLog: { + typeRefined: false, + optionsReduced, + interiorLog, + newType: newerAnnotation, + oldType: olderAnnotation, + }, + }; + } +} +function compareUnionTypes(newerType, olderType) { + if (newerType.memberType !== olderType.memberType) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Union member type does not match", + newerType, + olderType + ) + ); + } + return { + status: "matching", + }; +} +function comparePromiseTypes(newerType, olderType) { + if (newerType.elementType == null || olderType.elementType == null) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Promise has differing arguments", + newerType, + olderType + ) + ); + } + (0, _invariant.default)( + newerType.elementType != null && olderType.elementType != null, + EQUALITY_MSG + ); + return compareTypeAnnotation(newerType.elementType, olderType.elementType); +} +function compareGenericObjectTypes(newerType, olderType) { + if ( + newerType.dictionaryValueType == null && + olderType.dictionaryValueType == null + ) { + return { + status: "matching", + }; + } + if ( + newerType.dictionaryValueType != null && + olderType.dictionaryValueType != null + ) { + return compareTypeAnnotation( + newerType.dictionaryValueType, + olderType.dictionaryValueType + ); + } + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Generic Object types do not have matching dictionary types", + newerType, + olderType + ) + ); +} +function compareNumberLiteralTypes(newerType, olderType) { + return newerType.value === olderType.value + ? { + status: "matching", + } + : (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Numeric literals are not equal", + newerType, + olderType + ) + ); +} +function compareStringLiteralTypes(newerType, olderType) { + return newerType.value === olderType.value + ? { + status: "matching", + } + : (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "String literals are not equal", + newerType, + olderType + ) + ); +} +function compareStringLiteralUnionTypes(newerType, olderType) { + const results = compareArrayOfTypes( + true, + false, + newerType.types, + olderType.types + ); + switch (results.status) { + case "length-mismatch": + throw new Error("length-mismatch returned with length changes allowed"); + case "type-mismatch": + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + `Subtype of union at position ${results.newIndex} did not match`, + newerType, + olderType, + results.error + ) + ); + case "subtypable-changes": + if (results.nestedChanges.length > 0) { + throw new Error( + "Unexpected inline objects/functions in string literal union" + ); + } + if (results.addedElements.length > 0) { + return { + status: "positionalTypeChange", + changeLog: { + typeKind: "stringUnion", + nestedChanges: [], + addedElements: results.addedElements, + }, + }; + } + if (results.removedElements.length > 0) { + return { + status: "positionalTypeChange", + changeLog: { + typeKind: "stringUnion", + nestedChanges: [], + removedElements: results.removedElements, + }, + }; + } + console.log(JSON.stringify(results)); + throw new Error("string union returned unexpected set of changes"); + case "matching": + return { + status: "matching", + }; + default: + throw new Error("Unknown status"); + } +} +function compareFunctionTypes(newerType, olderType) { + const returnTypeResult = compareTypeAnnotation( + newerType.returnTypeAnnotation, + olderType.returnTypeAnnotation + ); + if (returnTypeResult.status === "error") { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Function return types do not match", + newerType, + olderType, + returnTypeResult.errorLog + ) + ); + } + const functionChanges = {}; + if ( + returnTypeResult.status === "properties" || + returnTypeResult.status === "members" || + returnTypeResult.status === "functionChange" || + returnTypeResult.status === "positionalTypeChange" || + returnTypeResult.status === "nullableChange" + ) { + functionChanges.returnType = returnTypeResult; + } + const argumentResults = compareArrayOfTypes( + true, + true, + newerType.params.map((_) => _.typeAnnotation), + olderType.params.map((_) => _.typeAnnotation) + ); + switch (argumentResults.status) { + case "length-mismatch": + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Function types have differing length of arguments", + newerType, + olderType + ) + ); + case "type-mismatch": + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + `Parameter at index ${argumentResults.newIndex} did not match`, + newerType, + olderType, + argumentResults.error + ) + ); + case "subtypable-changes": + functionChanges.parameterTypes = { + typeKind: "parameter", + nestedChanges: argumentResults.nestedChanges, + }; + break; + case "matching": + default: + break; + } + if ((0, _ComparisonResult.isFunctionLogEmpty)(functionChanges)) { + return { + status: "matching", + }; + } + return { + status: "functionChange", + functionChangeLog: functionChanges, + }; +} +function compareArrayOfTypes(fixedOrder, fixedLength, newerTypes, olderTypes) { + const sameLength = newerTypes.length === olderTypes.length; + if (fixedLength && !sameLength) { + return { + status: "length-mismatch", + }; + } + const nestedChanges = []; + const minLength = Math.min(newerTypes.length, olderTypes.length); + if (fixedOrder) { + for (let i = 0; i < minLength; i++) { + const result = compareTypeAnnotation(newerTypes[i], olderTypes[i]); + if (result.status === "error") { + return { + status: "type-mismatch", + error: result.errorLog, + newIndex: i, + oldIndex: i, + }; + } + if ( + result.status === "properties" || + result.status === "members" || + result.status === "functionChange" || + result.status === "positionalTypeChange" || + result.status === "nullableChange" + ) { + nestedChanges.push([i, i, result]); + } + } + if (nestedChanges.length === 0 && sameLength) { + return { + status: "matching", + }; + } + const addedElements = []; + const removedElements = []; + if (newerTypes.length < olderTypes.length) { + const elements = olderTypes.slice(minLength, olderTypes.length); + for (let i = 0; i < elements.length; i++) { + removedElements.push([i + minLength + 1, elements[i]]); + } + } + if (newerTypes.length > olderTypes.length) { + const elements = newerTypes.slice(minLength, newerTypes.length); + for (let i = 0; i < elements.length; i++) { + addedElements.push([i + minLength + 1, elements[i]]); + } + } + return { + status: "subtypable-changes", + nestedChanges, + addedElements, + removedElements, + }; + } + return compareArrayTypesOutOfOrder( + (0, _SortTypeAnnotations.sortTypeAnnotations)(newerTypes), + 0, + (0, _SortTypeAnnotations.sortTypeAnnotations)(olderTypes), + 0, + [], + [], + [] + ); +} +function compareArrayTypesOutOfOrder( + newerTypes, + newerIndex, + olderTypes, + olderIndex, + potentiallyAddedElements, + potentiallyRemovedElements, + nestedChanges +) { + const newLength = newerTypes.length; + const oldLength = olderTypes.length; + if (newerIndex === newLength || olderIndex === oldLength) { + const [errors, added, removed] = resolvePotentials( + potentiallyAddedElements, + potentiallyRemovedElements + ); + if (errors.length !== 0) { + return { + status: "type-mismatch", + error: errors[0][0], + oldIndex: errors[0][1], + newIndex: errors[0][2], + }; + } + if ( + added.length === 0 && + removed.length === 0 && + nestedChanges.length === 0 && + newerIndex === newLength && + olderIndex === oldLength + ) { + return { + status: "matching", + }; + } + if (newerIndex === newLength && olderIndex === oldLength) { + return { + status: "subtypable-changes", + nestedChanges, + addedElements: added, + removedElements: removed, + }; + } + if (newerIndex === newLength) { + return { + status: "subtypable-changes", + nestedChanges, + addedElements: added, + removedElements: removed.concat( + olderTypes.slice(olderIndex, oldLength) + ), + }; + } + return { + status: "subtypable-changes", + nestedChanges, + addedElements: added.concat(newerTypes.slice(newerIndex, newLength)), + removedElements: removed, + }; + } + const newTypePosn = newerTypes[newerIndex][0]; + const newType = newerTypes[newerIndex][1]; + const oldTypePosn = olderTypes[olderIndex][0]; + const oldType = olderTypes[olderIndex][1]; + const currentResult = compareTypeAnnotation(newType, oldType); + const sortComparison = (0, + _SortTypeAnnotations.compareTypeAnnotationForSorting)( + newerTypes[newerIndex], + olderTypes[olderIndex] + ); + switch (currentResult.status) { + case "matching": + return compareArrayTypesOutOfOrder( + newerTypes, + newerIndex + 1, + olderTypes, + olderIndex + 1, + potentiallyAddedElements, + potentiallyRemovedElements, + nestedChanges + ); + case "properties": + case "functionChange": + case "positionalTypeChange": + case "nullableChange": + return compareArrayTypesOutOfOrder( + newerTypes, + newerIndex + 1, + olderTypes, + olderIndex + 1, + potentiallyAddedElements, + potentiallyRemovedElements, + nestedChanges.concat[[oldTypePosn, newTypePosn, currentResult]] + ); + case "error": + if (sortComparison === 0) { + return { + status: "type-mismatch", + error: currentResult.errorLog, + newIndex: newTypePosn, + oldIndex: oldTypePosn, + }; + } + if (sortComparison < 0) { + return compareArrayTypesOutOfOrder( + newerTypes, + newerIndex + 1, + olderTypes, + olderIndex, + potentiallyAddedElements.concat([ + { + olderPosition: oldTypePosn, + newerPosition: newTypePosn, + error: currentResult.errorLog, + annotation: newType, + }, + ]), + potentiallyRemovedElements, + nestedChanges + ); + } + return compareArrayTypesOutOfOrder( + newerTypes, + newerIndex, + olderTypes, + olderIndex + 1, + potentiallyAddedElements, + potentiallyRemovedElements.concat([ + { + olderPosition: oldTypePosn, + newerPosition: newTypePosn, + error: currentResult.errorLog, + annotation: oldType, + }, + ]), + nestedChanges + ); + case "skipped": + throw new Error( + "Unexpected skipped status for array of type annotations" + ); + default: + throw new Error("Unsupported status " + currentResult.status); + } +} +function resolvePotentials(potentiallyAdded, potentiallyRemoved) { + const addedLength = potentiallyAdded.length; + const removedLength = potentiallyRemoved.length; + if (addedLength === 0 && removedLength === 0) { + return [[], [], []]; + } + if (addedLength === 0) { + return [ + [], + [], + potentiallyRemoved.map((removed) => [ + removed.olderPosition, + removed.annotation, + ]), + ]; + } + if (removedLength === 0) { + return [ + [], + potentiallyAdded.map((added) => [added.newerPosition, added.annotation]), + [], + ]; + } + const addedHead = potentiallyAdded[0]; + const removedHead = potentiallyRemoved[0]; + if (addedHead.olderPosition === removedHead.olderPosition) { + return [ + [[addedHead.error, addedHead.olderPosition, addedHead.newerPosition]], + [], + [], + ]; + } + if (removedHead.newerPosition === addedHead.newerPosition) { + return [ + [ + [ + removedHead.error, + removedHead.olderPosition, + removedHead.newerPosition, + ], + ], + [], + [], + ]; + } + const sortedOrder = (0, _SortTypeAnnotations.compareTypeAnnotationForSorting)( + [addedHead.newerPosition, addedHead.annotation], + [removedHead.olderPosition, removedHead.annotation] + ); + if (sortedOrder === 0) { + const [errors, added, removed] = resolvePotentials( + potentiallyAdded.slice(1, addedLength), + potentiallyRemoved.slice(1, removedLength) + ); + return [ + errors, + added.concat([[addedHead.newerPosition, addedHead.annotation]]), + removed.concat([[removedHead.olderPosition, removedHead.annotation]]), + ]; + } + if (sortedOrder < 0) { + const [errors, added, removed] = resolvePotentials( + potentiallyAdded.slice(1, addedLength), + potentiallyRemoved + ); + return [ + errors, + added.concat([[addedHead.newerPosition, addedHead.annotation]]), + removed, + ]; + } + const [errors, added, removed] = resolvePotentials( + potentiallyAdded, + potentiallyRemoved.slice(1, removedLength) + ); + return [ + errors, + added, + removed.concat([[removedHead.olderPosition, removedHead.annotation]]), + ]; +} +function compareEventEmitterTypes(newerAnnotation, olderAnnotation) { + const comparison = compareTypeAnnotation( + newerAnnotation.typeAnnotation, + olderAnnotation.typeAnnotation + ); + if (comparison.status === "error") { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "EventEmitter eventTypes are not equivalent", + newerAnnotation, + olderAnnotation, + comparison.errorLog + ) + ); + } + return comparison; +} +function compareReservedTypeAnnotation(newerAnnotation, olderAnnotation) { + if (newerAnnotation.name !== olderAnnotation.name) { + return (0, _ComparisonResult.makeError)( + (0, _ComparisonResult.typeAnnotationComparisonError)( + "Types are not equivalent", + newerAnnotation, + olderAnnotation + ) + ); + } + switch (newerAnnotation.name) { + case "RootTag": + case "ColorPrimitive": + case "ImageSourcePrimitive": + case "PointPrimitive": + case "EdgeInsetsPrimitive": + case "ImageRequestPrimitive": + case "DimensionPrimitive": + return { + status: "matching", + }; + default: + newerAnnotation.name; + throw new Error("Unknown reserved type " + newerAnnotation.name); + } +} diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow b/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow new file mode 100644 index 00000000000000..4b444655e0ad69 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow @@ -0,0 +1,99 @@ +/** + * 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 { + ComparisonResult, + MembersComparisonResult, +} from "./ComparisonResult"; +import type { + CompleteTypeAnnotation, + NamedShape, + NativeModuleAliasMap, + NativeModuleEnumDeclaration, + NativeModuleEnumDeclarationWithMembers, + NativeModuleEnumMap, + NativeModuleEnumMember, + NativeModuleFunctionTypeAnnotation, + NativeModuleGenericObjectTypeAnnotation, + NativeModulePromiseTypeAnnotation, + NativeModuleUnionTypeAnnotation, + NumberLiteralTypeAnnotation, + StringLiteralTypeAnnotation, + StringLiteralUnionTypeAnnotation, +} from "@react-native/codegen/src/CodegenSchema"; + +declare export function compareTypes( + newerType: CompleteTypeAnnotation, + olderType: ?CompleteTypeAnnotation, + newerTypesReg: ?NativeModuleAliasMap, + olderTypesReg: ?NativeModuleAliasMap, + newerEnumMap: ?NativeModuleEnumMap, + olderEnumMap: ?NativeModuleEnumMap +): ComparisonResult; + +declare export function compareTypeAnnotation( + originalNewerAnnotation: CompleteTypeAnnotation, + originalOlderAnnotation: CompleteTypeAnnotation +): ComparisonResult; + +declare export function compareObjectTypes( + newerPropertyTypes: $ReadOnlyArray>, + olderPropertyTypes: $ReadOnlyArray> +): ComparisonResult; + +declare export function compareEnumDeclarations( + newerDeclaration: NativeModuleEnumDeclaration, + olderDeclaration: NativeModuleEnumDeclaration +): ComparisonResult; + +declare export function compareEnumDeclarationMemberArrays( + newer: Array, + older: Array +): MembersComparisonResult; + +declare export function compareEnumDeclarationWithMembers( + newerDeclaration: NativeModuleEnumDeclarationWithMembers, + olderDeclaration: NativeModuleEnumDeclarationWithMembers +): ComparisonResult; + +declare export function compareUnionTypes( + newerType: NativeModuleUnionTypeAnnotation, + olderType: NativeModuleUnionTypeAnnotation +): ComparisonResult; + +declare export function comparePromiseTypes( + newerType: NativeModulePromiseTypeAnnotation, + olderType: NativeModulePromiseTypeAnnotation +): ComparisonResult; + +declare export function compareGenericObjectTypes( + newerType: NativeModuleGenericObjectTypeAnnotation, + olderType: NativeModuleGenericObjectTypeAnnotation +): ComparisonResult; + +declare export function compareNumberLiteralTypes( + newerType: NumberLiteralTypeAnnotation, + olderType: NumberLiteralTypeAnnotation +): ComparisonResult; + +declare export function compareStringLiteralTypes( + newerType: StringLiteralTypeAnnotation, + olderType: StringLiteralTypeAnnotation +): ComparisonResult; + +declare export function compareStringLiteralUnionTypes( + newerType: StringLiteralUnionTypeAnnotation, + olderType: StringLiteralUnionTypeAnnotation +): ComparisonResult; + +declare export function compareFunctionTypes( + newerType: NativeModuleFunctionTypeAnnotation, + olderType: NativeModuleFunctionTypeAnnotation +): ComparisonResult; diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts b/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts new file mode 100644 index 00000000000000..b02067659e3ecc --- /dev/null +++ b/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts @@ -0,0 +1,59 @@ +/** + * 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 + */ + +import type { ComparisonResult } from "./ComparisonResult"; +import type { + DiffSet, + DiffSummary, + ErrorStore, + ObjectTypeChangeStore, + SchemaDiff, +} from "./DiffResults"; +import type { + CompleteTypeAnnotation, + SchemaType, +} from "@react-native/codegen/src/CodegenSchema"; +type BoundaryDirection = "toNative" | "fromNative" | "both"; +export declare const removedPropertiesMessage: "Object removed required properties expected by native"; +export declare const addedPropertiesMessage: "Object added required properties, which native will not provide"; +export declare const stricterPropertiesMessage: "Property made strict, but native may not provide it"; +export declare const tooOptionalPropertiesMessage: "Property made optional, but native requires it"; +export declare const removedUnionMessage: "Union removed items, but native may still provide them"; +export declare const addedUnionMessage: "Union added items, but native will not expect/support them"; +export declare const removedEnumMessage: "Enum removed items, but native may still provide them"; +export declare const addedEnumMessage: "Enum added items, but native will not expect/support them"; +export declare const removedIntersectionMessage: "Intersection removed items, but native may still require properties contained in them"; +export declare const addedIntersectionMessage: "Intersection added items, but native may not provide all required attributes"; +export declare const toNativeVoidChangeMessage: "Native may not be able to safely handle presence of type"; +export declare const typeNullableChangeMessage: "Type made nullable, but native requires it"; +export declare const fromNativeVoidChangeMessage: "Type set to void but native may still provide a value"; +export declare const typeNonNullableChangeMessage: "Type made non-nullable, but native might provide null still"; +export declare function assessComparisonResult( + newTypes: Set<{ typeName: string; typeInformation: CompleteTypeAnnotation }>, + deprecatedTypes: Set<{ + typeName: string; + typeInformation: CompleteTypeAnnotation; + }>, + incompatibleChanges: Set, + objectTypeChanges: Set +): ( + typeName: string, + newType: CompleteTypeAnnotation, + oldType: null | undefined | CompleteTypeAnnotation, + difference: ComparisonResult, + oldDirection: BoundaryDirection +) => void; +export declare function hasUpdatesTypes(diff: DiffSet): boolean; +export declare function hasCodegenUpdatesTypes(diff: DiffSet): boolean; +export declare function buildSchemaDiff( + newerSchemaSet: SchemaType, + olderSchemaSet: SchemaType +): Set; +export declare function summarizeDiffSet(diffs: Set): DiffSummary; diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.js b/packages/react-native-compatibility-check/dist/VersionDiffing.js new file mode 100644 index 00000000000000..4eb67d770f9d94 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/VersionDiffing.js @@ -0,0 +1,1235 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.addedUnionMessage = + exports.addedPropertiesMessage = + exports.addedIntersectionMessage = + exports.addedEnumMessage = + void 0; +exports.assessComparisonResult = assessComparisonResult; +exports.buildSchemaDiff = buildSchemaDiff; +exports.fromNativeVoidChangeMessage = void 0; +exports.hasCodegenUpdatesTypes = hasCodegenUpdatesTypes; +exports.hasUpdatesTypes = hasUpdatesTypes; +exports.stricterPropertiesMessage = + exports.removedUnionMessage = + exports.removedPropertiesMessage = + exports.removedIntersectionMessage = + exports.removedEnumMessage = + void 0; +exports.summarizeDiffSet = summarizeDiffSet; +exports.typeNullableChangeMessage = + exports.typeNonNullableChangeMessage = + exports.tooOptionalPropertiesMessage = + exports.toNativeVoidChangeMessage = + void 0; +var _ComparisonResult = require("./ComparisonResult.js"); +var _convertPropToBasicTypes = _interopRequireDefault( + require("./convertPropToBasicTypes") +); +var codegenTypeDiffing = _interopRequireWildcard(require("./TypeDiffing")); +function _getRequireWildcardCache(e) { + if ("function" != typeof WeakMap) return null; + var r = new WeakMap(), + t = new WeakMap(); + return (_getRequireWildcardCache = function (e) { + return e ? t : r; + })(e); +} +function _interopRequireWildcard(e, r) { + if (!r && e && e.__esModule) return e; + if (null === e || ("object" != typeof e && "function" != typeof e)) + return { default: e }; + var t = _getRequireWildcardCache(r); + if (t && t.has(e)) return t.get(e); + var n = { __proto__: null }, + a = Object.defineProperty && Object.getOwnPropertyDescriptor; + for (var u in e) + if ("default" !== u && {}.hasOwnProperty.call(e, u)) { + var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; + i && (i.get || i.set) ? Object.defineProperty(n, u, i) : (n[u] = e[u]); + } + return (n.default = e), t && t.set(e, n), n; +} +function _interopRequireDefault(e) { + return e && e.__esModule ? e : { default: e }; +} +function nestedPropertiesCheck(typeName, result, check, inverseCheck) { + const nestedMap = + (mid, end) => + ([propertyName, comparisonResult]) => + nestedPropertiesCheck( + typeName + mid + propertyName + end, + comparisonResult, + check, + inverseCheck + ); + switch (result.status) { + case "error": + case "matching": + case "skipped": + throw new Error( + "Internal error: nested property change " + result.status + ); + case "properties": + let finalResult = check(result.propertyLog, null, null, null, typeName); + if (result.propertyLog.nestedPropertyChanges) { + finalResult = combine( + finalResult, + result.propertyLog.nestedPropertyChanges.map(nestedMap(".", "")) + ); + } + if (result.propertyLog.madeOptional) { + const furtherNestedProps = result.propertyLog.madeOptional.filter( + (optionalProp) => optionalProp.furtherChanges + ); + if (furtherNestedProps && furtherNestedProps.length > 0) { + const localNestedMap = nestedMap(".", ""); + const mappedProps = furtherNestedProps.map((optionalProp) => { + if (optionalProp.furtherChanges) { + return localNestedMap([ + optionalProp.property, + optionalProp.furtherChanges, + ]); + } + throw new Error("Internal error, filter failed"); + }); + finalResult = combine(finalResult, mappedProps); + } + } + return finalResult; + case "members": + return check(null, null, null, result.memberLog, typeName); + case "functionChange": + let returnTypeResult = []; + if (result.functionChangeLog.returnType) { + returnTypeResult = nestedPropertiesCheck( + typeName, + result.functionChangeLog.returnType, + check, + inverseCheck + ); + } + if (result.functionChangeLog.parameterTypes) { + return combine( + returnTypeResult, + result.functionChangeLog.parameterTypes.nestedChanges.map( + ([_oldParameterNumber, newParameterNumber, comparisonResult]) => + nestedPropertiesCheck( + typeName + " parameter " + newParameterNumber, + comparisonResult, + inverseCheck, + check + ) + ) + ); + } + return returnTypeResult; + case "positionalTypeChange": + const changeLog = result.changeLog; + const currentPositionalCheck = check( + null, + changeLog, + null, + null, + typeName + ); + return combine( + currentPositionalCheck, + changeLog.nestedChanges.map(([_oldIndex, newIndex, nestedChange]) => + nestedMap( + " element ", + " of " + changeLog.typeKind + )([newIndex.toString(), nestedChange]) + ) + ); + case "nullableChange": + const currentCheck = check( + null, + null, + result.nullableLog, + null, + typeName + ); + if (result.nullableLog.interiorLog) { + const interiorLog = result.nullableLog.interiorLog; + switch (interiorLog.status) { + case "matching": + return currentCheck; + case "properties": + case "functionChange": + case "positionalTypeChange": + case "nullableChange": + return combine(currentCheck, [ + nestedPropertiesCheck(typeName, interiorLog, check, inverseCheck), + ]); + default: + throw new Error( + "Internal error: nested with error or skipped status" + ); + } + } + return currentCheck; + default: + result.status; + return []; + } +} +function checkOptionalityAndSetError(typeName, properties, msg, errorCode) { + const requiredProperties = properties.filter( + (objectTypeProperty) => !objectTypeProperty.optional + ); + if (requiredProperties.length > 0) { + return [ + { + typeName, + errorCode, + errorInformation: (0, _ComparisonResult.propertyComparisonError)( + msg, + requiredProperties.map((property) => ({ + property: property.name, + })) + ), + }, + ]; + } + return []; +} +const removedPropertiesMessage = (exports.removedPropertiesMessage = + "Object removed required properties expected by native"); +function checkForUnsafeRemovedProperties( + propertyChange, + _postionalChange, + _nullableChange, + _memberChange, + typeName +) { + if (propertyChange && propertyChange.missingProperties) { + return checkOptionalityAndSetError( + typeName, + propertyChange.missingProperties, + removedPropertiesMessage, + "removedProps" + ); + } + return []; +} +const addedPropertiesMessage = (exports.addedPropertiesMessage = + "Object added required properties, which native will not provide"); +function checkForUnsafeAddedProperties( + propertyChange, + _positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if (propertyChange && propertyChange.addedProperties) { + return checkOptionalityAndSetError( + typeName, + propertyChange.addedProperties, + addedPropertiesMessage, + "addedProps" + ); + } + return []; +} +const stricterPropertiesMessage = (exports.stricterPropertiesMessage = + "Property made strict, but native may not provide it"); +function checkForUnSafeMadeStrictProperties( + propertyChange, + _positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + propertyChange && + propertyChange.madeStrict && + propertyChange.madeStrict.length > 0 + ) { + const err = (0, _ComparisonResult.propertyComparisonError)( + stricterPropertiesMessage, + propertyChange.madeStrict.map((property) => ({ + property: property.property, + })) + ); + return [ + { + typeName, + errorCode: "requiredProps", + errorInformation: err, + }, + ]; + } + return []; +} +const tooOptionalPropertiesMessage = (exports.tooOptionalPropertiesMessage = + "Property made optional, but native requires it"); +function checkForUnSafeMadeOptionalProperties( + propertyChange, + _positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + propertyChange && + propertyChange.madeOptional && + propertyChange.madeOptional.length > 0 + ) { + const err = (0, _ComparisonResult.propertyComparisonError)( + tooOptionalPropertiesMessage, + propertyChange.madeOptional.map((property) => ({ + property: property.property, + })) + ); + return [ + { + typeName, + errorCode: "optionalProps", + errorInformation: err, + }, + ]; + } + return []; +} +const removedUnionMessage = (exports.removedUnionMessage = + "Union removed items, but native may still provide them"); +function checkForUnsafeRemovedUnionItems( + _propertyChange, + positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + positionalChange && + (positionalChange.typeKind === "union" || + positionalChange.typeKind === "stringUnion") && + positionalChange.removedElements && + positionalChange.removedElements.length > 0 + ) { + return [ + { + typeName, + errorCode: "removedUnionCases", + errorInformation: (0, _ComparisonResult.positionalComparisonError)( + removedUnionMessage, + positionalChange.removedElements + ), + }, + ]; + } + return []; +} +const addedUnionMessage = (exports.addedUnionMessage = + "Union added items, but native will not expect/support them"); +function checkForUnsafeAddedUnionItems( + _propertyChange, + positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + positionalChange && + (positionalChange.typeKind === "union" || + positionalChange.typeKind === "stringUnion") && + positionalChange.addedElements && + positionalChange.addedElements.length > 0 + ) { + return [ + { + typeName, + errorCode: "addedUnionCases", + errorInformation: (0, _ComparisonResult.positionalComparisonError)( + addedUnionMessage, + positionalChange.addedElements + ), + }, + ]; + } + return []; +} +const removedEnumMessage = (exports.removedEnumMessage = + "Enum removed items, but native may still provide them"); +function checkForUnsafeRemovedEnumItems( + _propertyChange, + _positionalChange, + _nullableChange, + memberChange, + typeName +) { + if (memberChange?.missingMembers && memberChange?.missingMembers.length > 0) { + return [ + { + typeName, + errorCode: "removedEnumCases", + errorInformation: (0, _ComparisonResult.memberComparisonError)( + removedEnumMessage, + memberChange.missingMembers.map((member) => ({ + member: member.name, + })) + ), + }, + ]; + } + return []; +} +const addedEnumMessage = (exports.addedEnumMessage = + "Enum added items, but native will not expect/support them"); +function checkForUnsafeAddedEnumItems( + _propertyChange, + _positionalChange, + _nullableChange, + memberChange, + typeName +) { + if (memberChange?.addedMembers && memberChange?.addedMembers.length > 0) { + return [ + { + typeName, + errorCode: "addedEnumCases", + errorInformation: (0, _ComparisonResult.memberComparisonError)( + addedEnumMessage, + memberChange.addedMembers.map((member) => ({ + member: member.name, + })) + ), + }, + ]; + } + return []; +} +const removedIntersectionMessage = (exports.removedIntersectionMessage = + "Intersection removed items, but native may still require properties contained in them"); +function checkForUnsafeRemovedIntersectionItems( + _propertyChange, + positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + positionalChange && + positionalChange.typeKind === "intersection" && + positionalChange.removedElements && + positionalChange.removedElements.length > 0 + ) { + return [ + { + typeName, + errorCode: "removedIntersectCases", + errorInformation: (0, _ComparisonResult.positionalComparisonError)( + removedIntersectionMessage, + positionalChange.removedElements + ), + }, + ]; + } + return []; +} +const addedIntersectionMessage = (exports.addedIntersectionMessage = + "Intersection added items, but native may not provide all required attributes"); +function checkForUnsafeAddedIntersectionItems( + _propertyChange, + positionalChange, + _nullableChange, + _memberChange, + typeName +) { + if ( + positionalChange && + positionalChange.typeKind === "intersection" && + positionalChange.addedElements && + positionalChange.addedElements.length > 0 + ) { + return [ + { + typeName, + errorCode: "addedIntersectCases", + errorInformation: (0, _ComparisonResult.positionalComparisonError)( + addedIntersectionMessage, + positionalChange.addedElements + ), + }, + ]; + } + return []; +} +const toNativeVoidChangeMessage = (exports.toNativeVoidChangeMessage = + "Native may not be able to safely handle presence of type"); +const typeNullableChangeMessage = (exports.typeNullableChangeMessage = + "Type made nullable, but native requires it"); +function checkForUnsafeNullableToNativeChange( + _propertyChange, + _positionalChange, + nullableChange, + _memberChange, + typeName +) { + if ( + nullableChange && + !nullableChange.optionsReduced && + nullableChange.newType && + nullableChange.oldType + ) { + return [ + { + typeName, + errorCode: "nullableOfNonNull", + errorInformation: (0, _ComparisonResult.typeAnnotationComparisonError)( + nullableChange.typeRefined + ? toNativeVoidChangeMessage + : typeNullableChangeMessage, + nullableChange.newType, + nullableChange.oldType + ), + }, + ]; + } + return []; +} +const fromNativeVoidChangeMessage = (exports.fromNativeVoidChangeMessage = + "Type set to void but native may still provide a value"); +const typeNonNullableChangeMessage = (exports.typeNonNullableChangeMessage = + "Type made non-nullable, but native might provide null still"); +function checkForUnsafeNullableFromNativeChange( + _propertyChange, + _positionalChange, + nullableChange, + _memberChange, + typeName +) { + if ( + nullableChange && + nullableChange.optionsReduced && + nullableChange.newType && + nullableChange.oldType + ) { + return [ + { + typeName, + errorCode: "nonNullableOfNull", + errorInformation: (0, _ComparisonResult.typeAnnotationComparisonError)( + nullableChange.typeRefined + ? fromNativeVoidChangeMessage + : typeNonNullableChangeMessage, + nullableChange.newType, + nullableChange.oldType + ), + }, + ]; + } + return []; +} +function chainPropertiesChecks(checks) { + return ( + propertyChange, + positionalChange, + nullableChange, + memberChange, + typeName + ) => + checks.reduce( + (errorStore, checker) => + errorStore.concat( + checker( + propertyChange, + positionalChange, + nullableChange, + memberChange, + typeName + ) + ), + [] + ); +} +function combine(singleton, arrayOf) { + if (arrayOf.length > 0) { + return arrayOf.reduce( + (finalErrorArray, current) => finalErrorArray.concat(current), + singleton + ); + } + return singleton; +} +function compareFunctionTypesInContext( + typeName, + functionLog, + check, + inversecheck, + result +) { + if (functionLog.returnType) { + result = combine(result, [ + nestedPropertiesCheck( + typeName, + functionLog.returnType, + check, + inversecheck + ), + ]); + } + if ( + functionLog.parameterTypes && + functionLog.parameterTypes.nestedChanges.length > 0 + ) { + result = combine( + result, + functionLog.parameterTypes.nestedChanges.map( + ([_oldPropertyNum, newPropertyNum, comparisonResult]) => + nestedPropertiesCheck( + typeName + " parameter " + newPropertyNum, + comparisonResult, + inversecheck, + check + ) + ) + ); + } + return result; +} +const checksForTypesFlowingToNative = chainPropertiesChecks([ + checkForUnsafeRemovedProperties, + checkForUnSafeMadeOptionalProperties, + checkForUnsafeAddedUnionItems, + checkForUnsafeAddedEnumItems, + checkForUnsafeRemovedIntersectionItems, + checkForUnsafeNullableToNativeChange, +]); +const checksForTypesFlowingFromNative = chainPropertiesChecks([ + checkForUnsafeAddedProperties, + checkForUnSafeMadeStrictProperties, + checkForUnsafeRemovedUnionItems, + checkForUnsafeRemovedEnumItems, + checkForUnsafeAddedIntersectionItems, + checkForUnsafeNullableFromNativeChange, +]); +function assessComparisonResult( + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges +) { + return (typeName, newType, oldType, difference, oldDirection) => { + switch (difference.status) { + case "matching": + break; + case "skipped": + newTypes.add({ + typeName, + typeInformation: newType, + }); + break; + case "members": + { + const memberChange = difference.memberLog; + const toNativeErrorResult = checksForTypesFlowingToNative( + null, + null, + null, + memberChange, + typeName + ); + const fromNativeErrorResult = checksForTypesFlowingFromNative( + null, + null, + null, + memberChange, + typeName + ); + switch (oldDirection) { + case "toNative": + toNativeErrorResult.forEach((error) => + incompatibleChanges.add(error) + ); + break; + case "fromNative": + fromNativeErrorResult.forEach((error) => + incompatibleChanges.add(error) + ); + break; + case "both": + toNativeErrorResult.forEach((error) => + incompatibleChanges.add(error) + ); + fromNativeErrorResult.forEach((error) => + incompatibleChanges.add(error) + ); + break; + } + } + break; + case "properties": + const propertyChange = difference.propertyLog; + const unsafeForToNative = nestedPropertiesCheck( + typeName, + difference, + checksForTypesFlowingToNative, + checksForTypesFlowingFromNative + ); + const unsafeForFromNative = nestedPropertiesCheck( + typeName, + difference, + checksForTypesFlowingFromNative, + checksForTypesFlowingToNative + ); + switch (oldDirection) { + case "toNative": + unsafeForToNative.forEach((error) => + incompatibleChanges.add(error) + ); + break; + case "fromNative": + unsafeForFromNative.forEach((error) => + incompatibleChanges.add(error) + ); + break; + case "both": + unsafeForToNative.forEach((error) => + incompatibleChanges.add(error) + ); + unsafeForFromNative.forEach((error) => + incompatibleChanges.add(error) + ); + break; + } + if (!oldType) { + throw new Error("Internal error: properties change with no old type"); + } + objectTypeChanges.add({ + typeName, + newType, + oldType, + propertyChange, + }); + break; + case "error": + incompatibleChanges.add({ + typeName, + errorCode: "incompatibleTypes", + errorInformation: difference.errorLog, + }); + break; + case "functionChange": + const functionLog = difference.functionChangeLog; + let propertyErrors = []; + switch (oldDirection) { + case "toNative": + propertyErrors = compareFunctionTypesInContext( + typeName, + functionLog, + checksForTypesFlowingToNative, + checksForTypesFlowingFromNative, + propertyErrors + ); + break; + case "fromNative": + propertyErrors = compareFunctionTypesInContext( + typeName, + functionLog, + checksForTypesFlowingFromNative, + checksForTypesFlowingToNative, + propertyErrors + ); + break; + case "both": + propertyErrors = compareFunctionTypesInContext( + typeName, + functionLog, + checksForTypesFlowingToNative, + checksForTypesFlowingFromNative, + propertyErrors + ); + propertyErrors = compareFunctionTypesInContext( + typeName, + functionLog, + checksForTypesFlowingFromNative, + checksForTypesFlowingToNative, + propertyErrors + ); + break; + default: + throw new Error( + "Unsupported native boundary direction " + oldDirection + ); + } + propertyErrors.forEach((error) => incompatibleChanges.add(error)); + break; + case "positionalTypeChange": + const changeLog = difference.changeLog; + if ( + changeLog.nestedChanges.length > 0 || + changeLog.addedElements || + changeLog.removedElements + ) { + const changes = changeLog.nestedChanges; + const toNativeBase = checksForTypesFlowingToNative( + null, + changeLog, + null, + null, + typeName + ); + const toNativeResult = combine( + toNativeBase, + changes.map(([_oldIndex, newIndex, comparisonResult]) => + nestedPropertiesCheck( + `${typeName} element ${newIndex} of ${changeLog.typeKind}`, + comparisonResult, + checksForTypesFlowingToNative, + checksForTypesFlowingFromNative + ) + ) + ); + const fromNativeBase = checksForTypesFlowingFromNative( + null, + changeLog, + null, + null, + typeName + ); + const fromNativeResult = combine( + fromNativeBase, + changes.map(([_oldIndex, newIndex, comparisonResult]) => + nestedPropertiesCheck( + `${typeName} element ${newIndex} of ${changeLog.typeKind}`, + comparisonResult, + checksForTypesFlowingFromNative, + checksForTypesFlowingToNative + ) + ) + ); + switch (oldDirection) { + case "toNative": + toNativeResult.forEach((error) => incompatibleChanges.add(error)); + break; + case "fromNative": + fromNativeResult.forEach((error) => + incompatibleChanges.add(error) + ); + break; + case "both": + toNativeResult.forEach((error) => incompatibleChanges.add(error)); + fromNativeResult.forEach((error) => + incompatibleChanges.add(error) + ); + break; + } + } + break; + case "nullableChange": + if (!oldType) { + throw new Error( + "Internal error: old type null or undefined, after nullableChange" + ); + } + switch (oldDirection) { + case "toNative": + checkForUnsafeNullableToNativeChange( + null, + null, + difference.nullableLog, + null, + typeName + ).forEach((error) => incompatibleChanges.add(error)); + break; + case "fromNative": + checkForUnsafeNullableFromNativeChange( + null, + null, + difference.nullableLog, + null, + typeName + ).forEach((error) => incompatibleChanges.add(error)); + break; + case "both": + const err = (0, _ComparisonResult.typeInformationComparisonError)( + "Type may not change nullability, due to flowing to and from native", + newType, + oldType + ); + incompatibleChanges.add({ + typeName, + errorCode: "incompatibleTypes", + errorInformation: err, + }); + break; + default: + throw new Error("Unknown direction : " + oldDirection); + } + if (difference.interiorLog) { + const log = difference.interiorLog; + assessComparisonResult( + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges + )(typeName, newType, oldType, log, oldDirection); + } + break; + default: + difference.status; + throw new Error("Unsupported status: " + difference.status); + } + }; +} +function buildNativeModulesDiff(newerNativeModule, olderNativeModule) { + const moduleErrors = new Set(); + const nativeModuleName = newerNativeModule.moduleName; + if (olderNativeModule.moduleName !== newerNativeModule.moduleName) { + moduleErrors.add({ + nativeSpecName: olderNativeModule.moduleName, + omitted: true, + errorCode: "removedModule", + }); + } + const newTypes = new Set(); + const deprecatedTypes = new Set(); + const incompatibleChanges = new Set(); + const objectTypeChanges = new Set(); + const localAssessComparison = assessComparisonResult( + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges + ); + const newType = { + type: "ObjectTypeAnnotation", + properties: [ + ...newerNativeModule.spec.methods, + ...newerNativeModule.spec.eventEmitters, + ], + }; + const oldType = { + type: "ObjectTypeAnnotation", + properties: [ + ...olderNativeModule.spec.methods, + ...olderNativeModule.spec.eventEmitters, + ], + }; + const difference = codegenTypeDiffing.compareTypes( + newType, + olderNativeModule.moduleName === newerNativeModule.moduleName + ? oldType + : null, + newerNativeModule.aliasMap, + olderNativeModule.aliasMap, + newerNativeModule.enumMap, + olderNativeModule.enumMap + ); + localAssessComparison( + nativeModuleName, + newType, + oldType, + difference, + "fromNative" + ); + const typeUpdate = { + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges, + }; + if (hasCodegenUpdatesTypes(typeUpdate)) { + moduleErrors.add({ + nativeSpecName: nativeModuleName, + omitted: false, + errorCode: "incompatibleTypes", + changeInformation: typeUpdate, + }); + } + return moduleErrors; +} +function buildNativeComponentsDiff(newerNativeSchema, olderNativeSchema) { + const componentErrors = new Set(); + Object.entries(newerNativeSchema.components).forEach( + ([newerComponentName, newerComponent]) => { + const olderComponent = olderNativeSchema.components[newerComponentName]; + const newTypes = new Set(); + const deprecatedTypes = new Set(); + const incompatibleChanges = new Set(); + const objectTypeChanges = new Set(); + const localAssessComparison = assessComparisonResult( + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges + ); + newerComponent.commands.forEach((command) => { + const oldCommand = olderComponent.commands?.find( + (olderCommand) => olderCommand.name === command.name + ); + const newCommands = { + type: "ObjectTypeAnnotation", + properties: [command], + }; + const oldCommands = + oldCommand != null + ? { + type: "ObjectTypeAnnotation", + properties: [oldCommand], + } + : null; + const difference = codegenTypeDiffing.compareTypes( + newCommands, + oldCommands, + {}, + {}, + {}, + {} + ); + localAssessComparison( + newerComponentName, + newCommands, + oldCommands, + difference, + "fromNative" + ); + }); + olderComponent.commands?.forEach((command) => { + const newCommand = newerComponent.commands.find( + (newerCommand) => newerCommand.name === command.name + ); + if (newCommand == null) { + deprecatedTypes.add({ + typeName: command.name, + typeInformation: { + type: "ObjectTypeAnnotation", + properties: [command], + }, + }); + } + }); + const newConvertedProps = { + type: "ObjectTypeAnnotation", + properties: newerComponent.props.map((prop) => ({ + name: prop.name, + optional: prop.optional, + typeAnnotation: (0, _convertPropToBasicTypes.default)( + prop.typeAnnotation + ), + })), + }; + const oldConvertedProps = { + type: "ObjectTypeAnnotation", + properties: olderComponent.props.map((prop) => ({ + name: prop.name, + optional: prop.optional, + typeAnnotation: (0, _convertPropToBasicTypes.default)( + prop.typeAnnotation + ), + })), + }; + const propDifference = codegenTypeDiffing.compareTypes( + newConvertedProps, + oldConvertedProps, + {}, + {}, + {}, + {} + ); + localAssessComparison( + newerComponentName, + newConvertedProps, + oldConvertedProps, + propDifference, + "toNative" + ); + const typeUpdate = { + newTypes, + deprecatedTypes, + incompatibleChanges, + objectTypeChanges, + }; + if (hasCodegenUpdatesTypes(typeUpdate)) { + componentErrors.add({ + nativeSpecName: newerComponentName, + omitted: false, + errorCode: "incompatibleTypes", + changeInformation: typeUpdate, + }); + } + } + ); + Object.keys(olderNativeSchema.components).forEach((olderComponentName) => { + const newerComponent = newerNativeSchema.components[olderComponentName]; + if (newerComponent == null) { + componentErrors.add({ + nativeSpecName: olderComponentName, + omitted: true, + errorCode: "removedComponent", + }); + } + }); + return componentErrors; +} +function hasUpdatesTypes(diff) { + return ( + diff.newTypes.size > 0 || + diff.deprecatedTypes.size > 0 || + diff.objectTypeChanges.size > 0 || + diff.incompatibleChanges.size > 0 + ); +} +function hasCodegenUpdatesTypes(diff) { + return ( + diff.newTypes.size > 0 || + diff.deprecatedTypes.size > 0 || + diff.objectTypeChanges.size > 0 || + diff.incompatibleChanges.size > 0 + ); +} +function buildSchemaDiff(newerSchemaSet, olderSchemaSet) { + const diff = new Set(); + const newerSchema = newerSchemaSet.modules; + const olderSchema = olderSchemaSet.modules; + Object.keys(newerSchema).forEach((hasteModuleName) => { + const schemaEntry = newerSchema[hasteModuleName]; + const olderSchemaEntry = olderSchema[hasteModuleName]; + const framework = "ReactNative"; + if (schemaEntry.type === "Component") { + if (olderSchemaEntry?.type === "Component") { + const incompatibleComponents = buildNativeComponentsDiff( + schemaEntry, + olderSchemaEntry + ); + const hasIncompatibleComponents = incompatibleComponents?.size > 0; + if (hasIncompatibleComponents) { + diff.add({ + name: hasteModuleName, + framework: framework, + status: { + incompatibleSpecs: incompatibleComponents, + }, + }); + } + } + } + if (schemaEntry.type === "NativeModule") { + if (olderSchemaEntry?.type === "NativeModule") { + const incompatibleModules = buildNativeModulesDiff( + schemaEntry, + olderSchemaEntry + ); + const hasIncompatibleModules = + incompatibleModules != null && incompatibleModules.size; + if (hasIncompatibleModules) { + diff.add({ + name: hasteModuleName, + framework: framework, + status: { + incompatibleSpecs: incompatibleModules, + }, + }); + } + } + } + if (olderSchemaEntry == null) { + diff.add({ + name: hasteModuleName, + framework: framework, + status: "new", + }); + } + }); + Object.keys(olderSchema).forEach((hasteModuleName) => { + const newSchemaEntry = newerSchema[hasteModuleName]; + const oldSchemaEntry = olderSchema[hasteModuleName]; + if (oldSchemaEntry != null && newSchemaEntry == null) { + diff.add({ + name: hasteModuleName, + framework: "ReactNative", + status: "deprecated", + }); + } + }); + return diff; +} +function summarizeSchemaDiff(diff) { + switch (diff.status) { + case "new": + return { + status: "patchable", + incompatibilityReport: {}, + }; + case "deprecated": + return { + status: "ok", + incompatibilityReport: {}, + }; + default: + const differs = diff.status; + if (!differs.incompatibleSpecs) { + return { + status: "patchable", + incompatibilityReport: {}, + }; + } else { + const incompatibleObject = {}; + if (differs.incompatibleSpecs) { + const withErrors = Array.from(differs.incompatibleSpecs).filter( + (specError) => + specError.errorInformation || + (specError.changeInformation && + specError.changeInformation.incompatibleChanges.size > 0) + ); + if (withErrors.length > 0) { + if (incompatibleObject[diff.name]) { + incompatibleObject[diff.name].incompatibleSpecs = withErrors; + } else { + incompatibleObject[diff.name] = { + framework: diff.framework, + incompatibleSpecs: withErrors, + }; + } + } + } + const incompatibleUnchanged = + Object.keys(incompatibleObject).length === 0; + return { + status: incompatibleUnchanged ? "ok" : "incompatible", + incompatibilityReport: incompatibleObject, + }; + } + } +} +function combineSummaries(finalSummary, setSummary) { + switch (setSummary.status) { + case "ok": + return finalSummary; + case "patchable": + if (finalSummary.status === "ok") { + return setSummary; + } else { + return finalSummary; + } + default: + switch (finalSummary.status) { + case "ok": + case "patchable": + return setSummary; + default: + Object.keys(setSummary.incompatibilityReport).forEach( + (differingSchemaName) => + (finalSummary.incompatibilityReport[differingSchemaName] = + setSummary.incompatibilityReport[differingSchemaName]) + ); + return finalSummary; + } + } +} +function summarizeDiffSet(diffs) { + if (diffs.size === 0) { + return { + status: "ok", + incompatibilityReport: {}, + }; + } + const summary = []; + diffs.forEach((schemaDiff) => summary.push(summarizeSchemaDiff(schemaDiff))); + return summary.reduce(combineSummaries, summary[0]); +} diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow b/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow new file mode 100644 index 00000000000000..81d071972577a5 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow @@ -0,0 +1,71 @@ +/** + * 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 { ComparisonResult } from "./ComparisonResult"; +import type { + DiffSet, + DiffSummary, + ErrorStore, + ObjectTypeChangeStore, + SchemaDiff, +} from "./DiffResults"; +import type { + CompleteTypeAnnotation, + SchemaType, +} from "@react-native/codegen/src/CodegenSchema"; + +type BoundaryDirection = "toNative" | "fromNative" | "both"; + +// Exported for testing +declare export const removedPropertiesMessage: "Object removed required properties expected by native"; +declare export const addedPropertiesMessage: "Object added required properties, which native will not provide"; +declare export const stricterPropertiesMessage: "Property made strict, but native may not provide it"; +declare export const tooOptionalPropertiesMessage: "Property made optional, but native requires it"; +declare export const removedUnionMessage: "Union removed items, but native may still provide them"; +declare export const addedUnionMessage: "Union added items, but native will not expect/support them"; +declare export const removedEnumMessage: "Enum removed items, but native may still provide them"; +declare export const addedEnumMessage: "Enum added items, but native will not expect/support them"; +declare export const removedIntersectionMessage: "Intersection removed items, but native may still require properties contained in them"; +declare export const addedIntersectionMessage: "Intersection added items, but native may not provide all required attributes"; +declare export const toNativeVoidChangeMessage: "Native may not be able to safely handle presence of type"; +declare export const typeNullableChangeMessage: "Type made nullable, but native requires it"; +declare export const fromNativeVoidChangeMessage: "Type set to void but native may still provide a value"; +declare export const typeNonNullableChangeMessage: "Type made non-nullable, but native might provide null still"; +declare export function assessComparisonResult( + newTypes: Set<{ + typeName: string, + typeInformation: CompleteTypeAnnotation, + ... + }>, + deprecatedTypes: Set<{ + typeName: string, + typeInformation: CompleteTypeAnnotation, + ... + }>, + incompatibleChanges: Set, + objectTypeChanges: Set +): ( + typeName: string, + newType: CompleteTypeAnnotation, + oldType: ?CompleteTypeAnnotation, + difference: ComparisonResult, + oldDirection: BoundaryDirection +) => void; + +declare export function hasUpdatesTypes(diff: DiffSet): boolean; + +declare export function hasCodegenUpdatesTypes(diff: DiffSet): boolean; + +declare export function buildSchemaDiff( + newerSchemaSet: SchemaType, + olderSchemaSet: SchemaType +): Set; + +declare export function summarizeDiffSet(diffs: Set): DiffSummary; diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts new file mode 100644 index 00000000000000..dae27d33f8ee4c --- /dev/null +++ b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts @@ -0,0 +1,20 @@ +/** + * 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 + * @oncall react_native + */ + +import type { + CompleteTypeAnnotation, + ComponentArrayTypeAnnotation, + PropTypeAnnotation, +} from "@react-native/codegen/src/CodegenSchema"; +declare function convertPropToBasicTypes( + inputType: PropTypeAnnotation | ComponentArrayTypeAnnotation["elementType"] +): CompleteTypeAnnotation; +export default convertPropToBasicTypes; diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js new file mode 100644 index 00000000000000..472aa9c699a5b2 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js @@ -0,0 +1,86 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +exports.default = convertPropToBasicTypes; +function convertPropToBasicTypes(inputType) { + let resultingType; + 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": + 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), + })), + }; + break; + case "ArrayTypeAnnotation": + resultingType = { + type: "ArrayTypeAnnotation", + elementType: convertPropToBasicTypes(inputType.elementType), + }; + break; + default: + inputType.type; + throw new Error("Unexpected type " + inputType.type); + } + return resultingType; +} diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow new file mode 100644 index 00000000000000..1b5fdf9bf9eeb1 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow @@ -0,0 +1,20 @@ +/** + * 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 { + CompleteTypeAnnotation, + ComponentArrayTypeAnnotation, + PropTypeAnnotation, +} from "@react-native/codegen/src/CodegenSchema"; + +declare export default function convertPropToBasicTypes( + inputType: PropTypeAnnotation | ComponentArrayTypeAnnotation["elementType"] +): CompleteTypeAnnotation; diff --git a/packages/react-native-compatibility-check/dist/index.d.ts b/packages/react-native-compatibility-check/dist/index.d.ts new file mode 100644 index 00000000000000..a77d5288201764 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/index.d.ts @@ -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. + * + * + * @format + * @oncall react_native + */ + +export { compareSchemas } from "./index.js"; diff --git a/packages/react-native-compatibility-check/dist/index.js b/packages/react-native-compatibility-check/dist/index.js new file mode 100644 index 00000000000000..d655cc572a9dc1 --- /dev/null +++ b/packages/react-native-compatibility-check/dist/index.js @@ -0,0 +1,12 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true, +}); +Object.defineProperty(exports, "compareSchemas", { + enumerable: true, + get: function () { + return _index.compareSchemas; + }, +}); +var _index = require("./index.js"); diff --git a/packages/react-native-compatibility-check/dist/index.js.flow b/packages/react-native-compatibility-check/dist/index.js.flow new file mode 100644 index 00000000000000..74591a1c31f19c --- /dev/null +++ b/packages/react-native-compatibility-check/dist/index.js.flow @@ -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"; diff --git a/packages/react-native-compatibility-check/package.json b/packages/react-native-compatibility-check/package.json index 69ccc77b6e42f8..a2da75ee42676d 100644 --- a/packages/react-native-compatibility-check/package.json +++ b/packages/react-native-compatibility-check/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "exports": { - ".": "./src/index.js", + ".": "./dist/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 4a237ee7f8227c..8ce1b4dd0ce24e 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -17,15 +17,15 @@ #if !TARGET_OS_OSX // [macOS] #import #else // [macOS -#include #include +#include #endif // macOS] #import #import #if TARGET_OS_OSX // [macOS -#import #import +#import #endif // macOS] #import "RCTConversions.h" @@ -43,7 +43,6 @@ static NSString *kEscapeKeyCode = @"\x1B"; #endif // macOS] - using namespace facebook::react; @interface RCTTextInputComponentView () @@ -105,7 +104,8 @@ - (instancetype)initWithFrame:(CGRect)frame #if !TARGET_OS_OSX // [macOS] _backedTextInputView = defaultProps->multiline ? [RCTUITextView new] : [RCTUITextField new]; #else // [macOS - _backedTextInputView = defaultProps->multiline ? [[RCTWrappedTextView alloc] initWithFrame:self.bounds] : [RCTUITextField new]; + _backedTextInputView = + defaultProps->multiline ? [[RCTWrappedTextView alloc] initWithFrame:self.bounds] : [RCTUITextField new]; #endif // macOS] _backedTextInputView.textInputDelegate = self; _ignoreNextTextInputCall = NO; @@ -113,6 +113,14 @@ - (instancetype)initWithFrame:(CGRect)frame _didMoveToWindow = NO; _originalTypingAttributes = [_backedTextInputView.typingAttributes copy]; +#if TARGET_OS_OSX // [macOS + // Ensure the backing text view doesn't interfere with border rendering + // by making sure it doesn't draw outside its bounds + if (_backedTextInputView.layer) { + _backedTextInputView.layer.masksToBounds = YES; + } +#endif // macOS] + [self addSubview:_backedTextInputView]; #if TARGET_OS_IOS // [macOS] [visionOS] [self initializeReturnKeyType]; @@ -213,7 +221,6 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & [self _setMultiline:newTextInputProps.multiline]; } - #if !TARGET_OS_OSX // [macOS] if (newTextInputProps.traits.autocapitalizationType != oldTextInputProps.traits.autocapitalizationType) { _backedTextInputView.autocapitalizationType = @@ -227,9 +234,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & RCTUITextAutocorrectionTypeFromOptionalBool(newTextInputProps.traits.autoCorrect); } #else // [macOS - if (newTextInputProps.traits.autoCorrect != oldTextInputProps.traits.autoCorrect && newTextInputProps.traits.autoCorrect.has_value()) { - _backedTextInputView.automaticSpellingCorrectionEnabled = - newTextInputProps.traits.autoCorrect.value(); + if (newTextInputProps.traits.autoCorrect != oldTextInputProps.traits.autoCorrect && + newTextInputProps.traits.autoCorrect.has_value()) { + _backedTextInputView.automaticSpellingCorrectionEnabled = newTextInputProps.traits.autoCorrect.value(); } #endif // macOS] @@ -267,16 +274,16 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & RCTUITextSpellCheckingTypeFromOptionalBool(newTextInputProps.traits.spellCheck); } #else // [macOS - if (newTextInputProps.traits.spellCheck != oldTextInputProps.traits.spellCheck && newTextInputProps.traits.spellCheck.has_value()) { - _backedTextInputView.continuousSpellCheckingEnabled = - newTextInputProps.traits.spellCheck.value(); + if (newTextInputProps.traits.spellCheck != oldTextInputProps.traits.spellCheck && + newTextInputProps.traits.spellCheck.has_value()) { + _backedTextInputView.continuousSpellCheckingEnabled = newTextInputProps.traits.spellCheck.value(); } #endif // macOS] #if TARGET_OS_OSX // [macOS - if (newTextInputProps.traits.grammarCheck != oldTextInputProps.traits.grammarCheck && newTextInputProps.traits.grammarCheck.has_value()) { - _backedTextInputView.grammarCheckingEnabled = - newTextInputProps.traits.grammarCheck.value(); + if (newTextInputProps.traits.grammarCheck != oldTextInputProps.traits.grammarCheck && + newTextInputProps.traits.grammarCheck.has_value()) { + _backedTextInputView.grammarCheckingEnabled = newTextInputProps.traits.grammarCheck.value(); } #endif // macOS] @@ -372,7 +379,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & } #if TARGET_OS_OSX // [macOS - if (newTextInputProps.traits.pastedTypes!= oldTextInputProps.traits.pastedTypes) { + if (newTextInputProps.traits.pastedTypes != oldTextInputProps.traits.pastedTypes) { NSArray *types = RCTPasteboardTypeArrayFromProps(newTextInputProps.traits.pastedTypes); [_backedTextInputView setReadablePasteBoardTypes:types]; } @@ -577,30 +584,35 @@ - (void)textInputDidChangeSelection } #if TARGET_OS_OSX // [macOS -- (void)setEnableFocusRing:(BOOL)enableFocusRing { +- (void)setEnableFocusRing:(BOOL)enableFocusRing +{ [super setEnableFocusRing:enableFocusRing]; if ([_backedTextInputView respondsToSelector:@selector(setEnableFocusRing:)]) { [_backedTextInputView setEnableFocusRing:enableFocusRing]; } } -- (void)automaticSpellingCorrectionDidChange:(BOOL)enabled { +- (void)automaticSpellingCorrectionDidChange:(BOOL)enabled +{ if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter)->onAutoCorrectChange({.autoCorrectEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter) + ->onAutoCorrectChange({.autoCorrectEnabled = static_cast(enabled)}); } } - (void)continuousSpellCheckingDidChange:(BOOL)enabled { if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter)->onSpellCheckChange({.spellCheckEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter) + ->onSpellCheckChange({.spellCheckEnabled = static_cast(enabled)}); } } - (void)grammarCheckingDidChange:(BOOL)enabled { if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter)->onGrammarCheckChange({.grammarCheckEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter) + ->onGrammarCheckChange({.grammarCheckEnabled = static_cast(enabled)}); } } @@ -608,14 +620,11 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event { BOOL shouldSubmit = NO; NSDictionary *keyEvent = [RCTViewKeyboardEvent bodyFromEvent:event]; - auto const &props = *std::static_pointer_cast(_props); + const auto &props = *std::static_pointer_cast(_props); if (props.traits.submitKeyEvents.empty()) { - shouldSubmit = [keyEvent[@"key"] isEqualToString:@"Enter"] - && ![keyEvent[@"altKey"] boolValue] - && ![keyEvent[@"shiftKey"] boolValue] - && ![keyEvent[@"ctrlKey"] boolValue] - && ![keyEvent[@"metaKey"] boolValue] - && ![keyEvent[@"functionKey"] boolValue]; // Default clearTextOnSubmit key + shouldSubmit = [keyEvent[@"key"] isEqualToString:@"Enter"] && ![keyEvent[@"altKey"] boolValue] && + ![keyEvent[@"shiftKey"] boolValue] && ![keyEvent[@"ctrlKey"] boolValue] && ![keyEvent[@"metaKey"] boolValue] && + ![keyEvent[@"functionKey"] boolValue]; // Default clearTextOnSubmit key } else { NSString *keyValue = keyEvent[@"key"]; const char *keyCString = [keyValue UTF8String]; @@ -628,19 +637,17 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event const bool functionKey = [keyEvent[@"functionKey"] boolValue]; shouldSubmit = std::any_of( - props.traits.submitKeyEvents.begin(), - props.traits.submitKeyEvents.end(), - [&](auto const &submitKeyEvent) { - return submitKeyEvent.key == key && submitKeyEvent.altKey == altKey && - submitKeyEvent.shiftKey == shiftKey && submitKeyEvent.ctrlKey == ctrlKey && - submitKeyEvent.metaKey == metaKey && submitKeyEvent.functionKey == functionKey; - }); + props.traits.submitKeyEvents.begin(), props.traits.submitKeyEvents.end(), [&](const auto &submitKeyEvent) { + return submitKeyEvent.key == key && submitKeyEvent.altKey == altKey && + submitKeyEvent.shiftKey == shiftKey && submitKeyEvent.ctrlKey == ctrlKey && + submitKeyEvent.metaKey == metaKey && submitKeyEvent.functionKey == functionKey; + }); } } - + if (shouldSubmit) { if (_eventEmitter) { - auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); textInputEventEmitter.onSubmitEditing([self _textInputMetrics]); } @@ -654,30 +661,33 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event - (void)textInputDidCancel { if (_eventEmitter) { - auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); textInputEventEmitter.onKeyPress({ - .text = RCTStringFromNSString(kEscapeKeyCode), - .eventCount = static_cast(_mostRecentEventCount), + .text = RCTStringFromNSString(kEscapeKeyCode), + .eventCount = static_cast(_mostRecentEventCount), }); } - + [self textInputDidEndEditing]; } -- (NSDragOperation)textInputDraggingEntered:(nonnull id)draggingInfo { +- (NSDragOperation)textInputDraggingEntered:(nonnull id)draggingInfo +{ if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { return [self draggingEntered:draggingInfo]; } return NSDragOperationNone; } -- (void)textInputDraggingExited:(nonnull id)draggingInfo { +- (void)textInputDraggingExited:(nonnull id)draggingInfo +{ if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { [self draggingExited:draggingInfo]; } } -- (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingInfo { +- (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingInfo +{ if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { [self performDragOperation:draggingInfo]; return NO; @@ -686,28 +696,33 @@ - (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingI return YES; } -- (BOOL)textInputShouldHandleDeleteBackward:(nonnull id)sender { +- (BOOL)textInputShouldHandleDeleteBackward:(nonnull id)sender +{ return YES; } -- (BOOL)textInputShouldHandleDeleteForward:(nonnull id)sender { +- (BOOL)textInputShouldHandleDeleteForward:(nonnull id)sender +{ return YES; } -- (BOOL)textInputShouldHandleKeyEvent:(nonnull NSEvent *)event { +- (BOOL)textInputShouldHandleKeyEvent:(nonnull NSEvent *)event +{ return ![self handleKeyboardEvent:event]; } -- (BOOL)textInputShouldHandlePaste:(nonnull id)sender { +- (BOOL)textInputShouldHandlePaste:(nonnull id)sender +{ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]]; - NSArray* pastedTypes = ((RCTUITextView*) _backedTextInputView).readablePasteboardTypes; - + NSPasteboardType fileType = + [pasteboard availableTypeFromArray:@[ NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF ]]; + NSArray *pastedTypes = ((RCTUITextView *)_backedTextInputView).readablePasteboardTypes; + // If there's a fileType that is of interest, notify JS. Also blocks notifying JS if it's a text paste if (_eventEmitter && fileType != nil && [pastedTypes containsObject:fileType]) { - auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); - DataTransfer dataTransfer = [self dataTransferForPasteboard:pasteboard]; - textInputEventEmitter.onPaste({.dataTransfer = std::move(dataTransfer)}); + const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + DataTransfer dataTransfer = [self dataTransferForPasteboard:pasteboard]; + textInputEventEmitter.onPaste({.dataTransfer = std::move(dataTransfer)}); } // Only allow pasting text. @@ -724,7 +739,8 @@ - (void)scrollViewDidScroll:(RCTUIScrollView *)scrollView // [macOS] #if !TARGET_OS_OSX // [macOS] static_cast(*_eventEmitter).onScroll([self _textInputMetrics]); #else // [macOS - static_cast(*_eventEmitter).onScroll([self _textInputMetricsWithScrollView:scrollView]); + static_cast(*_eventEmitter) + .onScroll([self _textInputMetricsWithScrollView:scrollView]); #endif // macOS] } } @@ -801,7 +817,8 @@ - (void)setTextAndSelection:(NSInteger)eventCount #else // [macOS NSInteger startPosition = MIN(start, end); NSInteger endPosition = MAX(start, end); - [_backedTextInputView setSelectedTextRange:NSMakeRange(startPosition, endPosition - startPosition) notifyDelegate:YES]; + [_backedTextInputView setSelectedTextRange:NSMakeRange(startPosition, endPosition - startPosition) + notifyDelegate:YES]; #endif // macOS] _comingFromJS = NO; } @@ -952,7 +969,6 @@ - (void)handleInputAccessoryDoneButton } #endif // macOS] - - (void)_updateState { if (!_state) { @@ -1041,8 +1057,7 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString NSInteger start = selectedRange.location; NSInteger offsetFromEnd = oldTextLength - start; NSInteger newOffset = _backedTextInputView.attributedText.length - offsetFromEnd; - [_backedTextInputView setSelectedTextRange:NSMakeRange(newOffset, 0) - notifyDelegate:YES]; + [_backedTextInputView setSelectedTextRange:NSMakeRange(newOffset, 0) notifyDelegate:YES]; } #endif // macOS] } @@ -1085,9 +1100,11 @@ - (void)_setMultiline:(BOOL)multiline { [_backedTextInputView removeFromSuperview]; #if !TARGET_OS_OSX // [macOS] - RCTUIView *backedTextInputView = multiline ? [RCTUITextView new] : [RCTUITextField new]; + RCTUIView *backedTextInputView = + multiline ? [RCTUITextView new] : [RCTUITextField new]; #else // [macOS - RCTPlatformView *backedTextInputView = multiline ? [RCTWrappedTextView new] : [RCTUITextField new]; + RCTPlatformView *backedTextInputView = + multiline ? [RCTWrappedTextView new] : [RCTUITextField new]; #endif // macOS] backedTextInputView.frame = _backedTextInputView.frame; RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView); @@ -1118,10 +1135,11 @@ - (void)_setShowSoftInputOnFocus:(BOOL)showSoftInputOnFocus - (void)_setSecureTextEntry:(BOOL)secureTextEntry { [_backedTextInputView removeFromSuperview]; - RCTPlatformView *backedTextInputView = secureTextEntry ? [RCTUISecureTextField new] : [RCTUITextField new]; + RCTPlatformView *backedTextInputView = + secureTextEntry ? [RCTUISecureTextField new] : [RCTUITextField new]; backedTextInputView.frame = _backedTextInputView.frame; RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView); - + // Copy the text field specific properties if we came from a single line input before the switch if ([_backedTextInputView isKindOfClass:[RCTUITextField class]]) { RCTUITextField *previousTextField = (RCTUITextField *)_backedTextInputView; @@ -1159,17 +1177,16 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe BOOL shouldFallbackToBareTextComparison = #if !TARGET_OS_OSX // [macOS] - [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || - [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || - _backedTextInputView.markedTextRange || - _backedTextInputView.isSecureTextEntry || + [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || + [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || + _backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || #else // [macOS - // There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead - [[[_backedTextInputView inputContext] selectedKeyboardInputSource] containsString:@"com.apple.inputmethod.Korean"] || - [_backedTextInputView hasMarkedText] || - [_backedTextInputView isKindOfClass:[NSSecureTextField class]] || + // There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead + [[[_backedTextInputView inputContext] selectedKeyboardInputSource] + containsString:@"com.apple.inputmethod.Korean"] || + [_backedTextInputView hasMarkedText] || [_backedTextInputView isKindOfClass:[NSSecureTextField class]] || #endif // macOS] - fontHasBeenUpdatedBySystem; + fontHasBeenUpdatedBySystem; if (shouldFallbackToBareTextComparison) { return [newText.string isEqualToString:oldText.string]; From 09bb94a015ba507b2bad060c98d5be4310bde4b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:25:40 +0000 Subject: [PATCH 3/8] Force Core Animation border rendering for TextInput on macOS by enabling clipsToBounds Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .../TextInput/RCTTextInputComponentView.mm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 8ce1b4dd0ce24e..8c9ff0e803a35b 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -420,6 +420,21 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics { CGSize previousContentSize = _backedTextInputView.contentSize; +#if TARGET_OS_OSX // [macOS + // On macOS, ensure proper border rendering by enabling clip to bounds + // when borders are present. This forces Core Animation border rendering + // which displays correctly with the native text field subview. + const auto &props = static_cast(*_props); + const auto borderMetrics = props.resolveBorderMetrics(layoutMetrics); + BOOL hasBorder = borderMetrics.borderWidths.left > 0 || borderMetrics.borderWidths.right > 0 || + borderMetrics.borderWidths.top > 0 || borderMetrics.borderWidths.bottom > 0; + if (hasBorder) { + // Note: Setting clipsToBounds ensures Core Animation border rendering is used, + // which properly displays with the native text field subview on macOS + self.clipsToBounds = YES; + } +#endif // macOS] + [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; #if TARGET_OS_OSX // [macOS From a8b4c19d56a7736e2dc1dee89b8210720e1a2b44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:27:53 +0000 Subject: [PATCH 4/8] Address code review feedback: reset clipsToBounds when no borders and in prepareForRecycle Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .../ComponentViews/TextInput/RCTTextInputComponentView.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 8c9ff0e803a35b..0c0f473c4703f6 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -432,6 +432,9 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics // Note: Setting clipsToBounds ensures Core Animation border rendering is used, // which properly displays with the native text field subview on macOS self.clipsToBounds = YES; + } else { + // Reset clipsToBounds when no borders are present + self.clipsToBounds = NO; } #endif // macOS] @@ -461,6 +464,10 @@ - (void)prepareForRecycle _ignoreNextTextInputCall = NO; _didMoveToWindow = NO; [_backedTextInputView resignFirstResponder]; +#if TARGET_OS_OSX // [macOS + // Reset clipsToBounds to prevent state leakage in recycled components + self.clipsToBounds = NO; +#endif // macOS] } #pragma mark - RCTBackedTextInputDelegate From 4a62aa35a0959e81345055e7a99811777e71da63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 22:24:18 +0000 Subject: [PATCH 5/8] Remove unrelated build artifacts and package.json changes Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .gitignore | 1 + packages/community-cli-plugin/package.json | 2 +- packages/core-cli-utils/package.json | 6 +- packages/dev-middleware/package.json | 2 +- packages/metro-config/package.json | 2 +- .../dist/ComparisonResult.d.ts | 135 -- .../dist/ComparisonResult.js | 88 -- .../dist/ComparisonResult.js.flow | 188 --- .../dist/DiffResults.d.ts | 137 -- .../dist/DiffResults.js | 52 - .../dist/DiffResults.js.flow | 160 --- .../dist/ErrorFormatting.d.ts | 31 - .../dist/ErrorFormatting.js | 272 ---- .../dist/ErrorFormatting.js.flow | 34 - .../dist/SortTypeAnnotations.d.ts | 18 - .../dist/SortTypeAnnotations.js | 300 ---- .../dist/SortTypeAnnotations.js.flow | 20 - .../dist/TypeDiffing.d.ts | 86 -- .../dist/TypeDiffing.js | 1253 ----------------- .../dist/TypeDiffing.js.flow | 99 -- .../dist/VersionDiffing.d.ts | 59 - .../dist/VersionDiffing.js | 1235 ---------------- .../dist/VersionDiffing.js.flow | 71 - .../dist/convertPropToBasicTypes.d.ts | 20 - .../dist/convertPropToBasicTypes.js | 86 -- .../dist/convertPropToBasicTypes.js.flow | 20 - .../dist/index.d.ts | 12 - .../dist/index.js | 12 - .../dist/index.js.flow | 12 - .../package.json | 2 +- 30 files changed, 8 insertions(+), 4407 deletions(-) delete mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.js delete mode 100644 packages/react-native-compatibility-check/dist/ComparisonResult.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/DiffResults.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/DiffResults.js delete mode 100644 packages/react-native-compatibility-check/dist/DiffResults.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.js delete mode 100644 packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.js delete mode 100644 packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.js delete mode 100644 packages/react-native-compatibility-check/dist/TypeDiffing.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.js delete mode 100644 packages/react-native-compatibility-check/dist/VersionDiffing.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js delete mode 100644 packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow delete mode 100644 packages/react-native-compatibility-check/dist/index.d.ts delete mode 100644 packages/react-native-compatibility-check/dist/index.js delete mode 100644 packages/react-native-compatibility-check/dist/index.js.flow diff --git a/.gitignore b/.gitignore index 396da3ee520af1..8bdad4184a66ee 100644 --- a/.gitignore +++ b/.gitignore @@ -190,3 +190,4 @@ fix_*.patch .cursor/rules/nx-rules.mdc .github/instructions/nx.instructions.md # macOS] +packages/react-native-compatibility-check/dist/ diff --git a/packages/community-cli-plugin/package.json b/packages/community-cli-plugin/package.json index c1699033894e42..48d57288558183 100644 --- a/packages/community-cli-plugin/package.json +++ b/packages/community-cli-plugin/package.json @@ -16,7 +16,7 @@ }, "license": "MIT", "exports": { - ".": "./dist/index.js", + ".": "./src/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/core-cli-utils/package.json b/packages/core-cli-utils/package.json index 273f4e2de7eebf..f62b62d39b024b 100644 --- a/packages/core-cli-utils/package.json +++ b/packages/core-cli-utils/package.json @@ -4,16 +4,16 @@ "private": true, "description": "React Native CLI library for Frameworks to build on", "license": "MIT", - "main": "./dist/index.flow.js", + "main": "./src/index.flow.js", "repository": { "type": "git", "url": "git+https://github.com/facebook/react-native.git", "directory": "packages/core-cli-utils" }, "exports": { - ".": "./dist/index.js", + ".": "./src/index.js", "./package.json": "./package.json", - "./version.js": "./dist/public/version.js" + "./version.js": "./src/public/version.js" }, "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/core-cli-utils#readme", "keywords": [ diff --git a/packages/dev-middleware/package.json b/packages/dev-middleware/package.json index 92a8e008bea887..bf4a792ee40541 100644 --- a/packages/dev-middleware/package.json +++ b/packages/dev-middleware/package.json @@ -16,7 +16,7 @@ }, "license": "MIT", "exports": { - ".": "./dist/index.js", + ".": "./src/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index fe336e01362666..73076dccd42462 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -20,7 +20,7 @@ "node": ">=18" }, "exports": { - ".": "./dist/index.js", + ".": "./src/index.js", "./package.json": "./package.json" }, "files": [ diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts b/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts deleted file mode 100644 index 6e13ad67a8844d..00000000000000 --- a/packages/react-native-compatibility-check/dist/ComparisonResult.d.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * 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 - */ - -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; -export type PositionalComparisonResult = { - typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple"; - nestedChanges: Array<[number, number, ComparisonResult]>; - addedElements?: Array<[number, CompleteTypeAnnotation]>; - removedElements?: Array<[number, CompleteTypeAnnotation]>; -}; -export type FunctionComparisonResult = { - returnType?: ComparisonResult; - parameterTypes?: PositionalComparisonResult; -}; -export type PropertiesComparisonResult = { - addedProperties?: ReadonlyArray>; - missingProperties?: ReadonlyArray>; - 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; - missingMembers?: Array; - errorMembers?: Array<{ member: string; fault?: TypeComparisonError }>; -}; -export type NullableComparisonResult = { - typeRefined: boolean; - optionsReduced: boolean; - interiorLog: null | undefined | ComparisonResult; - newType: null | undefined | CompleteTypeAnnotation; - oldType: null | undefined | 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 declare function isPropertyLogEmpty( - result: PropertiesComparisonResult -): boolean; -export declare function isMemberLogEmpty( - result: MembersComparisonResult -): boolean; -export declare function isFunctionLogEmpty( - result: FunctionComparisonResult -): boolean; -export declare function makeError(error: TypeComparisonError): ComparisonResult; -export declare function typeInformationComparisonError( - message: string, - newerType: CompleteTypeAnnotation, - olderType: CompleteTypeAnnotation, - previousError?: TypeComparisonError -): TypeComparisonError; -export declare function typeAnnotationComparisonError( - message: string, - newerAnnotation: CompleteTypeAnnotation, - olderAnnotation: CompleteTypeAnnotation, - previousError?: TypeComparisonError -): TypeComparisonError; -export declare function propertyComparisonError( - message: string, - mismatchedProperties: Array<{ - property: string; - fault?: TypeComparisonError; - }>, - previousError?: TypeComparisonError -): TypeComparisonError; -export declare function memberComparisonError( - message: string, - mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>, - previousError?: TypeComparisonError -): TypeComparisonError; -export declare function positionalComparisonError( - message: string, - erroneousItems: Array<[number, CompleteTypeAnnotation]>, - previousError?: TypeComparisonError -): TypeComparisonError; diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.js b/packages/react-native-compatibility-check/dist/ComparisonResult.js deleted file mode 100644 index 835217ea999220..00000000000000 --- a/packages/react-native-compatibility-check/dist/ComparisonResult.js +++ /dev/null @@ -1,88 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.isFunctionLogEmpty = isFunctionLogEmpty; -exports.isMemberLogEmpty = isMemberLogEmpty; -exports.isPropertyLogEmpty = isPropertyLogEmpty; -exports.makeError = makeError; -exports.memberComparisonError = memberComparisonError; -exports.positionalComparisonError = positionalComparisonError; -exports.propertyComparisonError = propertyComparisonError; -exports.typeAnnotationComparisonError = typeAnnotationComparisonError; -exports.typeInformationComparisonError = typeInformationComparisonError; -function isPropertyLogEmpty(result) { - return !( - result.addedProperties || - result.missingProperties || - result.nestedPropertyChanges || - result.madeStrict || - result.madeOptional || - result.errorProperties - ); -} -function isMemberLogEmpty(result) { - return !(result.addedMembers || result.missingMembers || result.errorMembers); -} -function isFunctionLogEmpty(result) { - return !(result.returnType || result.parameterTypes); -} -function makeError(error) { - return { - status: "error", - errorLog: error, - }; -} -function typeInformationComparisonError( - message, - newerType, - olderType, - previousError -) { - return { - type: "TypeInformationComparisonError", - message, - newerType, - olderType, - previousError, - }; -} -function typeAnnotationComparisonError( - message, - newerAnnotation, - olderAnnotation, - previousError -) { - return { - type: "TypeAnnotationComparisonError", - message, - newerAnnotation, - olderAnnotation, - previousError, - }; -} -function propertyComparisonError(message, mismatchedProperties, previousError) { - return { - type: "PropertyComparisonError", - message, - mismatchedProperties, - previousError, - }; -} -function memberComparisonError(message, mismatchedMembers, previousError) { - return { - type: "MemberComparisonError", - message, - mismatchedMembers, - previousError, - }; -} -function positionalComparisonError(message, erroneousItems, previousError) { - return { - type: "PositionalComparisonError", - message, - erroneousItems, - previousError, - }; -} diff --git a/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow b/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow deleted file mode 100644 index 9188eddfa79c1c..00000000000000 --- a/packages/react-native-compatibility-check/dist/ComparisonResult.js.flow +++ /dev/null @@ -1,188 +0,0 @@ -/** - * 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>> - -export type PropertiesComparisonResult = { - addedProperties?: $ReadOnlyArray>, - missingProperties?: $ReadOnlyArray>, - 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, - missingMembers?: Array, - 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 }; - -declare export function isPropertyLogEmpty( - result: PropertiesComparisonResult -): boolean; - -declare export function isMemberLogEmpty( - result: MembersComparisonResult -): boolean; - -declare export function isFunctionLogEmpty( - result: FunctionComparisonResult -): boolean; - -declare export function makeError(error: TypeComparisonError): ComparisonResult; - -declare export function typeInformationComparisonError( - message: string, - newerType: CompleteTypeAnnotation, - olderType: CompleteTypeAnnotation, - previousError?: TypeComparisonError -): TypeComparisonError; - -declare export function typeAnnotationComparisonError( - message: string, - newerAnnotation: CompleteTypeAnnotation, - olderAnnotation: CompleteTypeAnnotation, - previousError?: TypeComparisonError -): TypeComparisonError; - -declare export function propertyComparisonError( - message: string, - mismatchedProperties: Array<{ - property: string, - fault?: TypeComparisonError, - ... - }>, - previousError?: TypeComparisonError -): TypeComparisonError; - -declare export function memberComparisonError( - message: string, - mismatchedMembers: Array<{ - member: string, - fault?: TypeComparisonError, - }>, - previousError?: TypeComparisonError -): TypeComparisonError; - -declare export function positionalComparisonError( - message: string, - erroneousItems: Array<[number, CompleteTypeAnnotation]>, - previousError?: TypeComparisonError -): TypeComparisonError; diff --git a/packages/react-native-compatibility-check/dist/DiffResults.d.ts b/packages/react-native-compatibility-check/dist/DiffResults.d.ts deleted file mode 100644 index e4179054afafa4..00000000000000 --- a/packages/react-native-compatibility-check/dist/DiffResults.d.ts +++ /dev/null @@ -1,137 +0,0 @@ -/** - * 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 - */ - -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; -}; -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; - deprecatedTypes: Set; - objectTypeChanges: Set; - incompatibleChanges: Set; -}; -type ExportableDiffSet = { - newTypes: Array; - deprecatedTypes: Array; - objectTypeChanges: Array; - incompatibleChanges: Array; -}; -export type Framework = "ReactNative"; -export type SchemaDiffers = { - incompatibleSpecs: null | undefined | Set; -}; -type ExportableSchemaDiffers = { - incompatibleSpecs: null | undefined | Array; -}; -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; -}; -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"; - incompatibilityReport: IncompatiblityReport; -}; -export type FormattedIncompatible = { - framework: Framework; - incompatibleSpecs?: Array; -}; -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"; - incompatibilityReport: FormattedIncompatiblityReport; -}; -export declare function nativeSpecErrorExporter( - nativeSpecError: NativeSpecErrorStore -): ExportableNativeSpecErrorStore; -export declare function schemaDiffExporter( - schemaDiff: SchemaDiff -): ExportableSchemaDiff; diff --git a/packages/react-native-compatibility-check/dist/DiffResults.js b/packages/react-native-compatibility-check/dist/DiffResults.js deleted file mode 100644 index 9f7dfbc736e521..00000000000000 --- a/packages/react-native-compatibility-check/dist/DiffResults.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.nativeSpecErrorExporter = nativeSpecErrorExporter; -exports.schemaDiffExporter = schemaDiffExporter; -function diffSetExporter(diffSet) { - return { - newTypes: Array.from(diffSet.newTypes), - deprecatedTypes: Array.from(diffSet.deprecatedTypes), - objectTypeChanges: Array.from(diffSet.objectTypeChanges), - incompatibleChanges: Array.from(diffSet.incompatibleChanges), - }; -} -function nativeSpecErrorExporter(nativeSpecError) { - 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) { - switch (status) { - case "new": - case "deprecated": - return status; - default: - return { - incompatibleSpecs: status.incompatibleSpecs - ? Array.from(status.incompatibleSpecs).map(nativeSpecErrorExporter) - : undefined, - }; - } -} -function schemaDiffExporter(schemaDiff) { - return { - name: schemaDiff.name, - framework: schemaDiff.framework, - status: schemaDiffCategoryExporter(schemaDiff.status), - }; -} diff --git a/packages/react-native-compatibility-check/dist/DiffResults.js.flow b/packages/react-native-compatibility-check/dist/DiffResults.js.flow deleted file mode 100644 index 659eba6d6982d0..00000000000000 --- a/packages/react-native-compatibility-check/dist/DiffResults.js.flow +++ /dev/null @@ -1,160 +0,0 @@ -/** - * 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, - deprecatedTypes: Set, - objectTypeChanges: Set, - incompatibleChanges: Set, -}; -type ExportableDiffSet = { - newTypes: Array, - deprecatedTypes: Array, - objectTypeChanges: Array, - incompatibleChanges: Array, -}; - -export type Framework = "ReactNative"; -export type SchemaDiffers = { - incompatibleSpecs: ?Set, -}; -type ExportableSchemaDiffers = { - incompatibleSpecs: ?Array, -}; -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, -}; -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, -}; - -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, -}; - -declare export function nativeSpecErrorExporter( - nativeSpecError: NativeSpecErrorStore -): ExportableNativeSpecErrorStore; - -declare export function schemaDiffExporter( - schemaDiff: SchemaDiff -): ExportableSchemaDiff; diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts b/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts deleted file mode 100644 index 27eaca66725d09..00000000000000 --- a/packages/react-native-compatibility-check/dist/ErrorFormatting.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 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 - */ - -import type { TypeComparisonError } from "./ComparisonResult"; -import type { - DiffSummary, - ErrorStore, - FormattedDiffSummary, - FormattedErrorStore, - NativeSpecErrorStore, -} from "./DiffResults"; -export declare function formatErrorMessage( - error: TypeComparisonError, - indent: number -): string; -export declare function formatErrorStore( - errorStore: ErrorStore -): FormattedErrorStore; -export declare function formatNativeSpecErrorStore( - specError: NativeSpecErrorStore -): Array; -export declare function formatDiffSet( - summary: DiffSummary -): FormattedDiffSummary; diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.js b/packages/react-native-compatibility-check/dist/ErrorFormatting.js deleted file mode 100644 index 8bb5e380d8d932..00000000000000 --- a/packages/react-native-compatibility-check/dist/ErrorFormatting.js +++ /dev/null @@ -1,272 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.formatDiffSet = formatDiffSet; -exports.formatErrorMessage = formatErrorMessage; -exports.formatErrorStore = formatErrorStore; -exports.formatNativeSpecErrorStore = formatNativeSpecErrorStore; -function indentedLineStart(indent) { - return "\n" + " ".repeat(indent); -} -function formatErrorMessage(error, indent = 0) { - 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": - 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; - return ""; - } -} -function formatTypeAnnotation(annotation) { - 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; - 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; - 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": - 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; - return JSON.stringify(annotation); - } -} -function formatErrorStore(errorStore) { - return { - message: - errorStore.typeName + - ": " + - formatErrorMessage(errorStore.errorInformation), - errorCode: errorStore.errorCode, - }; -} -function formatNativeSpecErrorStore(specError) { - 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) - ); - } - return []; -} -function formatDiffSet(summary) { - const summaryStatus = summary.status; - if (summaryStatus === "ok" || summaryStatus === "patchable") { - return summary; - } - const hasteModules = Object.keys(summary.incompatibilityReport); - const incompatibles = summary.incompatibilityReport; - const formattedIncompatibilities = {}; - hasteModules.forEach((hasteModule) => { - const incompat = incompatibles[hasteModule]; - const formattedIncompat = { - framework: incompat.framework, - }; - if (incompat.incompatibleSpecs) { - formattedIncompat.incompatibleSpecs = incompat.incompatibleSpecs.reduce( - (formattedModuleErrors, specErrorStore) => - formattedModuleErrors.concat( - formatNativeSpecErrorStore(specErrorStore) - ), - [] - ); - } - formattedIncompatibilities[hasteModule] = formattedIncompat; - }); - return { - status: summaryStatus, - incompatibilityReport: formattedIncompatibilities, - }; -} diff --git a/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow b/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow deleted file mode 100644 index d132768e178a09..00000000000000 --- a/packages/react-native-compatibility-check/dist/ErrorFormatting.js.flow +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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, - NativeSpecErrorStore, -} from "./DiffResults"; -declare export function formatErrorMessage( - error: TypeComparisonError, - indent: number -): string; - -declare export function formatErrorStore( - errorStore: ErrorStore -): FormattedErrorStore; - -declare export function formatNativeSpecErrorStore( - specError: NativeSpecErrorStore -): Array; - -declare export function formatDiffSet( - summary: DiffSummary -): FormattedDiffSummary; diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts deleted file mode 100644 index bc295d80883322..00000000000000 --- a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * 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 - */ - -import type { CompleteTypeAnnotation } from "@react-native/codegen/src/CodegenSchema"; -export declare function sortTypeAnnotations( - annotations: ReadonlyArray -): Array<[number, CompleteTypeAnnotation]>; -export declare function compareTypeAnnotationForSorting( - $$PARAM_0$$: [number, CompleteTypeAnnotation], - $$PARAM_1$$: [number, CompleteTypeAnnotation] -): number; diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js deleted file mode 100644 index d39e8402fca9ce..00000000000000 --- a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js +++ /dev/null @@ -1,300 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.compareTypeAnnotationForSorting = compareTypeAnnotationForSorting; -exports.sortTypeAnnotations = sortTypeAnnotations; -var _invariant = _interopRequireDefault(require("invariant")); -function _interopRequireDefault(e) { - return e && e.__esModule ? e : { default: e }; -} -function sortTypeAnnotations(annotations) { - const sortableArray = annotations.map((a, i) => [i, a]); - return sortableArray.sort(compareTypeAnnotationForSorting); -} -const EQUALITY_MSG = "typeA and typeB differ despite check"; -function compareTypeAnnotationForSorting( - [originalPositionA, typeA], - [originalPositionB, typeB] -) { - 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": - (0, _invariant.default)( - typeB.type === "ArrayTypeAnnotation", - EQUALITY_MSG - ); - return compareTypeAnnotationForSorting( - [originalPositionA, typeA.elementType], - [originalPositionB, typeB.elementType] - ); - case "BooleanTypeAnnotation": - return originalPositionA - originalPositionB; - case "EnumDeclaration": - (0, _invariant.default)(typeB.type === "EnumDeclaration", EQUALITY_MSG); - return typeA.memberType.localeCompare(typeB.memberType); - case "EnumDeclarationWithMembers": - (0, _invariant.default)( - 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": - (0, _invariant.default)( - 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": - (0, _invariant.default)( - typeB.type === "EventEmitterTypeAnnotation", - EQUALITY_MSG - ); - return compareTypeAnnotationForSorting( - [originalPositionA, typeA.typeAnnotation], - [originalPositionB, typeB.typeAnnotation] - ); - case "GenericObjectTypeAnnotation": - (0, _invariant.default)( - 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": - (0, _invariant.default)( - 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": - (0, _invariant.default)( - typeB.type === "NumberLiteralTypeAnnotation", - EQUALITY_MSG - ); - return typeA.value - typeB.value; - case "ObjectTypeAnnotation": - (0, _invariant.default)( - 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": - (0, _invariant.default)( - typeB.type === "StringLiteralTypeAnnotation", - EQUALITY_MSG - ); - return typeA.value.localeCompare(typeB.value); - case "StringLiteralUnionTypeAnnotation": - (0, _invariant.default)( - typeB.type === "StringLiteralUnionTypeAnnotation", - EQUALITY_MSG - ); - return compareAnnotationArraysForSorting( - [originalPositionA, typeA.types], - [originalPositionB, typeB.types] - ); - case "UnionTypeAnnotation": - (0, _invariant.default)( - typeB.type === "UnionTypeAnnotation", - EQUALITY_MSG - ); - return 0; - case "VoidTypeAnnotation": - return 0; - case "ReservedTypeAnnotation": - return 0; - case "PromiseTypeAnnotation": - (0, _invariant.default)( - typeB.type === "PromiseTypeAnnotation", - EQUALITY_MSG - ); - return compareTypeAnnotationForSorting( - [originalPositionA, typeA.elementType], - [originalPositionB, typeB.elementType] - ); - case "TypeAliasTypeAnnotation": - return 0; - case "MixedTypeAnnotation": - return 0; - default: - typeA.type; - return -1; - } -} -function nameComparison([nameA], [nameB]) { - if (nameA === nameB) { - return 0; - } else if (nameA < nameB) { - return -1; - } - return 1; -} -function compareNameAnnotationArraysForSorting( - [originalPositionA, arrayA], - [originalPositionB, arrayB] -) { - 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], - [originalPositionB, arrayB] -) { - 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) { - 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; - return -1; - } -} diff --git a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow b/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow deleted file mode 100644 index 67a5fccc6692bf..00000000000000 --- a/packages/react-native-compatibility-check/dist/SortTypeAnnotations.js.flow +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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"; - -declare export function sortTypeAnnotations( - annotations: $ReadOnlyArray -): Array<[number, CompleteTypeAnnotation]>; - -declare export function compareTypeAnnotationForSorting( - [number, CompleteTypeAnnotation], - [number, CompleteTypeAnnotation] -): number; diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts b/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts deleted file mode 100644 index 053d56cdd9f9aa..00000000000000 --- a/packages/react-native-compatibility-check/dist/TypeDiffing.d.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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 - */ - -import type { - ComparisonResult, - MembersComparisonResult, -} from "./ComparisonResult"; -import type { - CompleteTypeAnnotation, - NamedShape, - NativeModuleAliasMap, - NativeModuleEnumDeclaration, - NativeModuleEnumDeclarationWithMembers, - NativeModuleEnumMap, - NativeModuleEnumMember, - NativeModuleFunctionTypeAnnotation, - NativeModuleGenericObjectTypeAnnotation, - NativeModulePromiseTypeAnnotation, - NativeModuleUnionTypeAnnotation, - NumberLiteralTypeAnnotation, - StringLiteralTypeAnnotation, - StringLiteralUnionTypeAnnotation, -} from "@react-native/codegen/src/CodegenSchema"; -export declare function compareTypes( - newerType: CompleteTypeAnnotation, - olderType: null | undefined | CompleteTypeAnnotation, - newerTypesReg: null | undefined | NativeModuleAliasMap, - olderTypesReg: null | undefined | NativeModuleAliasMap, - newerEnumMap: null | undefined | NativeModuleEnumMap, - olderEnumMap: null | undefined | NativeModuleEnumMap -): ComparisonResult; -export declare function compareTypeAnnotation( - originalNewerAnnotation: CompleteTypeAnnotation, - originalOlderAnnotation: CompleteTypeAnnotation -): ComparisonResult; -export declare function compareObjectTypes( - newerPropertyTypes: ReadonlyArray>, - olderPropertyTypes: ReadonlyArray> -): ComparisonResult; -export declare function compareEnumDeclarations( - newerDeclaration: NativeModuleEnumDeclaration, - olderDeclaration: NativeModuleEnumDeclaration -): ComparisonResult; -export declare function compareEnumDeclarationMemberArrays( - newer: Array, - older: Array -): MembersComparisonResult; -export declare function compareEnumDeclarationWithMembers( - newerDeclaration: NativeModuleEnumDeclarationWithMembers, - olderDeclaration: NativeModuleEnumDeclarationWithMembers -): ComparisonResult; -export declare function compareUnionTypes( - newerType: NativeModuleUnionTypeAnnotation, - olderType: NativeModuleUnionTypeAnnotation -): ComparisonResult; -export declare function comparePromiseTypes( - newerType: NativeModulePromiseTypeAnnotation, - olderType: NativeModulePromiseTypeAnnotation -): ComparisonResult; -export declare function compareGenericObjectTypes( - newerType: NativeModuleGenericObjectTypeAnnotation, - olderType: NativeModuleGenericObjectTypeAnnotation -): ComparisonResult; -export declare function compareNumberLiteralTypes( - newerType: NumberLiteralTypeAnnotation, - olderType: NumberLiteralTypeAnnotation -): ComparisonResult; -export declare function compareStringLiteralTypes( - newerType: StringLiteralTypeAnnotation, - olderType: StringLiteralTypeAnnotation -): ComparisonResult; -export declare function compareStringLiteralUnionTypes( - newerType: StringLiteralUnionTypeAnnotation, - olderType: StringLiteralUnionTypeAnnotation -): ComparisonResult; -export declare function compareFunctionTypes( - newerType: NativeModuleFunctionTypeAnnotation, - olderType: NativeModuleFunctionTypeAnnotation -): ComparisonResult; diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.js b/packages/react-native-compatibility-check/dist/TypeDiffing.js deleted file mode 100644 index aa0cfacb05a015..00000000000000 --- a/packages/react-native-compatibility-check/dist/TypeDiffing.js +++ /dev/null @@ -1,1253 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.compareEnumDeclarationMemberArrays = compareEnumDeclarationMemberArrays; -exports.compareEnumDeclarationWithMembers = compareEnumDeclarationWithMembers; -exports.compareEnumDeclarations = compareEnumDeclarations; -exports.compareFunctionTypes = compareFunctionTypes; -exports.compareGenericObjectTypes = compareGenericObjectTypes; -exports.compareNumberLiteralTypes = compareNumberLiteralTypes; -exports.compareObjectTypes = compareObjectTypes; -exports.comparePromiseTypes = comparePromiseTypes; -exports.compareStringLiteralTypes = compareStringLiteralTypes; -exports.compareStringLiteralUnionTypes = compareStringLiteralUnionTypes; -exports.compareTypeAnnotation = compareTypeAnnotation; -exports.compareTypes = compareTypes; -exports.compareUnionTypes = compareUnionTypes; -var _ComparisonResult = require("./ComparisonResult"); -var _SortTypeAnnotations = require("./SortTypeAnnotations.js"); -var _invariant = _interopRequireDefault(require("invariant")); -function _interopRequireDefault(e) { - return e && e.__esModule ? e : { default: e }; -} -const EQUALITY_MSG = "previousType and afterType differ despite check"; -let _newerTypesReg, _olderTypesReg, _newerEnumMap, _olderEnumMap; -function compareTypes( - newerType, - olderType, - newerTypesReg, - olderTypesReg, - newerEnumMap, - olderEnumMap -) { - if (!olderType) { - return { - status: "skipped", - }; - } - _newerTypesReg = newerTypesReg; - _olderTypesReg = olderTypesReg; - _newerEnumMap = newerEnumMap; - _olderEnumMap = olderEnumMap; - const res = compareTypeAnnotation(newerType, olderType); - _newerTypesReg = undefined; - _olderTypesReg = undefined; - _newerEnumMap = undefined; - _olderEnumMap = undefined; - return res; -} -function removeNullableTypeAnnotations(annotation) { - if (annotation.type === "NullableTypeAnnotation") { - return removeNullableTypeAnnotations(annotation.typeAnnotation); - } - return annotation; -} -function lookupType(name, aliases) { - return aliases?.[name]; -} -function lookupEnum(name, enums) { - return enums?.[name]; -} -function compareTypeAnnotation( - originalNewerAnnotation, - originalOlderAnnotation -) { - const newerAnnotation = originalNewerAnnotation; - const olderAnnotation = originalOlderAnnotation; - if (newerAnnotation.type === "TypeAliasTypeAnnotation") { - const newerAnnotationDefinition = lookupType( - newerAnnotation.name, - _newerTypesReg - ); - if (newerAnnotationDefinition != null) { - return compareTypeAnnotation(newerAnnotationDefinition, olderAnnotation); - } - } - if (olderAnnotation.type === "TypeAliasTypeAnnotation") { - const olderAnnotationDefinition = lookupType( - olderAnnotation.name, - _olderTypesReg - ); - if (olderAnnotationDefinition != null) { - return compareTypeAnnotation(newerAnnotation, olderAnnotationDefinition); - } - } - (0, _invariant.default)( - newerAnnotation.type !== "TypeAliasTypeAnnotation" && - olderAnnotation.type !== "TypeAliasTypeAnnotation", - EQUALITY_MSG - ); - if (newerAnnotation.type !== olderAnnotation.type) { - if ( - newerAnnotation.type === "NullableTypeAnnotation" || - olderAnnotation.type === "NullableTypeAnnotation" - ) { - return compareNullableChange(newerAnnotation, olderAnnotation); - } - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Type annotations are not the same.", - newerAnnotation, - olderAnnotation - ) - ); - } - switch (newerAnnotation.type) { - case "AnyTypeAnnotation": - case "MixedTypeAnnotation": - case "DoubleTypeAnnotation": - case "FloatTypeAnnotation": - case "Int32TypeAnnotation": - case "BooleanTypeAnnotation": - case "NumberTypeAnnotation": - case "StringTypeAnnotation": - case "VoidTypeAnnotation": - return { - status: "matching", - }; - case "ArrayTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "ArrayTypeAnnotation", - EQUALITY_MSG - ); - return compareTypeAnnotation( - newerAnnotation.elementType, - olderAnnotation.elementType - ); - case "EnumDeclaration": - (0, _invariant.default)( - olderAnnotation.type === "EnumDeclaration", - EQUALITY_MSG - ); - return compareEnumDeclarations(newerAnnotation, olderAnnotation); - case "EnumDeclarationWithMembers": - (0, _invariant.default)( - olderAnnotation.type === "EnumDeclarationWithMembers", - EQUALITY_MSG - ); - return compareEnumDeclarationWithMembers( - newerAnnotation, - olderAnnotation - ); - case "FunctionTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "FunctionTypeAnnotation", - EQUALITY_MSG - ); - return compareFunctionTypes(newerAnnotation, olderAnnotation); - case "PromiseTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "PromiseTypeAnnotation", - EQUALITY_MSG - ); - return comparePromiseTypes(newerAnnotation, olderAnnotation); - case "GenericObjectTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "GenericObjectTypeAnnotation", - EQUALITY_MSG - ); - return compareGenericObjectTypes(newerAnnotation, olderAnnotation); - case "NullableTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "NullableTypeAnnotation", - EQUALITY_MSG - ); - return compareTypeAnnotation( - newerAnnotation.typeAnnotation, - olderAnnotation.typeAnnotation - ); - case "ObjectTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "ObjectTypeAnnotation", - EQUALITY_MSG - ); - return compareObjectTypes( - newerAnnotation.properties, - olderAnnotation.properties - ); - case "NumberLiteralTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "NumberLiteralTypeAnnotation", - EQUALITY_MSG - ); - return compareNumberLiteralTypes(newerAnnotation, olderAnnotation); - case "StringLiteralUnionTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "StringLiteralUnionTypeAnnotation", - EQUALITY_MSG - ); - return compareStringLiteralUnionTypes(newerAnnotation, olderAnnotation); - case "StringLiteralTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "StringLiteralTypeAnnotation", - EQUALITY_MSG - ); - return compareStringLiteralTypes(newerAnnotation, olderAnnotation); - case "UnionTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "UnionTypeAnnotation", - EQUALITY_MSG - ); - return compareUnionTypes(newerAnnotation, olderAnnotation); - case "EventEmitterTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "EventEmitterTypeAnnotation", - EQUALITY_MSG - ); - return compareEventEmitterTypes(newerAnnotation, olderAnnotation); - case "ReservedTypeAnnotation": - (0, _invariant.default)( - olderAnnotation.type === "ReservedTypeAnnotation", - EQUALITY_MSG - ); - return compareReservedTypeAnnotation(newerAnnotation, olderAnnotation); - default: - throw new Error(`Unsupported type annotation: ${newerAnnotation.type}`); - } -} -function compareObjectTypeProperty(first, second) { - if (first.name < second.name) { - return -1; - } else if (first.name > second.name) { - return 1; - } - return 0; -} -function compareEnumMember(first, second) { - if (first.name < second.name) { - return -1; - } else if (first.name > second.name) { - return 1; - } - return 0; -} -function updatePropertyError(name, newType, oldType, result) { - return (oldError) => { - const comparisonError = (0, - _ComparisonResult.typeAnnotationComparisonError)( - "has conflicting type changes", - newType, - oldType, - oldError - ); - const newFault = { - property: name, - fault: comparisonError, - }; - if (result.errorProperties) { - result.errorProperties.push(newFault); - } else { - result.errorProperties = [newFault]; - } - }; -} -function updateEnumMemberError(name, newType, oldType, result) { - return (oldError) => { - const comparisonError = (0, - _ComparisonResult.typeAnnotationComparisonError)( - "has conflicting changes", - newType, - oldType, - oldError - ); - const newFault = { - member: name, - fault: comparisonError, - }; - if (result.errorMembers) { - result.errorMembers.push(newFault); - } else { - result.errorMembers = [newFault]; - } - }; -} -function updateNestedProperties(name, propertyChange, result) { - if (result.nestedPropertyChanges) { - result.nestedPropertyChanges.push([name, propertyChange]); - } else { - result.nestedPropertyChanges = [[name, propertyChange]]; - } -} -function updateMadeOptional(name, result, furtherChange) { - if (result.madeOptional) { - result.madeOptional.push({ - property: name, - furtherChange, - }); - } else { - result.madeOptional = [ - { - property: name, - furtherChange, - }, - ]; - } -} -function updateMadeStrict(name, result, furtherChange) { - if (result.madeStrict) { - result.madeStrict.push({ - property: name, - furtherChange, - }); - } else { - result.madeStrict = [ - { - property: name, - furtherChange, - }, - ]; - } -} -function checkOptionalityChanges( - name, - newOptionality, - oldOptionality, - result, - furtherChange -) { - if (newOptionality === oldOptionality) { - if (furtherChange) { - updateNestedProperties(name, furtherChange, result); - } - return result; - } - if (newOptionality) { - updateMadeOptional(name, result, furtherChange); - } else { - updateMadeStrict(name, result, furtherChange); - } - return result; -} -function comparePropertyArrays(newerOriginal, olderOriginal) { - const newer = newerOriginal.slice(0); - const older = olderOriginal.slice(0); - if (newer.length === 0 && older.length === 0) { - return {}; - } - if (newer.length === 0) { - return { - missingProperties: older, - }; - } - if (older.length === 0) { - return { - addedProperties: newer, - }; - } - const newerHead = newer.pop(); - const olderHead = older.pop(); - (0, _invariant.default)( - newerHead != null && olderHead != null, - "Array is empty" - ); - const newerName = newerHead.name; - const olderName = olderHead.name; - if (newerName === olderName) { - const comparedTypes = compareTypeAnnotation( - newerHead.typeAnnotation, - olderHead.typeAnnotation - ); - const result = comparePropertyArrays(newer, older); - switch (comparedTypes.status) { - case "matching": - return checkOptionalityChanges( - newerName, - newerHead.optional, - olderHead.optional, - result - ); - case "skipped": - throw new Error( - "Internal error: returned 'skipped' for non-optional older type" - ); - case "nullableChange": - return checkOptionalityChanges( - newerName, - !comparedTypes.nullableLog.optionsReduced, - comparedTypes.nullableLog.optionsReduced, - result - ); - case "members": - case "properties": - case "functionChange": - case "positionalTypeChange": - return checkOptionalityChanges( - newerName, - newerHead.optional, - olderHead.optional, - result, - comparedTypes - ); - case "error": - updatePropertyError( - newerName, - newerHead.typeAnnotation, - olderHead.typeAnnotation, - result - )(comparedTypes.errorLog); - return result; - default: - throw new Error("Unsupported status " + comparedTypes.status); - } - } - if (newerName > olderName) { - older.push(olderHead); - const result = comparePropertyArrays(newer, older); - if (result.hasOwnProperty("addedProperties") && result.addedProperties) { - result.addedProperties = result.addedProperties.concat([newerHead]); - } else { - result.addedProperties = [newerHead]; - } - return result; - } - newer.push(newerHead); - const result = comparePropertyArrays(newer, older); - if (result.hasOwnProperty("missingProperties") && result.missingProperties) { - result.missingProperties = result.missingProperties.concat([olderHead]); - } else { - result.missingProperties = [olderHead]; - } - return result; -} -function compareObjectTypes(newerPropertyTypes, olderPropertyTypes) { - if (newerPropertyTypes.length === 0 && olderPropertyTypes.length === 0) { - return { - status: "matching", - }; - } - const sortedNewerTypes = []; - newerPropertyTypes.forEach((prop) => sortedNewerTypes.push(prop)); - if (sortedNewerTypes.length !== 0) { - sortedNewerTypes.sort(compareObjectTypeProperty); - } - const sortedOlderTypes = []; - olderPropertyTypes.forEach((prop) => sortedOlderTypes.push(prop)); - if (sortedOlderTypes.length !== 0) { - sortedOlderTypes.sort(compareObjectTypeProperty); - } - if (sortedNewerTypes.length === 0) { - return { - status: "properties", - propertyLog: { - missingProperties: sortedOlderTypes, - }, - }; - } - if (sortedOlderTypes.length === 0) { - return { - status: "properties", - propertyLog: { - addedProperties: sortedNewerTypes, - }, - }; - } - const result = comparePropertyArrays(sortedNewerTypes, sortedOlderTypes); - if ((0, _ComparisonResult.isPropertyLogEmpty)(result)) { - return { - status: "matching", - }; - } - if (result.errorProperties) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.propertyComparisonError)( - result.errorProperties.length > 1 - ? "Object contained properties with type mismatches" - : "Object contained a property with a type mismatch", - result.errorProperties - ) - ); - } - if ( - (result.addedProperties && - result.addedProperties.length > 0 && - result.addedProperties.length === newerPropertyTypes.length) || - (result.missingProperties && - result.missingProperties.length > 0 && - result.missingProperties.length === olderPropertyTypes.length) - ) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Object types do not match.", - objectTypeAnnotation(newerPropertyTypes), - objectTypeAnnotation(olderPropertyTypes) - ) - ); - } - return { - status: "properties", - propertyLog: result, - }; -} -function objectTypeAnnotation(properties) { - return { - type: "ObjectTypeAnnotation", - properties, - baseTypes: [], - }; -} -function compareEnumDeclarations(newerDeclaration, olderDeclaration) { - if (newerDeclaration.memberType !== olderDeclaration.memberType) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "EnumDeclaration member types are not the same", - newerDeclaration, - olderDeclaration - ) - ); - } - const newerAnnotationDefinition = lookupEnum( - newerDeclaration.name, - _newerEnumMap - ); - const olderAnnotationDefinition = lookupEnum( - olderDeclaration.name, - _olderEnumMap - ); - (0, _invariant.default)( - newerAnnotationDefinition != null && olderAnnotationDefinition != null, - "Could not find enum definition" - ); - return compareTypeAnnotation( - newerAnnotationDefinition, - olderAnnotationDefinition - ); -} -function compareEnumDeclarationMemberArrays(newer, older) { - if (newer.length === 0 && older.length === 0) { - return {}; - } else if (newer.length === 0) { - return { - missingMembers: older, - }; - } else if (older.length === 0) { - return { - addedMembers: newer, - }; - } - const newerHead = newer.pop(); - const olderHead = older.pop(); - (0, _invariant.default)( - newerHead != null && olderHead != null, - "Array is empty" - ); - const newerName = newerHead.name; - const olderName = olderHead.name; - if (newerName === olderName) { - const comparedTypes = compareTypeAnnotation( - newerHead.value, - olderHead.value - ); - const result = compareEnumDeclarationMemberArrays(newer, older); - switch (comparedTypes.status) { - case "matching": - return result; - case "error": - updateEnumMemberError( - newerName, - newerHead.value, - olderHead.value, - result - )(comparedTypes.errorLog); - return result; - case "skipped": - throw new Error( - "Internal error: returned 'skipped' for non-optional older type" - ); - case "nullableChange": - case "properties": - case "functionChange": - case "positionalTypeChange": - case "members": - break; - default: - throw new Error("Unsupported status " + comparedTypes.status); - } - } else if (newerName > olderName) { - older.push(olderHead); - const result = compareEnumDeclarationMemberArrays(newer, older); - if (result.hasOwnProperty("addedMembers") && result.addedMembers) { - result.addedMembers.push(newerHead); - } else { - result.addedMembers = [newerHead]; - } - return result; - } else if (newerName < olderName) { - newer.push(newerHead); - const result = compareEnumDeclarationMemberArrays(newer, older); - if (result.hasOwnProperty("missingMembers") && result.missingMembers) { - result.missingMembers.push(olderHead); - } else { - result.missingMembers = [olderHead]; - } - return result; - } - throw new Error("Internal error: should not reach here"); -} -function compareEnumDeclarationWithMembers(newerDeclaration, olderDeclaration) { - const sortedNewerTypes = Array.from(newerDeclaration.members).sort( - compareEnumMember - ); - const sortedOlderTypes = Array.from(olderDeclaration.members).sort( - compareEnumMember - ); - const result = compareEnumDeclarationMemberArrays( - sortedNewerTypes, - sortedOlderTypes - ); - if ((0, _ComparisonResult.isMemberLogEmpty)(result)) { - return { - status: "matching", - }; - } else if (result.errorMembers) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Enum types do not match", - newerDeclaration, - olderDeclaration, - (0, _ComparisonResult.memberComparisonError)( - result.errorMembers.length > 1 - ? "Enum contained members with type mismatches" - : "Enum contained a member with a type mismatch", - result.errorMembers - ) - ) - ); - } else if ( - (result.addedMembers && - result.addedMembers.length > 0 && - result.addedMembers.length === newerDeclaration.members.length) || - (result.missingMembers && - result.missingMembers.length > 0 && - result.missingMembers.length === olderDeclaration.members.length) - ) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Enum types do not match.", - newerDeclaration, - olderDeclaration - ) - ); - } - return { - status: "members", - memberLog: result, - }; -} -function compareNullableChange(newerAnnotation, olderAnnotation) { - const newVoidRemoved = - newerAnnotation.type === "NullableTypeAnnotation" - ? removeNullableTypeAnnotations(newerAnnotation) - : newerAnnotation; - const oldVoidRemoved = - olderAnnotation.type === "NullableTypeAnnotation" - ? removeNullableTypeAnnotations(olderAnnotation) - : olderAnnotation; - const optionalNew = newVoidRemoved.type !== newerAnnotation.type; - const optionalOld = oldVoidRemoved.type !== olderAnnotation.type; - (0, _invariant.default)( - optionalNew !== optionalOld, - "compareNullableChange called with both being nullable" - ); - const optionsReduced = !optionalNew && optionalOld; - if ( - newVoidRemoved.type === "VoidTypeAnnotation" || - oldVoidRemoved.type === "VoidTypeAnnotation" - ) { - return { - status: "nullableChange", - nullableLog: { - typeRefined: true, - optionsReduced, - interiorLog: null, - newType: newerAnnotation, - oldType: olderAnnotation, - }, - }; - } - const interiorLog = compareTypeAnnotation(newVoidRemoved, oldVoidRemoved); - switch (interiorLog.status) { - case "error": - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Type annotations are not the same.", - newerAnnotation, - olderAnnotation - ) - ); - case "matching": - return { - status: "nullableChange", - nullableLog: { - typeRefined: false, - optionsReduced, - interiorLog, - newType: newerAnnotation, - oldType: olderAnnotation, - }, - }; - default: - return { - status: "nullableChange", - nullableLog: { - typeRefined: false, - optionsReduced, - interiorLog, - newType: newerAnnotation, - oldType: olderAnnotation, - }, - }; - } -} -function compareUnionTypes(newerType, olderType) { - if (newerType.memberType !== olderType.memberType) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Union member type does not match", - newerType, - olderType - ) - ); - } - return { - status: "matching", - }; -} -function comparePromiseTypes(newerType, olderType) { - if (newerType.elementType == null || olderType.elementType == null) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Promise has differing arguments", - newerType, - olderType - ) - ); - } - (0, _invariant.default)( - newerType.elementType != null && olderType.elementType != null, - EQUALITY_MSG - ); - return compareTypeAnnotation(newerType.elementType, olderType.elementType); -} -function compareGenericObjectTypes(newerType, olderType) { - if ( - newerType.dictionaryValueType == null && - olderType.dictionaryValueType == null - ) { - return { - status: "matching", - }; - } - if ( - newerType.dictionaryValueType != null && - olderType.dictionaryValueType != null - ) { - return compareTypeAnnotation( - newerType.dictionaryValueType, - olderType.dictionaryValueType - ); - } - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Generic Object types do not have matching dictionary types", - newerType, - olderType - ) - ); -} -function compareNumberLiteralTypes(newerType, olderType) { - return newerType.value === olderType.value - ? { - status: "matching", - } - : (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Numeric literals are not equal", - newerType, - olderType - ) - ); -} -function compareStringLiteralTypes(newerType, olderType) { - return newerType.value === olderType.value - ? { - status: "matching", - } - : (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "String literals are not equal", - newerType, - olderType - ) - ); -} -function compareStringLiteralUnionTypes(newerType, olderType) { - const results = compareArrayOfTypes( - true, - false, - newerType.types, - olderType.types - ); - switch (results.status) { - case "length-mismatch": - throw new Error("length-mismatch returned with length changes allowed"); - case "type-mismatch": - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - `Subtype of union at position ${results.newIndex} did not match`, - newerType, - olderType, - results.error - ) - ); - case "subtypable-changes": - if (results.nestedChanges.length > 0) { - throw new Error( - "Unexpected inline objects/functions in string literal union" - ); - } - if (results.addedElements.length > 0) { - return { - status: "positionalTypeChange", - changeLog: { - typeKind: "stringUnion", - nestedChanges: [], - addedElements: results.addedElements, - }, - }; - } - if (results.removedElements.length > 0) { - return { - status: "positionalTypeChange", - changeLog: { - typeKind: "stringUnion", - nestedChanges: [], - removedElements: results.removedElements, - }, - }; - } - console.log(JSON.stringify(results)); - throw new Error("string union returned unexpected set of changes"); - case "matching": - return { - status: "matching", - }; - default: - throw new Error("Unknown status"); - } -} -function compareFunctionTypes(newerType, olderType) { - const returnTypeResult = compareTypeAnnotation( - newerType.returnTypeAnnotation, - olderType.returnTypeAnnotation - ); - if (returnTypeResult.status === "error") { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Function return types do not match", - newerType, - olderType, - returnTypeResult.errorLog - ) - ); - } - const functionChanges = {}; - if ( - returnTypeResult.status === "properties" || - returnTypeResult.status === "members" || - returnTypeResult.status === "functionChange" || - returnTypeResult.status === "positionalTypeChange" || - returnTypeResult.status === "nullableChange" - ) { - functionChanges.returnType = returnTypeResult; - } - const argumentResults = compareArrayOfTypes( - true, - true, - newerType.params.map((_) => _.typeAnnotation), - olderType.params.map((_) => _.typeAnnotation) - ); - switch (argumentResults.status) { - case "length-mismatch": - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Function types have differing length of arguments", - newerType, - olderType - ) - ); - case "type-mismatch": - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - `Parameter at index ${argumentResults.newIndex} did not match`, - newerType, - olderType, - argumentResults.error - ) - ); - case "subtypable-changes": - functionChanges.parameterTypes = { - typeKind: "parameter", - nestedChanges: argumentResults.nestedChanges, - }; - break; - case "matching": - default: - break; - } - if ((0, _ComparisonResult.isFunctionLogEmpty)(functionChanges)) { - return { - status: "matching", - }; - } - return { - status: "functionChange", - functionChangeLog: functionChanges, - }; -} -function compareArrayOfTypes(fixedOrder, fixedLength, newerTypes, olderTypes) { - const sameLength = newerTypes.length === olderTypes.length; - if (fixedLength && !sameLength) { - return { - status: "length-mismatch", - }; - } - const nestedChanges = []; - const minLength = Math.min(newerTypes.length, olderTypes.length); - if (fixedOrder) { - for (let i = 0; i < minLength; i++) { - const result = compareTypeAnnotation(newerTypes[i], olderTypes[i]); - if (result.status === "error") { - return { - status: "type-mismatch", - error: result.errorLog, - newIndex: i, - oldIndex: i, - }; - } - if ( - result.status === "properties" || - result.status === "members" || - result.status === "functionChange" || - result.status === "positionalTypeChange" || - result.status === "nullableChange" - ) { - nestedChanges.push([i, i, result]); - } - } - if (nestedChanges.length === 0 && sameLength) { - return { - status: "matching", - }; - } - const addedElements = []; - const removedElements = []; - if (newerTypes.length < olderTypes.length) { - const elements = olderTypes.slice(minLength, olderTypes.length); - for (let i = 0; i < elements.length; i++) { - removedElements.push([i + minLength + 1, elements[i]]); - } - } - if (newerTypes.length > olderTypes.length) { - const elements = newerTypes.slice(minLength, newerTypes.length); - for (let i = 0; i < elements.length; i++) { - addedElements.push([i + minLength + 1, elements[i]]); - } - } - return { - status: "subtypable-changes", - nestedChanges, - addedElements, - removedElements, - }; - } - return compareArrayTypesOutOfOrder( - (0, _SortTypeAnnotations.sortTypeAnnotations)(newerTypes), - 0, - (0, _SortTypeAnnotations.sortTypeAnnotations)(olderTypes), - 0, - [], - [], - [] - ); -} -function compareArrayTypesOutOfOrder( - newerTypes, - newerIndex, - olderTypes, - olderIndex, - potentiallyAddedElements, - potentiallyRemovedElements, - nestedChanges -) { - const newLength = newerTypes.length; - const oldLength = olderTypes.length; - if (newerIndex === newLength || olderIndex === oldLength) { - const [errors, added, removed] = resolvePotentials( - potentiallyAddedElements, - potentiallyRemovedElements - ); - if (errors.length !== 0) { - return { - status: "type-mismatch", - error: errors[0][0], - oldIndex: errors[0][1], - newIndex: errors[0][2], - }; - } - if ( - added.length === 0 && - removed.length === 0 && - nestedChanges.length === 0 && - newerIndex === newLength && - olderIndex === oldLength - ) { - return { - status: "matching", - }; - } - if (newerIndex === newLength && olderIndex === oldLength) { - return { - status: "subtypable-changes", - nestedChanges, - addedElements: added, - removedElements: removed, - }; - } - if (newerIndex === newLength) { - return { - status: "subtypable-changes", - nestedChanges, - addedElements: added, - removedElements: removed.concat( - olderTypes.slice(olderIndex, oldLength) - ), - }; - } - return { - status: "subtypable-changes", - nestedChanges, - addedElements: added.concat(newerTypes.slice(newerIndex, newLength)), - removedElements: removed, - }; - } - const newTypePosn = newerTypes[newerIndex][0]; - const newType = newerTypes[newerIndex][1]; - const oldTypePosn = olderTypes[olderIndex][0]; - const oldType = olderTypes[olderIndex][1]; - const currentResult = compareTypeAnnotation(newType, oldType); - const sortComparison = (0, - _SortTypeAnnotations.compareTypeAnnotationForSorting)( - newerTypes[newerIndex], - olderTypes[olderIndex] - ); - switch (currentResult.status) { - case "matching": - return compareArrayTypesOutOfOrder( - newerTypes, - newerIndex + 1, - olderTypes, - olderIndex + 1, - potentiallyAddedElements, - potentiallyRemovedElements, - nestedChanges - ); - case "properties": - case "functionChange": - case "positionalTypeChange": - case "nullableChange": - return compareArrayTypesOutOfOrder( - newerTypes, - newerIndex + 1, - olderTypes, - olderIndex + 1, - potentiallyAddedElements, - potentiallyRemovedElements, - nestedChanges.concat[[oldTypePosn, newTypePosn, currentResult]] - ); - case "error": - if (sortComparison === 0) { - return { - status: "type-mismatch", - error: currentResult.errorLog, - newIndex: newTypePosn, - oldIndex: oldTypePosn, - }; - } - if (sortComparison < 0) { - return compareArrayTypesOutOfOrder( - newerTypes, - newerIndex + 1, - olderTypes, - olderIndex, - potentiallyAddedElements.concat([ - { - olderPosition: oldTypePosn, - newerPosition: newTypePosn, - error: currentResult.errorLog, - annotation: newType, - }, - ]), - potentiallyRemovedElements, - nestedChanges - ); - } - return compareArrayTypesOutOfOrder( - newerTypes, - newerIndex, - olderTypes, - olderIndex + 1, - potentiallyAddedElements, - potentiallyRemovedElements.concat([ - { - olderPosition: oldTypePosn, - newerPosition: newTypePosn, - error: currentResult.errorLog, - annotation: oldType, - }, - ]), - nestedChanges - ); - case "skipped": - throw new Error( - "Unexpected skipped status for array of type annotations" - ); - default: - throw new Error("Unsupported status " + currentResult.status); - } -} -function resolvePotentials(potentiallyAdded, potentiallyRemoved) { - const addedLength = potentiallyAdded.length; - const removedLength = potentiallyRemoved.length; - if (addedLength === 0 && removedLength === 0) { - return [[], [], []]; - } - if (addedLength === 0) { - return [ - [], - [], - potentiallyRemoved.map((removed) => [ - removed.olderPosition, - removed.annotation, - ]), - ]; - } - if (removedLength === 0) { - return [ - [], - potentiallyAdded.map((added) => [added.newerPosition, added.annotation]), - [], - ]; - } - const addedHead = potentiallyAdded[0]; - const removedHead = potentiallyRemoved[0]; - if (addedHead.olderPosition === removedHead.olderPosition) { - return [ - [[addedHead.error, addedHead.olderPosition, addedHead.newerPosition]], - [], - [], - ]; - } - if (removedHead.newerPosition === addedHead.newerPosition) { - return [ - [ - [ - removedHead.error, - removedHead.olderPosition, - removedHead.newerPosition, - ], - ], - [], - [], - ]; - } - const sortedOrder = (0, _SortTypeAnnotations.compareTypeAnnotationForSorting)( - [addedHead.newerPosition, addedHead.annotation], - [removedHead.olderPosition, removedHead.annotation] - ); - if (sortedOrder === 0) { - const [errors, added, removed] = resolvePotentials( - potentiallyAdded.slice(1, addedLength), - potentiallyRemoved.slice(1, removedLength) - ); - return [ - errors, - added.concat([[addedHead.newerPosition, addedHead.annotation]]), - removed.concat([[removedHead.olderPosition, removedHead.annotation]]), - ]; - } - if (sortedOrder < 0) { - const [errors, added, removed] = resolvePotentials( - potentiallyAdded.slice(1, addedLength), - potentiallyRemoved - ); - return [ - errors, - added.concat([[addedHead.newerPosition, addedHead.annotation]]), - removed, - ]; - } - const [errors, added, removed] = resolvePotentials( - potentiallyAdded, - potentiallyRemoved.slice(1, removedLength) - ); - return [ - errors, - added, - removed.concat([[removedHead.olderPosition, removedHead.annotation]]), - ]; -} -function compareEventEmitterTypes(newerAnnotation, olderAnnotation) { - const comparison = compareTypeAnnotation( - newerAnnotation.typeAnnotation, - olderAnnotation.typeAnnotation - ); - if (comparison.status === "error") { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "EventEmitter eventTypes are not equivalent", - newerAnnotation, - olderAnnotation, - comparison.errorLog - ) - ); - } - return comparison; -} -function compareReservedTypeAnnotation(newerAnnotation, olderAnnotation) { - if (newerAnnotation.name !== olderAnnotation.name) { - return (0, _ComparisonResult.makeError)( - (0, _ComparisonResult.typeAnnotationComparisonError)( - "Types are not equivalent", - newerAnnotation, - olderAnnotation - ) - ); - } - switch (newerAnnotation.name) { - case "RootTag": - case "ColorPrimitive": - case "ImageSourcePrimitive": - case "PointPrimitive": - case "EdgeInsetsPrimitive": - case "ImageRequestPrimitive": - case "DimensionPrimitive": - return { - status: "matching", - }; - default: - newerAnnotation.name; - throw new Error("Unknown reserved type " + newerAnnotation.name); - } -} diff --git a/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow b/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow deleted file mode 100644 index 4b444655e0ad69..00000000000000 --- a/packages/react-native-compatibility-check/dist/TypeDiffing.js.flow +++ /dev/null @@ -1,99 +0,0 @@ -/** - * 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 { - ComparisonResult, - MembersComparisonResult, -} from "./ComparisonResult"; -import type { - CompleteTypeAnnotation, - NamedShape, - NativeModuleAliasMap, - NativeModuleEnumDeclaration, - NativeModuleEnumDeclarationWithMembers, - NativeModuleEnumMap, - NativeModuleEnumMember, - NativeModuleFunctionTypeAnnotation, - NativeModuleGenericObjectTypeAnnotation, - NativeModulePromiseTypeAnnotation, - NativeModuleUnionTypeAnnotation, - NumberLiteralTypeAnnotation, - StringLiteralTypeAnnotation, - StringLiteralUnionTypeAnnotation, -} from "@react-native/codegen/src/CodegenSchema"; - -declare export function compareTypes( - newerType: CompleteTypeAnnotation, - olderType: ?CompleteTypeAnnotation, - newerTypesReg: ?NativeModuleAliasMap, - olderTypesReg: ?NativeModuleAliasMap, - newerEnumMap: ?NativeModuleEnumMap, - olderEnumMap: ?NativeModuleEnumMap -): ComparisonResult; - -declare export function compareTypeAnnotation( - originalNewerAnnotation: CompleteTypeAnnotation, - originalOlderAnnotation: CompleteTypeAnnotation -): ComparisonResult; - -declare export function compareObjectTypes( - newerPropertyTypes: $ReadOnlyArray>, - olderPropertyTypes: $ReadOnlyArray> -): ComparisonResult; - -declare export function compareEnumDeclarations( - newerDeclaration: NativeModuleEnumDeclaration, - olderDeclaration: NativeModuleEnumDeclaration -): ComparisonResult; - -declare export function compareEnumDeclarationMemberArrays( - newer: Array, - older: Array -): MembersComparisonResult; - -declare export function compareEnumDeclarationWithMembers( - newerDeclaration: NativeModuleEnumDeclarationWithMembers, - olderDeclaration: NativeModuleEnumDeclarationWithMembers -): ComparisonResult; - -declare export function compareUnionTypes( - newerType: NativeModuleUnionTypeAnnotation, - olderType: NativeModuleUnionTypeAnnotation -): ComparisonResult; - -declare export function comparePromiseTypes( - newerType: NativeModulePromiseTypeAnnotation, - olderType: NativeModulePromiseTypeAnnotation -): ComparisonResult; - -declare export function compareGenericObjectTypes( - newerType: NativeModuleGenericObjectTypeAnnotation, - olderType: NativeModuleGenericObjectTypeAnnotation -): ComparisonResult; - -declare export function compareNumberLiteralTypes( - newerType: NumberLiteralTypeAnnotation, - olderType: NumberLiteralTypeAnnotation -): ComparisonResult; - -declare export function compareStringLiteralTypes( - newerType: StringLiteralTypeAnnotation, - olderType: StringLiteralTypeAnnotation -): ComparisonResult; - -declare export function compareStringLiteralUnionTypes( - newerType: StringLiteralUnionTypeAnnotation, - olderType: StringLiteralUnionTypeAnnotation -): ComparisonResult; - -declare export function compareFunctionTypes( - newerType: NativeModuleFunctionTypeAnnotation, - olderType: NativeModuleFunctionTypeAnnotation -): ComparisonResult; diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts b/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts deleted file mode 100644 index b02067659e3ecc..00000000000000 --- a/packages/react-native-compatibility-check/dist/VersionDiffing.d.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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 - */ - -import type { ComparisonResult } from "./ComparisonResult"; -import type { - DiffSet, - DiffSummary, - ErrorStore, - ObjectTypeChangeStore, - SchemaDiff, -} from "./DiffResults"; -import type { - CompleteTypeAnnotation, - SchemaType, -} from "@react-native/codegen/src/CodegenSchema"; -type BoundaryDirection = "toNative" | "fromNative" | "both"; -export declare const removedPropertiesMessage: "Object removed required properties expected by native"; -export declare const addedPropertiesMessage: "Object added required properties, which native will not provide"; -export declare const stricterPropertiesMessage: "Property made strict, but native may not provide it"; -export declare const tooOptionalPropertiesMessage: "Property made optional, but native requires it"; -export declare const removedUnionMessage: "Union removed items, but native may still provide them"; -export declare const addedUnionMessage: "Union added items, but native will not expect/support them"; -export declare const removedEnumMessage: "Enum removed items, but native may still provide them"; -export declare const addedEnumMessage: "Enum added items, but native will not expect/support them"; -export declare const removedIntersectionMessage: "Intersection removed items, but native may still require properties contained in them"; -export declare const addedIntersectionMessage: "Intersection added items, but native may not provide all required attributes"; -export declare const toNativeVoidChangeMessage: "Native may not be able to safely handle presence of type"; -export declare const typeNullableChangeMessage: "Type made nullable, but native requires it"; -export declare const fromNativeVoidChangeMessage: "Type set to void but native may still provide a value"; -export declare const typeNonNullableChangeMessage: "Type made non-nullable, but native might provide null still"; -export declare function assessComparisonResult( - newTypes: Set<{ typeName: string; typeInformation: CompleteTypeAnnotation }>, - deprecatedTypes: Set<{ - typeName: string; - typeInformation: CompleteTypeAnnotation; - }>, - incompatibleChanges: Set, - objectTypeChanges: Set -): ( - typeName: string, - newType: CompleteTypeAnnotation, - oldType: null | undefined | CompleteTypeAnnotation, - difference: ComparisonResult, - oldDirection: BoundaryDirection -) => void; -export declare function hasUpdatesTypes(diff: DiffSet): boolean; -export declare function hasCodegenUpdatesTypes(diff: DiffSet): boolean; -export declare function buildSchemaDiff( - newerSchemaSet: SchemaType, - olderSchemaSet: SchemaType -): Set; -export declare function summarizeDiffSet(diffs: Set): DiffSummary; diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.js b/packages/react-native-compatibility-check/dist/VersionDiffing.js deleted file mode 100644 index 4eb67d770f9d94..00000000000000 --- a/packages/react-native-compatibility-check/dist/VersionDiffing.js +++ /dev/null @@ -1,1235 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.addedUnionMessage = - exports.addedPropertiesMessage = - exports.addedIntersectionMessage = - exports.addedEnumMessage = - void 0; -exports.assessComparisonResult = assessComparisonResult; -exports.buildSchemaDiff = buildSchemaDiff; -exports.fromNativeVoidChangeMessage = void 0; -exports.hasCodegenUpdatesTypes = hasCodegenUpdatesTypes; -exports.hasUpdatesTypes = hasUpdatesTypes; -exports.stricterPropertiesMessage = - exports.removedUnionMessage = - exports.removedPropertiesMessage = - exports.removedIntersectionMessage = - exports.removedEnumMessage = - void 0; -exports.summarizeDiffSet = summarizeDiffSet; -exports.typeNullableChangeMessage = - exports.typeNonNullableChangeMessage = - exports.tooOptionalPropertiesMessage = - exports.toNativeVoidChangeMessage = - void 0; -var _ComparisonResult = require("./ComparisonResult.js"); -var _convertPropToBasicTypes = _interopRequireDefault( - require("./convertPropToBasicTypes") -); -var codegenTypeDiffing = _interopRequireWildcard(require("./TypeDiffing")); -function _getRequireWildcardCache(e) { - if ("function" != typeof WeakMap) return null; - var r = new WeakMap(), - t = new WeakMap(); - return (_getRequireWildcardCache = function (e) { - return e ? t : r; - })(e); -} -function _interopRequireWildcard(e, r) { - if (!r && e && e.__esModule) return e; - if (null === e || ("object" != typeof e && "function" != typeof e)) - return { default: e }; - var t = _getRequireWildcardCache(r); - if (t && t.has(e)) return t.get(e); - var n = { __proto__: null }, - a = Object.defineProperty && Object.getOwnPropertyDescriptor; - for (var u in e) - if ("default" !== u && {}.hasOwnProperty.call(e, u)) { - var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; - i && (i.get || i.set) ? Object.defineProperty(n, u, i) : (n[u] = e[u]); - } - return (n.default = e), t && t.set(e, n), n; -} -function _interopRequireDefault(e) { - return e && e.__esModule ? e : { default: e }; -} -function nestedPropertiesCheck(typeName, result, check, inverseCheck) { - const nestedMap = - (mid, end) => - ([propertyName, comparisonResult]) => - nestedPropertiesCheck( - typeName + mid + propertyName + end, - comparisonResult, - check, - inverseCheck - ); - switch (result.status) { - case "error": - case "matching": - case "skipped": - throw new Error( - "Internal error: nested property change " + result.status - ); - case "properties": - let finalResult = check(result.propertyLog, null, null, null, typeName); - if (result.propertyLog.nestedPropertyChanges) { - finalResult = combine( - finalResult, - result.propertyLog.nestedPropertyChanges.map(nestedMap(".", "")) - ); - } - if (result.propertyLog.madeOptional) { - const furtherNestedProps = result.propertyLog.madeOptional.filter( - (optionalProp) => optionalProp.furtherChanges - ); - if (furtherNestedProps && furtherNestedProps.length > 0) { - const localNestedMap = nestedMap(".", ""); - const mappedProps = furtherNestedProps.map((optionalProp) => { - if (optionalProp.furtherChanges) { - return localNestedMap([ - optionalProp.property, - optionalProp.furtherChanges, - ]); - } - throw new Error("Internal error, filter failed"); - }); - finalResult = combine(finalResult, mappedProps); - } - } - return finalResult; - case "members": - return check(null, null, null, result.memberLog, typeName); - case "functionChange": - let returnTypeResult = []; - if (result.functionChangeLog.returnType) { - returnTypeResult = nestedPropertiesCheck( - typeName, - result.functionChangeLog.returnType, - check, - inverseCheck - ); - } - if (result.functionChangeLog.parameterTypes) { - return combine( - returnTypeResult, - result.functionChangeLog.parameterTypes.nestedChanges.map( - ([_oldParameterNumber, newParameterNumber, comparisonResult]) => - nestedPropertiesCheck( - typeName + " parameter " + newParameterNumber, - comparisonResult, - inverseCheck, - check - ) - ) - ); - } - return returnTypeResult; - case "positionalTypeChange": - const changeLog = result.changeLog; - const currentPositionalCheck = check( - null, - changeLog, - null, - null, - typeName - ); - return combine( - currentPositionalCheck, - changeLog.nestedChanges.map(([_oldIndex, newIndex, nestedChange]) => - nestedMap( - " element ", - " of " + changeLog.typeKind - )([newIndex.toString(), nestedChange]) - ) - ); - case "nullableChange": - const currentCheck = check( - null, - null, - result.nullableLog, - null, - typeName - ); - if (result.nullableLog.interiorLog) { - const interiorLog = result.nullableLog.interiorLog; - switch (interiorLog.status) { - case "matching": - return currentCheck; - case "properties": - case "functionChange": - case "positionalTypeChange": - case "nullableChange": - return combine(currentCheck, [ - nestedPropertiesCheck(typeName, interiorLog, check, inverseCheck), - ]); - default: - throw new Error( - "Internal error: nested with error or skipped status" - ); - } - } - return currentCheck; - default: - result.status; - return []; - } -} -function checkOptionalityAndSetError(typeName, properties, msg, errorCode) { - const requiredProperties = properties.filter( - (objectTypeProperty) => !objectTypeProperty.optional - ); - if (requiredProperties.length > 0) { - return [ - { - typeName, - errorCode, - errorInformation: (0, _ComparisonResult.propertyComparisonError)( - msg, - requiredProperties.map((property) => ({ - property: property.name, - })) - ), - }, - ]; - } - return []; -} -const removedPropertiesMessage = (exports.removedPropertiesMessage = - "Object removed required properties expected by native"); -function checkForUnsafeRemovedProperties( - propertyChange, - _postionalChange, - _nullableChange, - _memberChange, - typeName -) { - if (propertyChange && propertyChange.missingProperties) { - return checkOptionalityAndSetError( - typeName, - propertyChange.missingProperties, - removedPropertiesMessage, - "removedProps" - ); - } - return []; -} -const addedPropertiesMessage = (exports.addedPropertiesMessage = - "Object added required properties, which native will not provide"); -function checkForUnsafeAddedProperties( - propertyChange, - _positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if (propertyChange && propertyChange.addedProperties) { - return checkOptionalityAndSetError( - typeName, - propertyChange.addedProperties, - addedPropertiesMessage, - "addedProps" - ); - } - return []; -} -const stricterPropertiesMessage = (exports.stricterPropertiesMessage = - "Property made strict, but native may not provide it"); -function checkForUnSafeMadeStrictProperties( - propertyChange, - _positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - propertyChange && - propertyChange.madeStrict && - propertyChange.madeStrict.length > 0 - ) { - const err = (0, _ComparisonResult.propertyComparisonError)( - stricterPropertiesMessage, - propertyChange.madeStrict.map((property) => ({ - property: property.property, - })) - ); - return [ - { - typeName, - errorCode: "requiredProps", - errorInformation: err, - }, - ]; - } - return []; -} -const tooOptionalPropertiesMessage = (exports.tooOptionalPropertiesMessage = - "Property made optional, but native requires it"); -function checkForUnSafeMadeOptionalProperties( - propertyChange, - _positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - propertyChange && - propertyChange.madeOptional && - propertyChange.madeOptional.length > 0 - ) { - const err = (0, _ComparisonResult.propertyComparisonError)( - tooOptionalPropertiesMessage, - propertyChange.madeOptional.map((property) => ({ - property: property.property, - })) - ); - return [ - { - typeName, - errorCode: "optionalProps", - errorInformation: err, - }, - ]; - } - return []; -} -const removedUnionMessage = (exports.removedUnionMessage = - "Union removed items, but native may still provide them"); -function checkForUnsafeRemovedUnionItems( - _propertyChange, - positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - positionalChange && - (positionalChange.typeKind === "union" || - positionalChange.typeKind === "stringUnion") && - positionalChange.removedElements && - positionalChange.removedElements.length > 0 - ) { - return [ - { - typeName, - errorCode: "removedUnionCases", - errorInformation: (0, _ComparisonResult.positionalComparisonError)( - removedUnionMessage, - positionalChange.removedElements - ), - }, - ]; - } - return []; -} -const addedUnionMessage = (exports.addedUnionMessage = - "Union added items, but native will not expect/support them"); -function checkForUnsafeAddedUnionItems( - _propertyChange, - positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - positionalChange && - (positionalChange.typeKind === "union" || - positionalChange.typeKind === "stringUnion") && - positionalChange.addedElements && - positionalChange.addedElements.length > 0 - ) { - return [ - { - typeName, - errorCode: "addedUnionCases", - errorInformation: (0, _ComparisonResult.positionalComparisonError)( - addedUnionMessage, - positionalChange.addedElements - ), - }, - ]; - } - return []; -} -const removedEnumMessage = (exports.removedEnumMessage = - "Enum removed items, but native may still provide them"); -function checkForUnsafeRemovedEnumItems( - _propertyChange, - _positionalChange, - _nullableChange, - memberChange, - typeName -) { - if (memberChange?.missingMembers && memberChange?.missingMembers.length > 0) { - return [ - { - typeName, - errorCode: "removedEnumCases", - errorInformation: (0, _ComparisonResult.memberComparisonError)( - removedEnumMessage, - memberChange.missingMembers.map((member) => ({ - member: member.name, - })) - ), - }, - ]; - } - return []; -} -const addedEnumMessage = (exports.addedEnumMessage = - "Enum added items, but native will not expect/support them"); -function checkForUnsafeAddedEnumItems( - _propertyChange, - _positionalChange, - _nullableChange, - memberChange, - typeName -) { - if (memberChange?.addedMembers && memberChange?.addedMembers.length > 0) { - return [ - { - typeName, - errorCode: "addedEnumCases", - errorInformation: (0, _ComparisonResult.memberComparisonError)( - addedEnumMessage, - memberChange.addedMembers.map((member) => ({ - member: member.name, - })) - ), - }, - ]; - } - return []; -} -const removedIntersectionMessage = (exports.removedIntersectionMessage = - "Intersection removed items, but native may still require properties contained in them"); -function checkForUnsafeRemovedIntersectionItems( - _propertyChange, - positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - positionalChange && - positionalChange.typeKind === "intersection" && - positionalChange.removedElements && - positionalChange.removedElements.length > 0 - ) { - return [ - { - typeName, - errorCode: "removedIntersectCases", - errorInformation: (0, _ComparisonResult.positionalComparisonError)( - removedIntersectionMessage, - positionalChange.removedElements - ), - }, - ]; - } - return []; -} -const addedIntersectionMessage = (exports.addedIntersectionMessage = - "Intersection added items, but native may not provide all required attributes"); -function checkForUnsafeAddedIntersectionItems( - _propertyChange, - positionalChange, - _nullableChange, - _memberChange, - typeName -) { - if ( - positionalChange && - positionalChange.typeKind === "intersection" && - positionalChange.addedElements && - positionalChange.addedElements.length > 0 - ) { - return [ - { - typeName, - errorCode: "addedIntersectCases", - errorInformation: (0, _ComparisonResult.positionalComparisonError)( - addedIntersectionMessage, - positionalChange.addedElements - ), - }, - ]; - } - return []; -} -const toNativeVoidChangeMessage = (exports.toNativeVoidChangeMessage = - "Native may not be able to safely handle presence of type"); -const typeNullableChangeMessage = (exports.typeNullableChangeMessage = - "Type made nullable, but native requires it"); -function checkForUnsafeNullableToNativeChange( - _propertyChange, - _positionalChange, - nullableChange, - _memberChange, - typeName -) { - if ( - nullableChange && - !nullableChange.optionsReduced && - nullableChange.newType && - nullableChange.oldType - ) { - return [ - { - typeName, - errorCode: "nullableOfNonNull", - errorInformation: (0, _ComparisonResult.typeAnnotationComparisonError)( - nullableChange.typeRefined - ? toNativeVoidChangeMessage - : typeNullableChangeMessage, - nullableChange.newType, - nullableChange.oldType - ), - }, - ]; - } - return []; -} -const fromNativeVoidChangeMessage = (exports.fromNativeVoidChangeMessage = - "Type set to void but native may still provide a value"); -const typeNonNullableChangeMessage = (exports.typeNonNullableChangeMessage = - "Type made non-nullable, but native might provide null still"); -function checkForUnsafeNullableFromNativeChange( - _propertyChange, - _positionalChange, - nullableChange, - _memberChange, - typeName -) { - if ( - nullableChange && - nullableChange.optionsReduced && - nullableChange.newType && - nullableChange.oldType - ) { - return [ - { - typeName, - errorCode: "nonNullableOfNull", - errorInformation: (0, _ComparisonResult.typeAnnotationComparisonError)( - nullableChange.typeRefined - ? fromNativeVoidChangeMessage - : typeNonNullableChangeMessage, - nullableChange.newType, - nullableChange.oldType - ), - }, - ]; - } - return []; -} -function chainPropertiesChecks(checks) { - return ( - propertyChange, - positionalChange, - nullableChange, - memberChange, - typeName - ) => - checks.reduce( - (errorStore, checker) => - errorStore.concat( - checker( - propertyChange, - positionalChange, - nullableChange, - memberChange, - typeName - ) - ), - [] - ); -} -function combine(singleton, arrayOf) { - if (arrayOf.length > 0) { - return arrayOf.reduce( - (finalErrorArray, current) => finalErrorArray.concat(current), - singleton - ); - } - return singleton; -} -function compareFunctionTypesInContext( - typeName, - functionLog, - check, - inversecheck, - result -) { - if (functionLog.returnType) { - result = combine(result, [ - nestedPropertiesCheck( - typeName, - functionLog.returnType, - check, - inversecheck - ), - ]); - } - if ( - functionLog.parameterTypes && - functionLog.parameterTypes.nestedChanges.length > 0 - ) { - result = combine( - result, - functionLog.parameterTypes.nestedChanges.map( - ([_oldPropertyNum, newPropertyNum, comparisonResult]) => - nestedPropertiesCheck( - typeName + " parameter " + newPropertyNum, - comparisonResult, - inversecheck, - check - ) - ) - ); - } - return result; -} -const checksForTypesFlowingToNative = chainPropertiesChecks([ - checkForUnsafeRemovedProperties, - checkForUnSafeMadeOptionalProperties, - checkForUnsafeAddedUnionItems, - checkForUnsafeAddedEnumItems, - checkForUnsafeRemovedIntersectionItems, - checkForUnsafeNullableToNativeChange, -]); -const checksForTypesFlowingFromNative = chainPropertiesChecks([ - checkForUnsafeAddedProperties, - checkForUnSafeMadeStrictProperties, - checkForUnsafeRemovedUnionItems, - checkForUnsafeRemovedEnumItems, - checkForUnsafeAddedIntersectionItems, - checkForUnsafeNullableFromNativeChange, -]); -function assessComparisonResult( - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges -) { - return (typeName, newType, oldType, difference, oldDirection) => { - switch (difference.status) { - case "matching": - break; - case "skipped": - newTypes.add({ - typeName, - typeInformation: newType, - }); - break; - case "members": - { - const memberChange = difference.memberLog; - const toNativeErrorResult = checksForTypesFlowingToNative( - null, - null, - null, - memberChange, - typeName - ); - const fromNativeErrorResult = checksForTypesFlowingFromNative( - null, - null, - null, - memberChange, - typeName - ); - switch (oldDirection) { - case "toNative": - toNativeErrorResult.forEach((error) => - incompatibleChanges.add(error) - ); - break; - case "fromNative": - fromNativeErrorResult.forEach((error) => - incompatibleChanges.add(error) - ); - break; - case "both": - toNativeErrorResult.forEach((error) => - incompatibleChanges.add(error) - ); - fromNativeErrorResult.forEach((error) => - incompatibleChanges.add(error) - ); - break; - } - } - break; - case "properties": - const propertyChange = difference.propertyLog; - const unsafeForToNative = nestedPropertiesCheck( - typeName, - difference, - checksForTypesFlowingToNative, - checksForTypesFlowingFromNative - ); - const unsafeForFromNative = nestedPropertiesCheck( - typeName, - difference, - checksForTypesFlowingFromNative, - checksForTypesFlowingToNative - ); - switch (oldDirection) { - case "toNative": - unsafeForToNative.forEach((error) => - incompatibleChanges.add(error) - ); - break; - case "fromNative": - unsafeForFromNative.forEach((error) => - incompatibleChanges.add(error) - ); - break; - case "both": - unsafeForToNative.forEach((error) => - incompatibleChanges.add(error) - ); - unsafeForFromNative.forEach((error) => - incompatibleChanges.add(error) - ); - break; - } - if (!oldType) { - throw new Error("Internal error: properties change with no old type"); - } - objectTypeChanges.add({ - typeName, - newType, - oldType, - propertyChange, - }); - break; - case "error": - incompatibleChanges.add({ - typeName, - errorCode: "incompatibleTypes", - errorInformation: difference.errorLog, - }); - break; - case "functionChange": - const functionLog = difference.functionChangeLog; - let propertyErrors = []; - switch (oldDirection) { - case "toNative": - propertyErrors = compareFunctionTypesInContext( - typeName, - functionLog, - checksForTypesFlowingToNative, - checksForTypesFlowingFromNative, - propertyErrors - ); - break; - case "fromNative": - propertyErrors = compareFunctionTypesInContext( - typeName, - functionLog, - checksForTypesFlowingFromNative, - checksForTypesFlowingToNative, - propertyErrors - ); - break; - case "both": - propertyErrors = compareFunctionTypesInContext( - typeName, - functionLog, - checksForTypesFlowingToNative, - checksForTypesFlowingFromNative, - propertyErrors - ); - propertyErrors = compareFunctionTypesInContext( - typeName, - functionLog, - checksForTypesFlowingFromNative, - checksForTypesFlowingToNative, - propertyErrors - ); - break; - default: - throw new Error( - "Unsupported native boundary direction " + oldDirection - ); - } - propertyErrors.forEach((error) => incompatibleChanges.add(error)); - break; - case "positionalTypeChange": - const changeLog = difference.changeLog; - if ( - changeLog.nestedChanges.length > 0 || - changeLog.addedElements || - changeLog.removedElements - ) { - const changes = changeLog.nestedChanges; - const toNativeBase = checksForTypesFlowingToNative( - null, - changeLog, - null, - null, - typeName - ); - const toNativeResult = combine( - toNativeBase, - changes.map(([_oldIndex, newIndex, comparisonResult]) => - nestedPropertiesCheck( - `${typeName} element ${newIndex} of ${changeLog.typeKind}`, - comparisonResult, - checksForTypesFlowingToNative, - checksForTypesFlowingFromNative - ) - ) - ); - const fromNativeBase = checksForTypesFlowingFromNative( - null, - changeLog, - null, - null, - typeName - ); - const fromNativeResult = combine( - fromNativeBase, - changes.map(([_oldIndex, newIndex, comparisonResult]) => - nestedPropertiesCheck( - `${typeName} element ${newIndex} of ${changeLog.typeKind}`, - comparisonResult, - checksForTypesFlowingFromNative, - checksForTypesFlowingToNative - ) - ) - ); - switch (oldDirection) { - case "toNative": - toNativeResult.forEach((error) => incompatibleChanges.add(error)); - break; - case "fromNative": - fromNativeResult.forEach((error) => - incompatibleChanges.add(error) - ); - break; - case "both": - toNativeResult.forEach((error) => incompatibleChanges.add(error)); - fromNativeResult.forEach((error) => - incompatibleChanges.add(error) - ); - break; - } - } - break; - case "nullableChange": - if (!oldType) { - throw new Error( - "Internal error: old type null or undefined, after nullableChange" - ); - } - switch (oldDirection) { - case "toNative": - checkForUnsafeNullableToNativeChange( - null, - null, - difference.nullableLog, - null, - typeName - ).forEach((error) => incompatibleChanges.add(error)); - break; - case "fromNative": - checkForUnsafeNullableFromNativeChange( - null, - null, - difference.nullableLog, - null, - typeName - ).forEach((error) => incompatibleChanges.add(error)); - break; - case "both": - const err = (0, _ComparisonResult.typeInformationComparisonError)( - "Type may not change nullability, due to flowing to and from native", - newType, - oldType - ); - incompatibleChanges.add({ - typeName, - errorCode: "incompatibleTypes", - errorInformation: err, - }); - break; - default: - throw new Error("Unknown direction : " + oldDirection); - } - if (difference.interiorLog) { - const log = difference.interiorLog; - assessComparisonResult( - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges - )(typeName, newType, oldType, log, oldDirection); - } - break; - default: - difference.status; - throw new Error("Unsupported status: " + difference.status); - } - }; -} -function buildNativeModulesDiff(newerNativeModule, olderNativeModule) { - const moduleErrors = new Set(); - const nativeModuleName = newerNativeModule.moduleName; - if (olderNativeModule.moduleName !== newerNativeModule.moduleName) { - moduleErrors.add({ - nativeSpecName: olderNativeModule.moduleName, - omitted: true, - errorCode: "removedModule", - }); - } - const newTypes = new Set(); - const deprecatedTypes = new Set(); - const incompatibleChanges = new Set(); - const objectTypeChanges = new Set(); - const localAssessComparison = assessComparisonResult( - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges - ); - const newType = { - type: "ObjectTypeAnnotation", - properties: [ - ...newerNativeModule.spec.methods, - ...newerNativeModule.spec.eventEmitters, - ], - }; - const oldType = { - type: "ObjectTypeAnnotation", - properties: [ - ...olderNativeModule.spec.methods, - ...olderNativeModule.spec.eventEmitters, - ], - }; - const difference = codegenTypeDiffing.compareTypes( - newType, - olderNativeModule.moduleName === newerNativeModule.moduleName - ? oldType - : null, - newerNativeModule.aliasMap, - olderNativeModule.aliasMap, - newerNativeModule.enumMap, - olderNativeModule.enumMap - ); - localAssessComparison( - nativeModuleName, - newType, - oldType, - difference, - "fromNative" - ); - const typeUpdate = { - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges, - }; - if (hasCodegenUpdatesTypes(typeUpdate)) { - moduleErrors.add({ - nativeSpecName: nativeModuleName, - omitted: false, - errorCode: "incompatibleTypes", - changeInformation: typeUpdate, - }); - } - return moduleErrors; -} -function buildNativeComponentsDiff(newerNativeSchema, olderNativeSchema) { - const componentErrors = new Set(); - Object.entries(newerNativeSchema.components).forEach( - ([newerComponentName, newerComponent]) => { - const olderComponent = olderNativeSchema.components[newerComponentName]; - const newTypes = new Set(); - const deprecatedTypes = new Set(); - const incompatibleChanges = new Set(); - const objectTypeChanges = new Set(); - const localAssessComparison = assessComparisonResult( - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges - ); - newerComponent.commands.forEach((command) => { - const oldCommand = olderComponent.commands?.find( - (olderCommand) => olderCommand.name === command.name - ); - const newCommands = { - type: "ObjectTypeAnnotation", - properties: [command], - }; - const oldCommands = - oldCommand != null - ? { - type: "ObjectTypeAnnotation", - properties: [oldCommand], - } - : null; - const difference = codegenTypeDiffing.compareTypes( - newCommands, - oldCommands, - {}, - {}, - {}, - {} - ); - localAssessComparison( - newerComponentName, - newCommands, - oldCommands, - difference, - "fromNative" - ); - }); - olderComponent.commands?.forEach((command) => { - const newCommand = newerComponent.commands.find( - (newerCommand) => newerCommand.name === command.name - ); - if (newCommand == null) { - deprecatedTypes.add({ - typeName: command.name, - typeInformation: { - type: "ObjectTypeAnnotation", - properties: [command], - }, - }); - } - }); - const newConvertedProps = { - type: "ObjectTypeAnnotation", - properties: newerComponent.props.map((prop) => ({ - name: prop.name, - optional: prop.optional, - typeAnnotation: (0, _convertPropToBasicTypes.default)( - prop.typeAnnotation - ), - })), - }; - const oldConvertedProps = { - type: "ObjectTypeAnnotation", - properties: olderComponent.props.map((prop) => ({ - name: prop.name, - optional: prop.optional, - typeAnnotation: (0, _convertPropToBasicTypes.default)( - prop.typeAnnotation - ), - })), - }; - const propDifference = codegenTypeDiffing.compareTypes( - newConvertedProps, - oldConvertedProps, - {}, - {}, - {}, - {} - ); - localAssessComparison( - newerComponentName, - newConvertedProps, - oldConvertedProps, - propDifference, - "toNative" - ); - const typeUpdate = { - newTypes, - deprecatedTypes, - incompatibleChanges, - objectTypeChanges, - }; - if (hasCodegenUpdatesTypes(typeUpdate)) { - componentErrors.add({ - nativeSpecName: newerComponentName, - omitted: false, - errorCode: "incompatibleTypes", - changeInformation: typeUpdate, - }); - } - } - ); - Object.keys(olderNativeSchema.components).forEach((olderComponentName) => { - const newerComponent = newerNativeSchema.components[olderComponentName]; - if (newerComponent == null) { - componentErrors.add({ - nativeSpecName: olderComponentName, - omitted: true, - errorCode: "removedComponent", - }); - } - }); - return componentErrors; -} -function hasUpdatesTypes(diff) { - return ( - diff.newTypes.size > 0 || - diff.deprecatedTypes.size > 0 || - diff.objectTypeChanges.size > 0 || - diff.incompatibleChanges.size > 0 - ); -} -function hasCodegenUpdatesTypes(diff) { - return ( - diff.newTypes.size > 0 || - diff.deprecatedTypes.size > 0 || - diff.objectTypeChanges.size > 0 || - diff.incompatibleChanges.size > 0 - ); -} -function buildSchemaDiff(newerSchemaSet, olderSchemaSet) { - const diff = new Set(); - const newerSchema = newerSchemaSet.modules; - const olderSchema = olderSchemaSet.modules; - Object.keys(newerSchema).forEach((hasteModuleName) => { - const schemaEntry = newerSchema[hasteModuleName]; - const olderSchemaEntry = olderSchema[hasteModuleName]; - const framework = "ReactNative"; - if (schemaEntry.type === "Component") { - if (olderSchemaEntry?.type === "Component") { - const incompatibleComponents = buildNativeComponentsDiff( - schemaEntry, - olderSchemaEntry - ); - const hasIncompatibleComponents = incompatibleComponents?.size > 0; - if (hasIncompatibleComponents) { - diff.add({ - name: hasteModuleName, - framework: framework, - status: { - incompatibleSpecs: incompatibleComponents, - }, - }); - } - } - } - if (schemaEntry.type === "NativeModule") { - if (olderSchemaEntry?.type === "NativeModule") { - const incompatibleModules = buildNativeModulesDiff( - schemaEntry, - olderSchemaEntry - ); - const hasIncompatibleModules = - incompatibleModules != null && incompatibleModules.size; - if (hasIncompatibleModules) { - diff.add({ - name: hasteModuleName, - framework: framework, - status: { - incompatibleSpecs: incompatibleModules, - }, - }); - } - } - } - if (olderSchemaEntry == null) { - diff.add({ - name: hasteModuleName, - framework: framework, - status: "new", - }); - } - }); - Object.keys(olderSchema).forEach((hasteModuleName) => { - const newSchemaEntry = newerSchema[hasteModuleName]; - const oldSchemaEntry = olderSchema[hasteModuleName]; - if (oldSchemaEntry != null && newSchemaEntry == null) { - diff.add({ - name: hasteModuleName, - framework: "ReactNative", - status: "deprecated", - }); - } - }); - return diff; -} -function summarizeSchemaDiff(diff) { - switch (diff.status) { - case "new": - return { - status: "patchable", - incompatibilityReport: {}, - }; - case "deprecated": - return { - status: "ok", - incompatibilityReport: {}, - }; - default: - const differs = diff.status; - if (!differs.incompatibleSpecs) { - return { - status: "patchable", - incompatibilityReport: {}, - }; - } else { - const incompatibleObject = {}; - if (differs.incompatibleSpecs) { - const withErrors = Array.from(differs.incompatibleSpecs).filter( - (specError) => - specError.errorInformation || - (specError.changeInformation && - specError.changeInformation.incompatibleChanges.size > 0) - ); - if (withErrors.length > 0) { - if (incompatibleObject[diff.name]) { - incompatibleObject[diff.name].incompatibleSpecs = withErrors; - } else { - incompatibleObject[diff.name] = { - framework: diff.framework, - incompatibleSpecs: withErrors, - }; - } - } - } - const incompatibleUnchanged = - Object.keys(incompatibleObject).length === 0; - return { - status: incompatibleUnchanged ? "ok" : "incompatible", - incompatibilityReport: incompatibleObject, - }; - } - } -} -function combineSummaries(finalSummary, setSummary) { - switch (setSummary.status) { - case "ok": - return finalSummary; - case "patchable": - if (finalSummary.status === "ok") { - return setSummary; - } else { - return finalSummary; - } - default: - switch (finalSummary.status) { - case "ok": - case "patchable": - return setSummary; - default: - Object.keys(setSummary.incompatibilityReport).forEach( - (differingSchemaName) => - (finalSummary.incompatibilityReport[differingSchemaName] = - setSummary.incompatibilityReport[differingSchemaName]) - ); - return finalSummary; - } - } -} -function summarizeDiffSet(diffs) { - if (diffs.size === 0) { - return { - status: "ok", - incompatibilityReport: {}, - }; - } - const summary = []; - diffs.forEach((schemaDiff) => summary.push(summarizeSchemaDiff(schemaDiff))); - return summary.reduce(combineSummaries, summary[0]); -} diff --git a/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow b/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow deleted file mode 100644 index 81d071972577a5..00000000000000 --- a/packages/react-native-compatibility-check/dist/VersionDiffing.js.flow +++ /dev/null @@ -1,71 +0,0 @@ -/** - * 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 { ComparisonResult } from "./ComparisonResult"; -import type { - DiffSet, - DiffSummary, - ErrorStore, - ObjectTypeChangeStore, - SchemaDiff, -} from "./DiffResults"; -import type { - CompleteTypeAnnotation, - SchemaType, -} from "@react-native/codegen/src/CodegenSchema"; - -type BoundaryDirection = "toNative" | "fromNative" | "both"; - -// Exported for testing -declare export const removedPropertiesMessage: "Object removed required properties expected by native"; -declare export const addedPropertiesMessage: "Object added required properties, which native will not provide"; -declare export const stricterPropertiesMessage: "Property made strict, but native may not provide it"; -declare export const tooOptionalPropertiesMessage: "Property made optional, but native requires it"; -declare export const removedUnionMessage: "Union removed items, but native may still provide them"; -declare export const addedUnionMessage: "Union added items, but native will not expect/support them"; -declare export const removedEnumMessage: "Enum removed items, but native may still provide them"; -declare export const addedEnumMessage: "Enum added items, but native will not expect/support them"; -declare export const removedIntersectionMessage: "Intersection removed items, but native may still require properties contained in them"; -declare export const addedIntersectionMessage: "Intersection added items, but native may not provide all required attributes"; -declare export const toNativeVoidChangeMessage: "Native may not be able to safely handle presence of type"; -declare export const typeNullableChangeMessage: "Type made nullable, but native requires it"; -declare export const fromNativeVoidChangeMessage: "Type set to void but native may still provide a value"; -declare export const typeNonNullableChangeMessage: "Type made non-nullable, but native might provide null still"; -declare export function assessComparisonResult( - newTypes: Set<{ - typeName: string, - typeInformation: CompleteTypeAnnotation, - ... - }>, - deprecatedTypes: Set<{ - typeName: string, - typeInformation: CompleteTypeAnnotation, - ... - }>, - incompatibleChanges: Set, - objectTypeChanges: Set -): ( - typeName: string, - newType: CompleteTypeAnnotation, - oldType: ?CompleteTypeAnnotation, - difference: ComparisonResult, - oldDirection: BoundaryDirection -) => void; - -declare export function hasUpdatesTypes(diff: DiffSet): boolean; - -declare export function hasCodegenUpdatesTypes(diff: DiffSet): boolean; - -declare export function buildSchemaDiff( - newerSchemaSet: SchemaType, - olderSchemaSet: SchemaType -): Set; - -declare export function summarizeDiffSet(diffs: Set): DiffSummary; diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts deleted file mode 100644 index dae27d33f8ee4c..00000000000000 --- a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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 - * @oncall react_native - */ - -import type { - CompleteTypeAnnotation, - ComponentArrayTypeAnnotation, - PropTypeAnnotation, -} from "@react-native/codegen/src/CodegenSchema"; -declare function convertPropToBasicTypes( - inputType: PropTypeAnnotation | ComponentArrayTypeAnnotation["elementType"] -): CompleteTypeAnnotation; -export default convertPropToBasicTypes; diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js deleted file mode 100644 index 472aa9c699a5b2..00000000000000 --- a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -exports.default = convertPropToBasicTypes; -function convertPropToBasicTypes(inputType) { - let resultingType; - 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": - 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), - })), - }; - break; - case "ArrayTypeAnnotation": - resultingType = { - type: "ArrayTypeAnnotation", - elementType: convertPropToBasicTypes(inputType.elementType), - }; - break; - default: - inputType.type; - throw new Error("Unexpected type " + inputType.type); - } - return resultingType; -} diff --git a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow b/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow deleted file mode 100644 index 1b5fdf9bf9eeb1..00000000000000 --- a/packages/react-native-compatibility-check/dist/convertPropToBasicTypes.js.flow +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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 { - CompleteTypeAnnotation, - ComponentArrayTypeAnnotation, - PropTypeAnnotation, -} from "@react-native/codegen/src/CodegenSchema"; - -declare export default function convertPropToBasicTypes( - inputType: PropTypeAnnotation | ComponentArrayTypeAnnotation["elementType"] -): CompleteTypeAnnotation; diff --git a/packages/react-native-compatibility-check/dist/index.d.ts b/packages/react-native-compatibility-check/dist/index.d.ts deleted file mode 100644 index a77d5288201764..00000000000000 --- a/packages/react-native-compatibility-check/dist/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 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 - * @oncall react_native - */ - -export { compareSchemas } from "./index.js"; diff --git a/packages/react-native-compatibility-check/dist/index.js b/packages/react-native-compatibility-check/dist/index.js deleted file mode 100644 index d655cc572a9dc1..00000000000000 --- a/packages/react-native-compatibility-check/dist/index.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true, -}); -Object.defineProperty(exports, "compareSchemas", { - enumerable: true, - get: function () { - return _index.compareSchemas; - }, -}); -var _index = require("./index.js"); diff --git a/packages/react-native-compatibility-check/dist/index.js.flow b/packages/react-native-compatibility-check/dist/index.js.flow deleted file mode 100644 index 74591a1c31f19c..00000000000000 --- a/packages/react-native-compatibility-check/dist/index.js.flow +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 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"; diff --git a/packages/react-native-compatibility-check/package.json b/packages/react-native-compatibility-check/package.json index a2da75ee42676d..69ccc77b6e42f8 100644 --- a/packages/react-native-compatibility-check/package.json +++ b/packages/react-native-compatibility-check/package.json @@ -23,7 +23,7 @@ "node": ">=18" }, "exports": { - ".": "./dist/index.js", + ".": "./src/index.js", "./package.json": "./package.json" }, "files": [ From c8712e81feff3049e8ca6ddf2f54f019b5f8f0a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 23:46:22 +0000 Subject: [PATCH 6/8] Remove formatting-only changes, keep only functional border rendering fix Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .../TextInput/RCTTextInputComponentView.mm | 151 ++++++++---------- 1 file changed, 71 insertions(+), 80 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 0c0f473c4703f6..21e0e63c93cc9a 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -17,15 +17,15 @@ #if !TARGET_OS_OSX // [macOS] #import #else // [macOS -#include #include +#include #endif // macOS] #import #import #if TARGET_OS_OSX // [macOS -#import #import +#import #endif // macOS] #import "RCTConversions.h" @@ -43,6 +43,7 @@ static NSString *kEscapeKeyCode = @"\x1B"; #endif // macOS] + using namespace facebook::react; @interface RCTTextInputComponentView () @@ -104,8 +105,7 @@ - (instancetype)initWithFrame:(CGRect)frame #if !TARGET_OS_OSX // [macOS] _backedTextInputView = defaultProps->multiline ? [RCTUITextView new] : [RCTUITextField new]; #else // [macOS - _backedTextInputView = - defaultProps->multiline ? [[RCTWrappedTextView alloc] initWithFrame:self.bounds] : [RCTUITextField new]; + _backedTextInputView = defaultProps->multiline ? [[RCTWrappedTextView alloc] initWithFrame:self.bounds] : [RCTUITextField new]; #endif // macOS] _backedTextInputView.textInputDelegate = self; _ignoreNextTextInputCall = NO; @@ -221,6 +221,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & [self _setMultiline:newTextInputProps.multiline]; } + #if !TARGET_OS_OSX // [macOS] if (newTextInputProps.traits.autocapitalizationType != oldTextInputProps.traits.autocapitalizationType) { _backedTextInputView.autocapitalizationType = @@ -234,9 +235,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & RCTUITextAutocorrectionTypeFromOptionalBool(newTextInputProps.traits.autoCorrect); } #else // [macOS - if (newTextInputProps.traits.autoCorrect != oldTextInputProps.traits.autoCorrect && - newTextInputProps.traits.autoCorrect.has_value()) { - _backedTextInputView.automaticSpellingCorrectionEnabled = newTextInputProps.traits.autoCorrect.value(); + if (newTextInputProps.traits.autoCorrect != oldTextInputProps.traits.autoCorrect && newTextInputProps.traits.autoCorrect.has_value()) { + _backedTextInputView.automaticSpellingCorrectionEnabled = + newTextInputProps.traits.autoCorrect.value(); } #endif // macOS] @@ -274,16 +275,16 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & RCTUITextSpellCheckingTypeFromOptionalBool(newTextInputProps.traits.spellCheck); } #else // [macOS - if (newTextInputProps.traits.spellCheck != oldTextInputProps.traits.spellCheck && - newTextInputProps.traits.spellCheck.has_value()) { - _backedTextInputView.continuousSpellCheckingEnabled = newTextInputProps.traits.spellCheck.value(); + if (newTextInputProps.traits.spellCheck != oldTextInputProps.traits.spellCheck && newTextInputProps.traits.spellCheck.has_value()) { + _backedTextInputView.continuousSpellCheckingEnabled = + newTextInputProps.traits.spellCheck.value(); } #endif // macOS] #if TARGET_OS_OSX // [macOS - if (newTextInputProps.traits.grammarCheck != oldTextInputProps.traits.grammarCheck && - newTextInputProps.traits.grammarCheck.has_value()) { - _backedTextInputView.grammarCheckingEnabled = newTextInputProps.traits.grammarCheck.value(); + if (newTextInputProps.traits.grammarCheck != oldTextInputProps.traits.grammarCheck && newTextInputProps.traits.grammarCheck.has_value()) { + _backedTextInputView.grammarCheckingEnabled = + newTextInputProps.traits.grammarCheck.value(); } #endif // macOS] @@ -379,7 +380,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & } #if TARGET_OS_OSX // [macOS - if (newTextInputProps.traits.pastedTypes != oldTextInputProps.traits.pastedTypes) { + if (newTextInputProps.traits.pastedTypes!= oldTextInputProps.traits.pastedTypes) { NSArray *types = RCTPasteboardTypeArrayFromProps(newTextInputProps.traits.pastedTypes); [_backedTextInputView setReadablePasteBoardTypes:types]; } @@ -606,35 +607,30 @@ - (void)textInputDidChangeSelection } #if TARGET_OS_OSX // [macOS -- (void)setEnableFocusRing:(BOOL)enableFocusRing -{ +- (void)setEnableFocusRing:(BOOL)enableFocusRing { [super setEnableFocusRing:enableFocusRing]; if ([_backedTextInputView respondsToSelector:@selector(setEnableFocusRing:)]) { [_backedTextInputView setEnableFocusRing:enableFocusRing]; } } -- (void)automaticSpellingCorrectionDidChange:(BOOL)enabled -{ +- (void)automaticSpellingCorrectionDidChange:(BOOL)enabled { if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter) - ->onAutoCorrectChange({.autoCorrectEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter)->onAutoCorrectChange({.autoCorrectEnabled = static_cast(enabled)}); } } - (void)continuousSpellCheckingDidChange:(BOOL)enabled { if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter) - ->onSpellCheckChange({.spellCheckEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter)->onSpellCheckChange({.spellCheckEnabled = static_cast(enabled)}); } } - (void)grammarCheckingDidChange:(BOOL)enabled { if (_eventEmitter) { - std::static_pointer_cast(_eventEmitter) - ->onGrammarCheckChange({.grammarCheckEnabled = static_cast(enabled)}); + std::static_pointer_cast(_eventEmitter)->onGrammarCheckChange({.grammarCheckEnabled = static_cast(enabled)}); } } @@ -642,11 +638,14 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event { BOOL shouldSubmit = NO; NSDictionary *keyEvent = [RCTViewKeyboardEvent bodyFromEvent:event]; - const auto &props = *std::static_pointer_cast(_props); + auto const &props = *std::static_pointer_cast(_props); if (props.traits.submitKeyEvents.empty()) { - shouldSubmit = [keyEvent[@"key"] isEqualToString:@"Enter"] && ![keyEvent[@"altKey"] boolValue] && - ![keyEvent[@"shiftKey"] boolValue] && ![keyEvent[@"ctrlKey"] boolValue] && ![keyEvent[@"metaKey"] boolValue] && - ![keyEvent[@"functionKey"] boolValue]; // Default clearTextOnSubmit key + shouldSubmit = [keyEvent[@"key"] isEqualToString:@"Enter"] + && ![keyEvent[@"altKey"] boolValue] + && ![keyEvent[@"shiftKey"] boolValue] + && ![keyEvent[@"ctrlKey"] boolValue] + && ![keyEvent[@"metaKey"] boolValue] + && ![keyEvent[@"functionKey"] boolValue]; // Default clearTextOnSubmit key } else { NSString *keyValue = keyEvent[@"key"]; const char *keyCString = [keyValue UTF8String]; @@ -659,17 +658,19 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event const bool functionKey = [keyEvent[@"functionKey"] boolValue]; shouldSubmit = std::any_of( - props.traits.submitKeyEvents.begin(), props.traits.submitKeyEvents.end(), [&](const auto &submitKeyEvent) { - return submitKeyEvent.key == key && submitKeyEvent.altKey == altKey && - submitKeyEvent.shiftKey == shiftKey && submitKeyEvent.ctrlKey == ctrlKey && - submitKeyEvent.metaKey == metaKey && submitKeyEvent.functionKey == functionKey; - }); + props.traits.submitKeyEvents.begin(), + props.traits.submitKeyEvents.end(), + [&](auto const &submitKeyEvent) { + return submitKeyEvent.key == key && submitKeyEvent.altKey == altKey && + submitKeyEvent.shiftKey == shiftKey && submitKeyEvent.ctrlKey == ctrlKey && + submitKeyEvent.metaKey == metaKey && submitKeyEvent.functionKey == functionKey; + }); } } - + if (shouldSubmit) { if (_eventEmitter) { - const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); textInputEventEmitter.onSubmitEditing([self _textInputMetrics]); } @@ -683,33 +684,30 @@ - (void)submitOnKeyDownIfNeeded:(nonnull NSEvent *)event - (void)textInputDidCancel { if (_eventEmitter) { - const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); textInputEventEmitter.onKeyPress({ - .text = RCTStringFromNSString(kEscapeKeyCode), - .eventCount = static_cast(_mostRecentEventCount), + .text = RCTStringFromNSString(kEscapeKeyCode), + .eventCount = static_cast(_mostRecentEventCount), }); } - + [self textInputDidEndEditing]; } -- (NSDragOperation)textInputDraggingEntered:(nonnull id)draggingInfo -{ +- (NSDragOperation)textInputDraggingEntered:(nonnull id)draggingInfo { if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { return [self draggingEntered:draggingInfo]; } return NSDragOperationNone; } -- (void)textInputDraggingExited:(nonnull id)draggingInfo -{ +- (void)textInputDraggingExited:(nonnull id)draggingInfo { if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { [self draggingExited:draggingInfo]; } } -- (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingInfo -{ +- (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingInfo { if ([draggingInfo.draggingPasteboard availableTypeFromArray:self.registeredDraggedTypes]) { [self performDragOperation:draggingInfo]; return NO; @@ -718,33 +716,28 @@ - (BOOL)textInputShouldHandleDragOperation:(nonnull id)draggingI return YES; } -- (BOOL)textInputShouldHandleDeleteBackward:(nonnull id)sender -{ +- (BOOL)textInputShouldHandleDeleteBackward:(nonnull id)sender { return YES; } -- (BOOL)textInputShouldHandleDeleteForward:(nonnull id)sender -{ +- (BOOL)textInputShouldHandleDeleteForward:(nonnull id)sender { return YES; } -- (BOOL)textInputShouldHandleKeyEvent:(nonnull NSEvent *)event -{ +- (BOOL)textInputShouldHandleKeyEvent:(nonnull NSEvent *)event { return ![self handleKeyboardEvent:event]; } -- (BOOL)textInputShouldHandlePaste:(nonnull id)sender -{ +- (BOOL)textInputShouldHandlePaste:(nonnull id)sender { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - NSPasteboardType fileType = - [pasteboard availableTypeFromArray:@[ NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF ]]; - NSArray *pastedTypes = ((RCTUITextView *)_backedTextInputView).readablePasteboardTypes; - + NSPasteboardType fileType = [pasteboard availableTypeFromArray:@[NSFilenamesPboardType, NSPasteboardTypePNG, NSPasteboardTypeTIFF]]; + NSArray* pastedTypes = ((RCTUITextView*) _backedTextInputView).readablePasteboardTypes; + // If there's a fileType that is of interest, notify JS. Also blocks notifying JS if it's a text paste if (_eventEmitter && fileType != nil && [pastedTypes containsObject:fileType]) { - const auto &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); - DataTransfer dataTransfer = [self dataTransferForPasteboard:pasteboard]; - textInputEventEmitter.onPaste({.dataTransfer = std::move(dataTransfer)}); + auto const &textInputEventEmitter = *std::static_pointer_cast(_eventEmitter); + DataTransfer dataTransfer = [self dataTransferForPasteboard:pasteboard]; + textInputEventEmitter.onPaste({.dataTransfer = std::move(dataTransfer)}); } // Only allow pasting text. @@ -761,8 +754,7 @@ - (void)scrollViewDidScroll:(RCTUIScrollView *)scrollView // [macOS] #if !TARGET_OS_OSX // [macOS] static_cast(*_eventEmitter).onScroll([self _textInputMetrics]); #else // [macOS - static_cast(*_eventEmitter) - .onScroll([self _textInputMetricsWithScrollView:scrollView]); + static_cast(*_eventEmitter).onScroll([self _textInputMetricsWithScrollView:scrollView]); #endif // macOS] } } @@ -839,8 +831,7 @@ - (void)setTextAndSelection:(NSInteger)eventCount #else // [macOS NSInteger startPosition = MIN(start, end); NSInteger endPosition = MAX(start, end); - [_backedTextInputView setSelectedTextRange:NSMakeRange(startPosition, endPosition - startPosition) - notifyDelegate:YES]; + [_backedTextInputView setSelectedTextRange:NSMakeRange(startPosition, endPosition - startPosition) notifyDelegate:YES]; #endif // macOS] _comingFromJS = NO; } @@ -991,6 +982,7 @@ - (void)handleInputAccessoryDoneButton } #endif // macOS] + - (void)_updateState { if (!_state) { @@ -1079,7 +1071,8 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString NSInteger start = selectedRange.location; NSInteger offsetFromEnd = oldTextLength - start; NSInteger newOffset = _backedTextInputView.attributedText.length - offsetFromEnd; - [_backedTextInputView setSelectedTextRange:NSMakeRange(newOffset, 0) notifyDelegate:YES]; + [_backedTextInputView setSelectedTextRange:NSMakeRange(newOffset, 0) + notifyDelegate:YES]; } #endif // macOS] } @@ -1122,11 +1115,9 @@ - (void)_setMultiline:(BOOL)multiline { [_backedTextInputView removeFromSuperview]; #if !TARGET_OS_OSX // [macOS] - RCTUIView *backedTextInputView = - multiline ? [RCTUITextView new] : [RCTUITextField new]; + RCTUIView *backedTextInputView = multiline ? [RCTUITextView new] : [RCTUITextField new]; #else // [macOS - RCTPlatformView *backedTextInputView = - multiline ? [RCTWrappedTextView new] : [RCTUITextField new]; + RCTPlatformView *backedTextInputView = multiline ? [RCTWrappedTextView new] : [RCTUITextField new]; #endif // macOS] backedTextInputView.frame = _backedTextInputView.frame; RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView); @@ -1157,11 +1148,10 @@ - (void)_setShowSoftInputOnFocus:(BOOL)showSoftInputOnFocus - (void)_setSecureTextEntry:(BOOL)secureTextEntry { [_backedTextInputView removeFromSuperview]; - RCTPlatformView *backedTextInputView = - secureTextEntry ? [RCTUISecureTextField new] : [RCTUITextField new]; + RCTPlatformView *backedTextInputView = secureTextEntry ? [RCTUISecureTextField new] : [RCTUITextField new]; backedTextInputView.frame = _backedTextInputView.frame; RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView); - + // Copy the text field specific properties if we came from a single line input before the switch if ([_backedTextInputView isKindOfClass:[RCTUITextField class]]) { RCTUITextField *previousTextField = (RCTUITextField *)_backedTextInputView; @@ -1199,16 +1189,17 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe BOOL shouldFallbackToBareTextComparison = #if !TARGET_OS_OSX // [macOS] - [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || - [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || - _backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || + [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || + [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || + _backedTextInputView.markedTextRange || + _backedTextInputView.isSecureTextEntry || #else // [macOS - // There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead - [[[_backedTextInputView inputContext] selectedKeyboardInputSource] - containsString:@"com.apple.inputmethod.Korean"] || - [_backedTextInputView hasMarkedText] || [_backedTextInputView isKindOfClass:[NSSecureTextField class]] || + // There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead + [[[_backedTextInputView inputContext] selectedKeyboardInputSource] containsString:@"com.apple.inputmethod.Korean"] || + [_backedTextInputView hasMarkedText] || + [_backedTextInputView isKindOfClass:[NSSecureTextField class]] || #endif // macOS] - fontHasBeenUpdatedBySystem; + fontHasBeenUpdatedBySystem; if (shouldFallbackToBareTextComparison) { return [newText.string isEqualToString:oldText.string]; From 3968a5346a6f1fd2e036920b4400922f87352c28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 00:44:12 +0000 Subject: [PATCH 7/8] Simplify fix to just set clipsToBounds in initWithFrame on macOS Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .../TextInput/RCTTextInputComponentView.mm | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 21e0e63c93cc9a..c8b24e7840bd56 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -114,11 +114,7 @@ - (instancetype)initWithFrame:(CGRect)frame _originalTypingAttributes = [_backedTextInputView.typingAttributes copy]; #if TARGET_OS_OSX // [macOS - // Ensure the backing text view doesn't interfere with border rendering - // by making sure it doesn't draw outside its bounds - if (_backedTextInputView.layer) { - _backedTextInputView.layer.masksToBounds = YES; - } + [self setClipsToBounds:YES]; #endif // macOS] [self addSubview:_backedTextInputView]; @@ -421,24 +417,6 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics { CGSize previousContentSize = _backedTextInputView.contentSize; -#if TARGET_OS_OSX // [macOS - // On macOS, ensure proper border rendering by enabling clip to bounds - // when borders are present. This forces Core Animation border rendering - // which displays correctly with the native text field subview. - const auto &props = static_cast(*_props); - const auto borderMetrics = props.resolveBorderMetrics(layoutMetrics); - BOOL hasBorder = borderMetrics.borderWidths.left > 0 || borderMetrics.borderWidths.right > 0 || - borderMetrics.borderWidths.top > 0 || borderMetrics.borderWidths.bottom > 0; - if (hasBorder) { - // Note: Setting clipsToBounds ensures Core Animation border rendering is used, - // which properly displays with the native text field subview on macOS - self.clipsToBounds = YES; - } else { - // Reset clipsToBounds when no borders are present - self.clipsToBounds = NO; - } -#endif // macOS] - [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; #if TARGET_OS_OSX // [macOS @@ -465,10 +443,6 @@ - (void)prepareForRecycle _ignoreNextTextInputCall = NO; _didMoveToWindow = NO; [_backedTextInputView resignFirstResponder]; -#if TARGET_OS_OSX // [macOS - // Reset clipsToBounds to prevent state leakage in recycled components - self.clipsToBounds = NO; -#endif // macOS] } #pragma mark - RCTBackedTextInputDelegate From 40cc07d4500265a14601650e9ac4df503b0306a5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 00:47:52 +0000 Subject: [PATCH 8/8] Remove .gitignore change Co-authored-by: Saadnajmi <6722175+Saadnajmi@users.noreply.github.com> --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8bdad4184a66ee..396da3ee520af1 100644 --- a/.gitignore +++ b/.gitignore @@ -190,4 +190,3 @@ fix_*.patch .cursor/rules/nx-rules.mdc .github/instructions/nx.instructions.md # macOS] -packages/react-native-compatibility-check/dist/