From c084066d35492dd39227e03442d6c3a4e0299dd9 Mon Sep 17 00:00:00 2001 From: Gijs Weterings Date: Thu, 12 Oct 2023 10:59:52 -0700 Subject: [PATCH] remove metro-react-native-interop-tools package Summary: This package was an early prototype for some new tooling aimed at js/native incompatibilities. We've learned from this approach and designed a more scalable approach. Given this, I'm going to remove this package as this particular approach won't get to a shippable state. Reviewed By: huntie Differential Revision: D50221033 fbshipit-source-id: 6c3819b9137f3fb9723d162c41c0031dd13699c3 --- .../.npmignore | 6 - .../README.md | 5 - .../package.json | 24 - .../__snapshots__/ast-helpers-test.js.snap | 486 ------------------ .../type-comparison-test.js.snap | 471 ----------------- .../src/__tests__/ast-helpers-test.js | 454 ---------------- .../src/__tests__/index-test.js | 16 - .../src/__tests__/type-comparison-test.js | 99 ---- .../src/ast-helpers.js | 396 -------------- .../src/index.js | 14 - .../src/type-annotation.js | 154 ------ .../src/type-comparison.js | 447 ---------------- 12 files changed, 2572 deletions(-) delete mode 100644 packages/metro-react-native-interop-tools/.npmignore delete mode 100644 packages/metro-react-native-interop-tools/README.md delete mode 100644 packages/metro-react-native-interop-tools/package.json delete mode 100644 packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/ast-helpers-test.js.snap delete mode 100644 packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/type-comparison-test.js.snap delete mode 100644 packages/metro-react-native-interop-tools/src/__tests__/ast-helpers-test.js delete mode 100644 packages/metro-react-native-interop-tools/src/__tests__/index-test.js delete mode 100644 packages/metro-react-native-interop-tools/src/__tests__/type-comparison-test.js delete mode 100644 packages/metro-react-native-interop-tools/src/ast-helpers.js delete mode 100644 packages/metro-react-native-interop-tools/src/index.js delete mode 100644 packages/metro-react-native-interop-tools/src/type-annotation.js delete mode 100644 packages/metro-react-native-interop-tools/src/type-comparison.js diff --git a/packages/metro-react-native-interop-tools/.npmignore b/packages/metro-react-native-interop-tools/.npmignore deleted file mode 100644 index 0ec3b99a14..0000000000 --- a/packages/metro-react-native-interop-tools/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -**/__mocks__/ -**/__tests__/ -/build/ -/src.real/ -/types/ -yarn.lock diff --git a/packages/metro-react-native-interop-tools/README.md b/packages/metro-react-native-interop-tools/README.md deleted file mode 100644 index fed7cadffb..0000000000 --- a/packages/metro-react-native-interop-tools/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# metro-react-native-interop-tools - -This package contains version diffing logic for Metro to determine incompatibilities between native and JavaScript code. - -> Warning: This package is experimental. diff --git a/packages/metro-react-native-interop-tools/package.json b/packages/metro-react-native-interop-tools/package.json deleted file mode 100644 index 255a99018a..0000000000 --- a/packages/metro-react-native-interop-tools/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "metro-react-native-interop-tools", - "version": "0.79.1", - "description": "Interop tools for React Native applications", - "main": "src/index.js", - "repository": { - "type": "git", - "url": "git@github.com:facebook/metro.git" - }, - "scripts": { - "prepare-release": "test -d build && rm -rf src.real && mv src src.real && mv build src", - "cleanup-release": "test ! -e build && mv src build && mv src.real src" - }, - "dependencies": { - "@babel/core": "^7.20.0", - "@babel/types": "^7.20.0", - "hermes-parser": "0.16.0", - "nullthrows": "^1.1.1" - }, - "license": "MIT", - "engines": { - "node": ">=18" - } -} diff --git a/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/ast-helpers-test.js.snap b/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/ast-helpers-test.js.snap deleted file mode 100644 index 9b4de5ef52..0000000000 --- a/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/ast-helpers-test.js.snap +++ /dev/null @@ -1,486 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`getBoundarySchemaFromAST, integration test 1`] = ` -Object { - "source": "test.js", - "typegenSchema": Object { - "Spec": Object { - "typeAnnotation": Object { - "extends": Array [ - Object { - "loc": Object { - "end": Object { - "column": 45, - "line": 2, - }, - "start": Object { - "column": 34, - "line": 2, - }, - }, - "name": "TurboModule", - "typeParameters": Array [], - }, - ], - "innerType": Object { - "loc": Object { - "end": Object { - "column": 5, - "line": 15, - }, - "start": Object { - "column": 46, - "line": 2, - }, - }, - "properties": Array [ - Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 13, - }, - "start": Object { - "column": 6, - "line": 3, - }, - }, - "name": "getConstants", - "optional": false, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 13, - }, - "start": Object { - "column": 21, - "line": 3, - }, - }, - "params": Array [], - "returnTypeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 13, - }, - "start": Object { - "column": 27, - "line": 3, - }, - }, - "properties": Array [ - Object { - "loc": Object { - "end": Object { - "column": 29, - "line": 4, - }, - "start": Object { - "column": 8, - "line": 4, - }, - }, - "name": "testGeneric0", - "optional": false, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 29, - "line": 4, - }, - "start": Object { - "column": 23, - "line": 4, - }, - }, - "name": "Object", - "type": "GenericTypeAnnotation", - "typeParameters": Array [], - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 37, - "line": 5, - }, - "start": Object { - "column": 8, - "line": 5, - }, - }, - "name": "testUnion0", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 37, - "line": 5, - }, - "start": Object { - "column": 22, - "line": 5, - }, - }, - "type": "UnionTypeAnnotation", - "types": Array [ - Object { - "loc": Object { - "end": Object { - "column": 28, - "line": 5, - }, - "start": Object { - "column": 22, - "line": 5, - }, - }, - "type": "StringTypeAnnotation", - }, - Object { - "loc": Object { - "end": Object { - "column": 37, - "line": 5, - }, - "start": Object { - "column": 31, - "line": 5, - }, - }, - "type": "StringTypeAnnotation", - }, - ], - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 44, - "line": 6, - }, - "start": Object { - "column": 8, - "line": 6, - }, - }, - "name": "testIntersection0", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 44, - "line": 6, - }, - "start": Object { - "column": 29, - "line": 6, - }, - }, - "type": "IntersectionTypeAnnotation", - "types": Array [ - Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 6, - }, - "start": Object { - "column": 29, - "line": 6, - }, - }, - "type": "StringTypeAnnotation", - }, - Object { - "loc": Object { - "end": Object { - "column": 44, - "line": 6, - }, - "start": Object { - "column": 38, - "line": 6, - }, - }, - "type": "StringTypeAnnotation", - }, - ], - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 38, - "line": 7, - }, - "start": Object { - "column": 8, - "line": 7, - }, - }, - "name": "testTuple0", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 38, - "line": 7, - }, - "start": Object { - "column": 22, - "line": 7, - }, - }, - "type": "TupleTypeAnnotation", - "types": Array [ - Object { - "loc": Object { - "end": Object { - "column": 29, - "line": 7, - }, - "start": Object { - "column": 23, - "line": 7, - }, - }, - "type": "StringTypeAnnotation", - }, - Object { - "loc": Object { - "end": Object { - "column": 37, - "line": 7, - }, - "start": Object { - "column": 31, - "line": 7, - }, - }, - "type": "NumberTypeAnnotation", - }, - ], - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 23, - "line": 8, - }, - "start": Object { - "column": 8, - "line": 8, - }, - }, - "name": "scale", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 23, - "line": 8, - }, - "start": Object { - "column": 17, - "line": 8, - }, - }, - "type": "NumberTypeAnnotation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 30, - "line": 9, - }, - "start": Object { - "column": 8, - "line": 9, - }, - }, - "name": "isSimulator", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 30, - "line": 9, - }, - "start": Object { - "column": 23, - "line": 9, - }, - }, - "type": "BooleanTypeAnnotation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 32, - "line": 10, - }, - "start": Object { - "column": 8, - "line": 10, - }, - }, - "name": "majorOsVersion", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 32, - "line": 10, - }, - "start": Object { - "column": 26, - "line": 10, - }, - }, - "type": "NumberTypeAnnotation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 27, - "line": 11, - }, - "start": Object { - "column": 8, - "line": 11, - }, - }, - "name": "isTablet", - "optional": true, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 27, - "line": 11, - }, - "start": Object { - "column": 20, - "line": 11, - }, - }, - "type": "BooleanTypeAnnotation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 25, - "line": 12, - }, - "start": Object { - "column": 8, - "line": 12, - }, - }, - "name": "deviceID", - "optional": false, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 25, - "line": 12, - }, - "start": Object { - "column": 19, - "line": 12, - }, - }, - "type": "StringTypeAnnotation", - }, - }, - ], - "type": "ObjectTypeAnnotation", - }, - "type": "FunctionTypeAnnotation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 63, - "line": 14, - }, - "start": Object { - "column": 6, - "line": 14, - }, - }, - "name": "setKeepScreenOn", - "optional": false, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 63, - "line": 14, - }, - "start": Object { - "column": 24, - "line": 14, - }, - }, - "params": Array [ - Object { - "loc": Object { - "end": Object { - "column": 54, - "line": 14, - }, - "start": Object { - "column": 25, - "line": 14, - }, - }, - "name": "screenShouldBeKeptOn", - "optional": false, - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 54, - "line": 14, - }, - "start": Object { - "column": 47, - "line": 14, - }, - }, - "type": "BooleanTypeAnnotation", - }, - }, - ], - "returnTypeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 63, - "line": 14, - }, - "start": Object { - "column": 59, - "line": 14, - }, - }, - "type": "VoidTypeAnnotation", - }, - "type": "FunctionTypeAnnotation", - }, - }, - ], - "type": "ObjectTypeAnnotation", - }, - "type": "InterfaceDeclarationTypeAnnotation", - }, - }, - }, -} -`; diff --git a/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/type-comparison-test.js.snap b/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/type-comparison-test.js.snap deleted file mode 100644 index bfe410dee3..0000000000 --- a/packages/metro-react-native-interop-tools/src/__tests__/__snapshots__/type-comparison-test.js.snap +++ /dev/null @@ -1,471 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`comparing basic types 1`] = ` -" - left-type: - boolean - right-type: - boolean - output: - no errors" -`; - -exports[`comparing basic types 2`] = ` -" - left-type: - string - right-type: - string - output: - no errors" -`; - -exports[`comparing basic types 3`] = ` -" - left-type: - number - right-type: - number - output: - no errors" -`; - -exports[`comparing basic types 4`] = ` -" - left-type: - void - right-type: - void - output: - no errors" -`; - -exports[`comparing basic types 5`] = ` -" - left-type: - boolean - right-type: - number - output: - Error: cannot change boolean to number because native code will break when js calls it. - " -`; - -exports[`comparing basic types 6`] = ` -" - left-type: - 'a' - right-type: - 'a' - output: - no errors" -`; - -exports[`comparing basic types 7`] = ` -" - left-type: - 'a' - right-type: - 'b' - output: - Error: cannot change string literal with value 'a' to string literal with value 'b' because native code will break when js calls it. - " -`; - -exports[`comparing basic types 8`] = ` -" - left-type: - 8 - right-type: - 8 - output: - no errors" -`; - -exports[`comparing basic types 9`] = ` -" - left-type: - 2 - right-type: - 8 - output: - Error: cannot change number literal with value '2' to number literal with value '8' because native code will break when js calls it. - " -`; - -exports[`comparing basic types 10`] = ` -" - left-type: - 2 - right-type: - number - output: - Error: cannot change number literal to number because native code will break when js calls it. - " -`; - -exports[`comparing basic types 11`] = ` -" - left-type: - number - right-type: - 2 - output: - no errors" -`; - -exports[`comparing basic types 12`] = ` -" - left-type: - string - right-type: - 'a' - output: - no errors" -`; - -exports[`comparing basic types 13`] = ` -" - left-type: - 'a' - right-type: - string - output: - Error: cannot change string literal to string because native code will break when js calls it. - " -`; - -exports[`comparing basic types 14`] = ` -" - left-type: - true - right-type: - true - output: - no errors" -`; - -exports[`comparing basic types 15`] = ` -" - left-type: - true - right-type: - false - output: - Error: cannot change boolean literal with value 'true' to boolean literal with value 'false' because native code will break when js calls it. - " -`; - -exports[`comparing basic types 16`] = ` -" - left-type: - string - right-type: - ?string - output: - Error: cannot change string to nullable string because native code will break when js calls it. - " -`; - -exports[`comparing basic types 17`] = ` -" - left-type: - ?number - right-type: - number - output: - no errors" -`; - -exports[`comparing basic types 18`] = ` -" - left-type: - ?boolean - right-type: - true - output: - no errors" -`; - -exports[`comparing basic types 19`] = ` -" - left-type: - ?string - right-type: - ?string - output: - no errors" -`; - -exports[`comparing basic types 20`] = ` -" - left-type: - ?string - right-type: - ?'foo' - output: - no errors" -`; - -exports[`comparing basic types 21`] = ` -" - left-type: - ?string - right-type: - ?number - output: - Error: cannot change string to number because native code will break when js calls it. - " -`; - -exports[`comparing basic types 22`] = ` -" - left-type: - null - right-type: - null - output: - no errors" -`; - -exports[`comparing basic types 23`] = ` -" - left-type: - ?string - right-type: - null - output: - no errors" -`; - -exports[`comparing basic types 24`] = ` -" - left-type: - ?boolean - right-type: - void - output: - no errors" -`; - -exports[`comparing basic types 25`] = ` -" - left-type: - () => boolean - right-type: - () => ?boolean - output: - no errors" -`; - -exports[`comparing basic types 26`] = ` -" - left-type: - () => ?boolean - right-type: - () => boolean - output: - Error: cannot change nullable boolean to boolean because is incompatible with what the native code returns. - " -`; - -exports[`comparing basic types 27`] = ` -" - left-type: - () => true - right-type: - () => boolean - output: - no errors" -`; - -exports[`comparing basic types 28`] = ` -" - left-type: - (test: ?boolean) => true - right-type: - (test: boolean) => true - output: - no errors" -`; - -exports[`comparing basic types 29`] = ` -" - left-type: - (test?: string) => void - right-type: - () => void - output: - no errors" -`; - -exports[`comparing basic types 30`] = ` -" - left-type: - (test: string) => void - right-type: - () => void - output: - Error: cannot remove required parameter string because native code will break when js calls it. - " -`; - -exports[`comparing basic types 31`] = ` -" - left-type: - () => void - right-type: - (test?: string) => void - output: - no errors" -`; - -exports[`comparing basic types 32`] = ` -" - left-type: - () => void - right-type: - (test?: string, test2: number) => void - output: - Error: cannot add new required parameter number because native will not provide it. - " -`; - -exports[`comparing basic types 33`] = ` -" - left-type: - (test?: boolean) => true - right-type: - (test?: string) => true - output: - Error: cannot change boolean to string because native code will break when js calls it. - " -`; - -exports[`comparing basic types 34`] = ` -" - left-type: - (test: string) => ?true - right-type: - () => void - output: - Error: cannot change nullable boolean literal to void because is incompatible with what the native code returns. - Error: cannot remove required parameter string because native code will break when js calls it. - " -`; - -exports[`comparing basic types 35`] = ` -" - left-type: - {name: string, age: ?number } - right-type: - {name: string, age: number } - output: - no errors" -`; - -exports[`comparing basic types 36`] = ` -" - left-type: - {name: string, age: number } - right-type: - {name: string, age?: number } - output: - Error: cannot change required number to optional number because native code will break when js calls it. - " -`; - -exports[`comparing basic types 37`] = ` -" - left-type: - {name: string, age: number } - right-type: - {name: string} - output: - Error: cannot remove number from object properties because native code will break when js calls it. - " -`; - -exports[`comparing basic types 38`] = ` -" - left-type: - {name: string, age?: number } - right-type: - {name: string} - output: - no errors" -`; - -exports[`comparing basic types 39`] = ` -" - left-type: - {name: string} - right-type: - {name: string, ...} - output: - no errors" -`; - -exports[`comparing basic types 40`] = ` -" - left-type: - {name: string} - right-type: - {name: string, age: number} - output: - Error: cannot add number to object properties because native code will break when js calls it. - " -`; - -exports[`comparing basic types 41`] = ` -" - left-type: - {name: string} - right-type: - {name: string, age?: number} - output: - no errors" -`; - -exports[`comparing basic types 42`] = ` -" - left-type: - () => {name: string, age?: number } - right-type: - () => {name: string} - output: - no errors" -`; - -exports[`comparing basic types 43`] = ` -" - left-type: - () => {name: string, age: number } - right-type: - () => {name: string} - output: - Error: cannot remove number from object properties because it is incompatible with what the native code returns. - " -`; - -exports[`comparing basic types 44`] = ` -" - left-type: - () => {name: string} - right-type: - () => {name: string, age: number} - output: - Error: cannot add number to object properties because it is incompatible with what the native code returns. - " -`; - -exports[`comparing basic types 45`] = ` -" - left-type: - () => {name: string} - right-type: - () => {name: string, age: ?number} - output: - Error: cannot add nullable number to object properties because it is incompatible with what the native code returns. - " -`; diff --git a/packages/metro-react-native-interop-tools/src/__tests__/ast-helpers-test.js b/packages/metro-react-native-interop-tools/src/__tests__/ast-helpers-test.js deleted file mode 100644 index ac4ef030fd..0000000000 --- a/packages/metro-react-native-interop-tools/src/__tests__/ast-helpers-test.js +++ /dev/null @@ -1,454 +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 * as t from '@babel/types'; -import { - isTurboModule, - getTypeAnnotation, - getFunctionTypeParameter, - getFunctionTypeAnnotation, - getObjectTypeAnnotation, - getObjectTypeProperty, - getObjectTypeSpreadProperty, - getGenericTypeAnnotation, - getTupleTypeAnnotation, - getUnionTypeAnnotation, - getIntersectionTypeAnnotation, - getArrayTypeAnnotation, - getStringLiteralTypeAnnotation, - getNumberLiteralTypeAnnotation, - getInterfaceExtends, - getTypeParameters, - getNameFromID, - getNodeLoc, - getBoundarySchemaFromAST, -} from '../ast-helpers.js'; -import {parse} from 'hermes-parser'; - -test('isTurboModule returns true, name is "TurboModule" and typeParams is null', () => { - expect( - isTurboModule(t.interfaceExtends(t.identifier('TurboModule'))), - ).toEqual(true); -}); - -test('isTurboModule returns false, name is not "TurboModule"', () => { - expect( - isTurboModule(t.interfaceExtends(t.identifier('OtherModule'))), - ).toEqual(false); -}); - -test('isTurboModule returns false, typeParameters it is not empty', () => { - expect( - isTurboModule( - t.interfaceExtends( - t.identifier('TurboModule'), - t.typeParameterInstantiation([t.anyTypeAnnotation()]), - ), - ), - ).toEqual(false); -}); - -test('getTypeAnnotation, testing BooleanTypeAnnotation', () => { - expect(getTypeAnnotation(t.booleanTypeAnnotation()).type).toBe( - t.booleanTypeAnnotation().type, - ); -}); - -test('getTypeAnnotation, testing NumberTypeAnnotation', () => { - expect(getTypeAnnotation(t.numberTypeAnnotation()).type).toBe( - t.numberTypeAnnotation().type, - ); -}); - -test('getTypeAnnotation, testing StringTypeAnnotation', () => { - expect(getTypeAnnotation(t.stringTypeAnnotation()).type).toBe( - t.stringTypeAnnotation().type, - ); -}); - -test('getTypeAnnotation, testing VoidTypeAnnotation', () => { - expect(getTypeAnnotation(t.voidTypeAnnotation()).type).toBe( - t.voidTypeAnnotation().type, - ); -}); - -test('getTypeAnnotation, testing NullableTypeAnnotation', () => { - expect( - getTypeAnnotation(t.nullableTypeAnnotation(t.anyTypeAnnotation())), - ).toEqual({ - type: 'NullableTypeAnnotation', - loc: null, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }); -}); - -test('getFunctionTypeAnnotation, function has a function as parameter', () => { - const callback: BabelNodeFunctionTypeAnnotation = t.functionTypeAnnotation( - undefined, - [], - undefined, - t.voidTypeAnnotation(), - ); - const functionNode: BabelNodeFunctionTypeAnnotation = - t.functionTypeAnnotation( - undefined, - [ - t.functionTypeParam( - t.identifier('screenShoudBeKeptOn'), - t.anyTypeAnnotation(), - ), - t.functionTypeParam(t.identifier('callback'), callback), - ], - undefined, - t.anyTypeAnnotation(), - ); - expect(getFunctionTypeAnnotation(functionNode)).toEqual({ - type: 'FunctionTypeAnnotation', - loc: null, - params: [ - { - loc: null, - name: 'screenShoudBeKeptOn', - optional: undefined, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }, - { - loc: null, - name: 'callback', - optional: undefined, - typeAnnotation: { - type: 'FunctionTypeAnnotation', - loc: null, - params: [], - returnTypeAnnotation: { - type: 'VoidTypeAnnotation', - loc: null, - }, - }, - }, - ], - returnTypeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }); -}); - -test('getFunctionTypeParameter, testig basic type parameter', () => { - const param: BabelNodeFunctionTypeParam = t.functionTypeParam( - t.identifier('testParam'), - t.anyTypeAnnotation(), - ); - expect(getFunctionTypeParameter(param)).toEqual({ - loc: null, - name: 'testParam', - optional: undefined, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }); -}); - -test('getObjectTypeAnnotation, testing an object with a AnyTypeAnnotation property', () => { - const property: BabelNodeObjectTypeProperty = t.objectTypeProperty( - t.identifier('setKeepScreenOn'), - t.anyTypeAnnotation(), - t.variance('minus'), - ); - const objectNode: BabelNodeObjectTypeAnnotation = t.objectTypeAnnotation( - [property], - [], - [], - [], - false, - ); - expect(getObjectTypeAnnotation(objectNode)).toEqual({ - type: 'ObjectTypeAnnotation', - loc: null, - properties: [ - { - loc: null, - name: 'setKeepScreenOn', - optional: null, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }, - ], - }); -}); - -test('getObjectTypeProperty, testing AnyTypeAnnotation property', () => { - const property: BabelNodeObjectTypeProperty = t.objectTypeProperty( - t.identifier('testProp'), - t.anyTypeAnnotation(), - t.variance('plus'), - ); - expect(getObjectTypeProperty(property)).toEqual({ - loc: null, - name: 'testProp', - optional: null, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }); -}); - -test('getObjectTypeSpreadProperty returns unknown type', () => { - const spreadProperty: BabelNodeObjectTypeSpreadProperty = - t.objectTypeSpreadProperty(t.anyTypeAnnotation()); - expect(getObjectTypeSpreadProperty(spreadProperty)).toEqual({ - loc: null, - name: '', - optional: false, - typeAnnotation: { - loc: null, - type: 'AnyTypeAnnotation', - }, - }); -}); - -test('getTupleTypeAnnotation, testing basic tuple', () => { - const typeNode: BabelNodeTupleTypeAnnotation = t.tupleTypeAnnotation([ - t.anyTypeAnnotation(), - t.anyTypeAnnotation(), - ]); - expect(getTupleTypeAnnotation(typeNode)).toEqual({ - type: 'TupleTypeAnnotation', - loc: null, - types: [ - {type: 'AnyTypeAnnotation', loc: null}, - {type: 'AnyTypeAnnotation', loc: null}, - ], - }); -}); - -test('getGenericTypeAnnotation, testing a generic type', () => { - const typeNode: BabelNodeGenericTypeAnnotation = t.genericTypeAnnotation( - t.identifier('testGeneric'), - t.typeParameterInstantiation([ - t.anyTypeAnnotation(), - t.anyTypeAnnotation(), - ]), - ); - expect(getGenericTypeAnnotation(typeNode)).toEqual({ - type: 'GenericTypeAnnotation', - loc: null, - name: 'testGeneric', - typeParameters: [ - {type: 'AnyTypeAnnotation', loc: null}, - {type: 'AnyTypeAnnotation', loc: null}, - ], - }); -}); - -test('getUnionTypeAnnotation, testing an union type', () => { - const typeNode: BabelNodeUnionTypeAnnotation = t.unionTypeAnnotation([ - t.anyTypeAnnotation(), - t.anyTypeAnnotation(), - ]); - expect(getUnionTypeAnnotation(typeNode)).toEqual({ - type: 'UnionTypeAnnotation', - loc: null, - types: [ - {type: 'AnyTypeAnnotation', loc: null}, - {type: 'AnyTypeAnnotation', loc: null}, - ], - }); -}); - -test('getIntersectionTypeAnnotation, testing an intersection type', () => { - const typeNode: BabelNodeIntersectionTypeAnnotation = - t.intersectionTypeAnnotation([ - t.anyTypeAnnotation(), - t.anyTypeAnnotation(), - ]); - expect(getIntersectionTypeAnnotation(typeNode)).toEqual({ - type: 'IntersectionTypeAnnotation', - loc: null, - types: [ - {type: 'AnyTypeAnnotation', loc: null}, - {type: 'AnyTypeAnnotation', loc: null}, - ], - }); -}); - -test('getArrayTypeAnnotation, testing an array of AnyTypeAnnotation', () => { - const arrayNode: BabelNodeArrayTypeAnnotation = t.arrayTypeAnnotation( - t.anyTypeAnnotation(), - ); - expect(getArrayTypeAnnotation(arrayNode)).toEqual({ - type: 'ArrayTypeAnnotation', - loc: null, - elementType: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }); -}); - -test('getTypeAnnotation, testing BooleanLiteralTypeAnnotation', () => { - expect(getTypeAnnotation(t.booleanLiteralTypeAnnotation(true))).toEqual({ - type: 'BooleanLiteralTypeAnnotation', - loc: null, - value: true, - }); -}); - -//TODO:T130441624 add test.each instead of creating each test individualy -test('getTypeAnnotation, testing NullLiteralTypeAnnotation', () => { - expect(getTypeAnnotation(t.nullLiteralTypeAnnotation())).toEqual({ - type: 'NullLiteralTypeAnnotation', - loc: null, - }); -}); - -test('getNumberLiteralTypeAnnotation, testing NumberLiteralType', () => { - const typeNode: BabelNodeNumberLiteralTypeAnnotation = - t.numberLiteralTypeAnnotation(4); - expect(getNumberLiteralTypeAnnotation(typeNode)).toEqual({ - type: 'NumberLiteralTypeAnnotation', - loc: null, - value: 4, - }); -}); - -test('getStringLiteralTypeAnnotation, testing StringLiteralType', () => { - const typeNode: BabelNodeStringLiteralTypeAnnotation = - t.stringLiteralTypeAnnotation('test'); - expect(getStringLiteralTypeAnnotation(typeNode)).toEqual({ - type: 'StringLiteralTypeAnnotation', - loc: null, - value: 'test', - }); -}); - -test('getTypeParameters, testing AnyTypeAnnotation parameter', () => { - const params: Array = [t.anyTypeAnnotation()]; - expect(getTypeParameters(params)).toEqual([ - { - type: 'AnyTypeAnnotation', - loc: null, - }, - ]); -}); - -test('getInterfaceExtends, testing interface with no parameters', () => { - const interfaceNode: BabelNodeInterfaceExtends = t.interfaceExtends( - t.identifier('test'), - undefined, - ); - expect(getInterfaceExtends(interfaceNode)).toEqual({ - loc: null, - name: 'test', - typeParameters: [], - }); -}); - -test('getNameFromID, testing BabelNodeIdentifier', () => { - const node: BabelNodeIdentifier = t.identifier('test'); - expect(getNameFromID(node)).toBe('test'); -}); - -test('getNameFromID, testing BabelNodeQualifiedTypeIdentifier', () => { - const node: BabelNodeQualifiedTypeIdentifier = t.qualifiedTypeIdentifier( - t.identifier('test'), - t.identifier('testQualifier'), - ); - expect(getNameFromID(node)).toBe('test'); -}); - -test('getNameFromID, testing BabelNodeStringLiteral', () => { - const node: BabelNodeStringLiteral = t.stringLiteral('test'); - expect(getNameFromID(node)).toBe('test'); -}); - -test('getNodeLoc, testing basic loc', () => { - // $FlowFixMe[incompatible-exact] - const ast: BabelNodeFile = parse('test', { - babel: true, - sourceType: 'module', - sourceFilename: 'test.js', - }); - expect(getNodeLoc(ast.loc)).toEqual({ - start: { - line: 1, - column: 0, - }, - end: { - line: 1, - column: 4, - }, - }); -}); - -test('getNodeLoc, testing undefined loc', () => { - expect(getNodeLoc(undefined)).toBe(null); -}); - -test('getBoundarySchemaFromAST, integration test', () => { - const code: string = ` - export interface Spec extends TurboModule { - +getConstants: () => {| - +testGeneric0: Object, - +testUnion0?: string | string, - +testIntersection0?: string & string, - +testTuple0?: [string, number], - +scale?: number, - +isSimulator?: boolean, - +majorOsVersion?: number, - +isTablet?: boolean, - +deviceID: string, - |}; - +setKeepScreenOn: (screenShouldBeKeptOn: boolean) => void; - } - - const NativeModule: ?Spec = TurboModuleRegistry.get('DeviceManager'); - - let NativeDeviceManager: ?Spec = null; - let constants = null; - - if (NativeModule != null) { - NativeDeviceManager = { - getConstants(): {| - +scale?: number, - +isSimulator?: boolean, - +majorOsVersion?: number, - +isTablet?: boolean, - +deviceID: string, - |} { - if (constants == null) { - constants = NativeModule.getConstants(); - } - return constants; - }, - setKeepScreenOn(screenShouldBeKeptOn: boolean): void { - NativeModule.setKeepScreenOn(screenShouldBeKeptOn); - }, - }; - }`; - // $FlowFixMe[incompatible-exact] - const ast: BabelNodeFile = parse(code, { - babel: true, - sourceType: 'module', - sourceFilename: 'NativeDeviceManager.js', - }); - expect(getBoundarySchemaFromAST(ast, 'test.js')).toMatchSnapshot(); -}); diff --git a/packages/metro-react-native-interop-tools/src/__tests__/index-test.js b/packages/metro-react-native-interop-tools/src/__tests__/index-test.js deleted file mode 100644 index 71cc4502d1..0000000000 --- a/packages/metro-react-native-interop-tools/src/__tests__/index-test.js +++ /dev/null @@ -1,16 +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 run from '../index'; - -test('returns Hello World', () => { - expect(run()).toEqual('Hello World'); -}); diff --git a/packages/metro-react-native-interop-tools/src/__tests__/type-comparison-test.js b/packages/metro-react-native-interop-tools/src/__tests__/type-comparison-test.js deleted file mode 100644 index fca4c6d17f..0000000000 --- a/packages/metro-react-native-interop-tools/src/__tests__/type-comparison-test.js +++ /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 - * @oncall react_native - */ - -import {parse} from 'hermes-parser'; -import {getTypeAnnotation} from '../ast-helpers.js'; -import {compareTypeAnnotation} from '../type-comparison.js'; -import type {AnyTypeAnnotation} from '../type-annotation.js'; -import type {FlowType, Statement} from '@babel/types'; - -function getTypeFromAlias(body: Statement): FlowType { - if (body.type !== 'TypeAlias') { - throw new Error('This function support only TypeAlias'); - } - return body.right; -} - -function getTypeFromCode(stringType: string): AnyTypeAnnotation { - const ast: $FlowFixMe = parse('type T =' + stringType, { - babel: true, - sourceType: 'module', - sourceFilename: 'NativeDeviceManager.js', - }); - const astType = getTypeFromAlias(ast.program.body[0]); - return getTypeAnnotation(astType); -} - -test.each([ - ['boolean', 'boolean'], - ['string', 'string'], - ['number', 'number'], - ['void', 'void'], - ['boolean', 'number'], - ["'a'", "'a'"], - ["'a'", "'b'"], - ['8', '8'], - ['2', '8'], - ['2', 'number'], - ['number', '2'], - ['string', "'a'"], - ["'a'", 'string'], - ['true', 'true'], - ['true', 'false'], - ['string', '?string'], - ['?number', 'number'], - ['?boolean', 'true'], - ['?string', '?string'], - ['?string', "?'foo'"], - ['?string', '?number'], - ['null', 'null'], - ['?string', 'null'], - ['?boolean', 'void'], - ['() => boolean', '() => ?boolean'], - ['() => ?boolean', '() => boolean'], - ['() => true', '() => boolean'], - ['(test: ?boolean) => true', '(test: boolean) => true'], - ['(test?: string) => void', '() => void'], - ['(test: string) => void', '() => void'], - ['() => void', '(test?: string) => void'], - ['() => void', '(test?: string, test2: number) => void'], - ['(test?: boolean) => true', '(test?: string) => true'], - ['(test: string) => ?true', '() => void'], - ['{name: string, age: ?number }', '{name: string, age: number }'], - ['{name: string, age: number }', '{name: string, age?: number }'], - ['{name: string, age: number }', '{name: string}'], - ['{name: string, age?: number }', '{name: string}'], - ['{name: string}', '{name: string, ...}'], - ['{name: string}', '{name: string, age: number}'], - ['{name: string}', '{name: string, age?: number}'], - ['() => {name: string, age?: number }', '() => {name: string}'], - ['() => {name: string, age: number }', '() => {name: string}'], - ['() => {name: string}', '() => {name: string, age: number}'], - ['() => {name: string}', '() => {name: string, age: ?number}'], -])('comparing basic types', (left, right) => { - const result = compareTypeAnnotation( - getTypeFromCode(left), - getTypeFromCode(right), - false, - ); - let messages: string = ''; - result.forEach(error => { - messages = messages + error.message + '\n \t\t'; - }); - messages = messages === '' ? 'no errors' : messages; - expect(` - left-type: - ${left} - right-type: - ${right} - output: - ${messages}`).toMatchSnapshot(); -}); diff --git a/packages/metro-react-native-interop-tools/src/ast-helpers.js b/packages/metro-react-native-interop-tools/src/ast-helpers.js deleted file mode 100644 index 035262ba01..0000000000 --- a/packages/metro-react-native-interop-tools/src/ast-helpers.js +++ /dev/null @@ -1,396 +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 { - File as BabelNodeFile, - FunctionTypeAnnotation as BabelNodeFunctionTypeAnnotation, - FunctionTypeParam as BabelNodeFunctionTypeParam, - ObjectTypeAnnotation as BabelNodeObjectTypeAnnotation, - ObjectTypeProperty as BabelNodeObjectTypeProperty, - ObjectTypeSpreadProperty as BabelNodeObjectTypeSpreadProperty, - TupleTypeAnnotation as BabelNodeTupleTypeAnnotation, - NullableTypeAnnotation as BabelNodeNullableTypeAnnotation, - GenericTypeAnnotation as BabelNodeGenericTypeAnnotation, - UnionTypeAnnotation as BabelNodeUnionTypeAnnotation, - IntersectionTypeAnnotation as BabelNodeIntersectionTypeAnnotation, - ArrayTypeAnnotation as BabelNodeArrayTypeAnnotation, - InterfaceExtends as BabelNodeInterfaceExtends, - StringLiteralTypeAnnotation as BabelNodeStringLiteralTypeAnnotation, - NumberLiteralTypeAnnotation as BabelNodeNumberLiteralTypeAnnotation, - InterfaceDeclaration as BabelNodeInterfaceDeclaration, - FlowType as BabelNodeFlowType, - Statement as BabelNodeStatement, -} from '@babel/types'; - -import type { - AnyType, - NumberTypeAnnotation, - StringTypeAnnotation, - VoidTypeAnnotation, - BooleanTypeAnnotation, - InterfaceExtends, - AnyTypeAnnotation, - ArrayTypeAnnotation, - NullableTypeAnnotation, - FunctionTypeAnnotation, - ObjectTypeAnnotation, - FunctionTypeParam, - ObjectTypeProperty, - TupleTypeAnnotation, - GenericTypeAnnotation, - UnionTypeAnnotation, - IntersectionTypeAnnotation, - StringLiteralTypeAnnotation, - NumberLiteralTypeAnnotation, - BooleanLiteralTypeAnnotation, - NullLiteralTypeAnnotation, -} from './type-annotation.js'; - -export type BoundarySchema = { - typegenSchema: {}, - source: string, - ... -}; - -export function isTurboModule(i: BabelNodeInterfaceExtends): boolean { - return ( - i.id.name === 'TurboModule' && - (i.typeParameters == null || i.typeParameters.params.length === 0) - ); -} - -export function getNodeLoc( - loc: ?BabelNodeSourceLocation, -): ?BabelNodeSourceLocation { - return loc == null - ? null - : { - start: loc.start, - end: loc.end, - }; -} - -export function getTypeAnnotation(typeNode: BabelNodeFlow): AnyTypeAnnotation { - switch (typeNode.type) { - case 'BooleanTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: BooleanTypeAnnotation); - - case 'NumberTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: NumberTypeAnnotation); - - case 'StringTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: StringTypeAnnotation); - - case 'VoidTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: VoidTypeAnnotation); - - case 'AnyTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: AnyType); - - case 'NullLiteralTypeAnnotation': - return ({ - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - }: NullLiteralTypeAnnotation); - - case 'BooleanLiteralTypeAnnotation': - return getBooleanLiteralTypeAnnotation(typeNode); - - case 'NumberLiteralTypeAnnotation': - return getNumberLiteralTypeAnnotation(typeNode); - - case 'StringLiteralTypeAnnotation': - return getStringLiteralTypeAnnotation(typeNode); - - case 'ArrayTypeAnnotation': - return getArrayTypeAnnotation(typeNode); - - case 'NullableTypeAnnotation': - return getNullableTypeAnnotation(typeNode); - - case 'FunctionTypeAnnotation': - return getFunctionTypeAnnotation(typeNode); - - case 'ObjectTypeAnnotation': - return getObjectTypeAnnotation(typeNode); - - case 'TupleTypeAnnotation': - return getTupleTypeAnnotation(typeNode); - - case 'GenericTypeAnnotation': - return getGenericTypeAnnotation(typeNode); - - case 'UnionTypeAnnotation': - return getUnionTypeAnnotation(typeNode); - - case 'IntersectionTypeAnnotation': - return getIntersectionTypeAnnotation(typeNode); - - default: - throw new Error(typeNode.type + ' not supported'); - } -} - -export function getFunctionTypeAnnotation( - typeNode: BabelNodeFunctionTypeAnnotation, -): FunctionTypeAnnotation { - return { - type: 'FunctionTypeAnnotation', - loc: getNodeLoc(typeNode.loc), - params: typeNode.params.map(getFunctionTypeParameter), - returnTypeAnnotation: getTypeAnnotation(typeNode.returnType), - }; -} - -export function getFunctionTypeParameter( - param: BabelNodeFunctionTypeParam, -): FunctionTypeParam { - return { - loc: getNodeLoc(param.loc), - name: param.name?.name, - optional: param.optional, - typeAnnotation: getTypeAnnotation(param.typeAnnotation), - }; -} - -export function getObjectTypeAnnotation( - typeNode: BabelNodeObjectTypeAnnotation, -): ObjectTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - properties: typeNode.properties.map( - ( - property: - | BabelNodeObjectTypeProperty - | BabelNodeObjectTypeSpreadProperty, - ) => { - return property.type === 'ObjectTypeProperty' - ? getObjectTypeProperty(property) - : getObjectTypeSpreadProperty(property); - }, - ), - }; -} - -//TODO T127639272 add support for spread properties -export function getObjectTypeSpreadProperty( - typeProperty: BabelNodeObjectTypeSpreadProperty, -): ObjectTypeProperty { - return { - loc: getNodeLoc(typeProperty.loc), - name: '', - optional: false, - typeAnnotation: { - type: 'AnyTypeAnnotation', - loc: null, - }, - }; -} - -export function getObjectTypeProperty( - typeProperty: BabelNodeObjectTypeProperty, -): ObjectTypeProperty { - return { - loc: getNodeLoc(typeProperty.loc), - name: getNameFromID(typeProperty.key), - optional: typeProperty.optional, - typeAnnotation: getTypeAnnotation(typeProperty.value), - }; -} - -export function getTupleTypeAnnotation( - typeNode: BabelNodeTupleTypeAnnotation, -): TupleTypeAnnotation { - return { - type: 'TupleTypeAnnotation', - loc: getNodeLoc(typeNode.loc), - types: typeNode.types.map(getTypeAnnotation), - }; -} - -export function getNullableTypeAnnotation( - typeNode: BabelNodeNullableTypeAnnotation, -): NullableTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - typeAnnotation: getTypeAnnotation(typeNode.typeAnnotation), - }; -} - -// Flow can check for exhaustive switch cases where eslint can not, using flow to cover all possible cases is better than having default fallbacks. -// eslint-disable-next-line consistent-return -export function getNameFromID( - node: - | BabelNodeIdentifier - | BabelNodeQualifiedTypeIdentifier - | BabelNodeStringLiteral, -): string { - switch (node.type) { - case 'QualifiedTypeIdentifier': - return node.id.name; - case 'StringLiteral': - return node.value; - case 'Identifier': - return node.name; - } -} - -export function getGenericTypeAnnotation( - typeNode: BabelNodeGenericTypeAnnotation, -): GenericTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - name: getNameFromID(typeNode.id), - typeParameters: typeNode.typeParameters?.params - ? typeNode.typeParameters.params?.map(getTypeAnnotation) - : [], - }; -} - -export function getUnionTypeAnnotation( - typeNode: BabelNodeUnionTypeAnnotation, -): UnionTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - types: typeNode.types.map(getTypeAnnotation), - }; -} - -export function getIntersectionTypeAnnotation( - typeNode: BabelNodeIntersectionTypeAnnotation, -): IntersectionTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - types: typeNode.types.map(getTypeAnnotation), - }; -} - -export function getArrayTypeAnnotation( - typeNode: BabelNodeArrayTypeAnnotation, -): ArrayTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - elementType: getTypeAnnotation(typeNode.elementType), - }; -} - -export function getStringLiteralTypeAnnotation( - typeNode: BabelNodeStringLiteralTypeAnnotation, -): StringLiteralTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - value: typeNode.value, - }; -} - -export function getNumberLiteralTypeAnnotation( - typeNode: BabelNodeNumberLiteralTypeAnnotation, -): NumberLiteralTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - value: typeNode.value, - }; -} - -export function getBooleanLiteralTypeAnnotation( - typeNode: BabelNodeBooleanLiteralTypeAnnotation, -): BooleanLiteralTypeAnnotation { - return { - type: typeNode.type, - loc: getNodeLoc(typeNode.loc), - value: typeNode.value, - }; -} - -export function getInterfaceExtends( - interfaceNode: BabelNodeInterfaceExtends, -): InterfaceExtends { - return { - loc: getNodeLoc(interfaceNode.loc), - name: getNameFromID(interfaceNode.id), - typeParameters: getTypeParameters(interfaceNode.typeParameters?.params), - }; -} - -function interfaceDeclarationReducer( - interfaceDeclaration: ?BabelNodeInterfaceDeclaration, - bodyNode: BabelNodeStatement, -): ?BabelNodeInterfaceDeclaration { - if ( - bodyNode.type === 'ExportNamedDeclaration' && - bodyNode.declaration != null - ) { - return interfaceDeclarationReducer( - interfaceDeclaration, - bodyNode.declaration, - ); - } else if ( - bodyNode.type === 'InterfaceDeclaration' && - bodyNode.extends?.some(isTurboModule) - ) { - return bodyNode; - } - return interfaceDeclaration; -} - -export function getTypeParameters( - params: ?Array, -): Array { - return params?.map(getTypeAnnotation) ?? []; -} - -export function getBoundarySchemaFromAST( - ast: BabelNodeFile, - source: string, -): BoundarySchema { - const schema: BoundarySchema = { - typegenSchema: {}, - source, - }; - const interfaceNode: ?BabelNodeInterfaceDeclaration = ast.program.body.reduce( - interfaceDeclarationReducer, - null, - ); - if (interfaceNode != null) { - // $FlowFixMe[prop-missing] - schema.typegenSchema[interfaceNode.id.name] = { - typeAnnotation: { - type: 'InterfaceDeclarationTypeAnnotation', - innerType: getTypeAnnotation(interfaceNode.body), - extends: interfaceNode.extends?.map(getInterfaceExtends), - }, - }; - } - return schema; -} diff --git a/packages/metro-react-native-interop-tools/src/index.js b/packages/metro-react-native-interop-tools/src/index.js deleted file mode 100644 index d72adb6b2b..0000000000 --- a/packages/metro-react-native-interop-tools/src/index.js +++ /dev/null @@ -1,14 +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 default function run(): string { - return 'Hello World'; -} diff --git a/packages/metro-react-native-interop-tools/src/type-annotation.js b/packages/metro-react-native-interop-tools/src/type-annotation.js deleted file mode 100644 index bd730ff5ab..0000000000 --- a/packages/metro-react-native-interop-tools/src/type-annotation.js +++ /dev/null @@ -1,154 +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 {SourceLocation} from '@babel/types'; - -export type AnyType = $ReadOnly<{ - type: 'AnyTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type BooleanTypeAnnotation = $ReadOnly<{ - type: 'BooleanTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type NumberTypeAnnotation = $ReadOnly<{ - type: 'NumberTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type StringTypeAnnotation = $ReadOnly<{ - type: 'StringTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type VoidTypeAnnotation = $ReadOnly<{ - type: 'VoidTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type FunctionTypeParam = $ReadOnly<{| - loc: ?SourceLocation, - name: ?string, - optional: ?boolean, - typeAnnotation: AnyTypeAnnotation, -|}>; - -export type ObjectTypeProperty = $ReadOnly<{ - loc: ?SourceLocation, - name: string, - optional: boolean, - typeAnnotation: AnyTypeAnnotation, -}>; - -export type InterfaceExtends = $ReadOnly<{ - loc: ?BabelNodeSourceLocation, - name: string, - typeParameters: $ReadOnlyArray, -}>; - -export type NullableTypeAnnotation = $ReadOnly<{ - type: 'NullableTypeAnnotation', - loc: ?SourceLocation, - typeAnnotation: AnyTypeAnnotation, -}>; - -export type FunctionTypeAnnotation = $ReadOnly<{ - type: 'FunctionTypeAnnotation', - loc: ?SourceLocation, - params: $ReadOnlyArray, - returnTypeAnnotation: AnyTypeAnnotation, -}>; - -export type ObjectTypeAnnotation = $ReadOnly<{ - type: 'ObjectTypeAnnotation', - loc: ?SourceLocation, - properties: $ReadOnlyArray, -}>; - -export type TupleTypeAnnotation = $ReadOnly<{ - type: 'TupleTypeAnnotation', - loc: ?SourceLocation, - types: $ReadOnlyArray, -}>; - -export type GenericTypeAnnotation = $ReadOnly<{ - type: 'GenericTypeAnnotation', - loc: ?SourceLocation, - name: string, - typeParameters: $ReadOnlyArray, -}>; - -export type UnionTypeAnnotation = $ReadOnly<{ - type: 'UnionTypeAnnotation', - loc: ?SourceLocation, - types: $ReadOnlyArray, -}>; - -export type IntersectionTypeAnnotation = $ReadOnly<{ - type: 'IntersectionTypeAnnotation', - loc: ?SourceLocation, - types: $ReadOnlyArray, -}>; - -export type ArrayTypeAnnotation = $ReadOnly<{ - type: 'ArrayTypeAnnotation', - loc: ?SourceLocation, - elementType: AnyTypeAnnotation, -}>; - -export type StringLiteralTypeAnnotation = $ReadOnly<{ - type: 'StringLiteralTypeAnnotation', - loc: ?SourceLocation, - value: string, -}>; - -export type NumberLiteralTypeAnnotation = $ReadOnly<{ - type: 'NumberLiteralTypeAnnotation', - loc: ?SourceLocation, - value: number, -}>; - -export type BooleanLiteralTypeAnnotation = $ReadOnly<{ - type: 'BooleanLiteralTypeAnnotation', - loc: ?SourceLocation, - value: boolean, -}>; - -export type NullLiteralTypeAnnotation = $ReadOnly<{ - type: 'NullLiteralTypeAnnotation', - loc: ?SourceLocation, -}>; - -export type LiteralTypeAnnotation = - | StringLiteralTypeAnnotation - | NumberLiteralTypeAnnotation - | BooleanLiteralTypeAnnotation; - -export type AnyTypeAnnotation = - | BooleanTypeAnnotation - | NumberTypeAnnotation - | StringTypeAnnotation - | VoidTypeAnnotation - | AnyType - | NullableTypeAnnotation - | FunctionTypeAnnotation - | ObjectTypeAnnotation - | TupleTypeAnnotation - | GenericTypeAnnotation - | UnionTypeAnnotation - | IntersectionTypeAnnotation - | ArrayTypeAnnotation - | StringLiteralTypeAnnotation - | NumberLiteralTypeAnnotation - | BooleanLiteralTypeAnnotation - | NullLiteralTypeAnnotation; diff --git a/packages/metro-react-native-interop-tools/src/type-comparison.js b/packages/metro-react-native-interop-tools/src/type-comparison.js deleted file mode 100644 index 79765889b5..0000000000 --- a/packages/metro-react-native-interop-tools/src/type-comparison.js +++ /dev/null @@ -1,447 +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 { - VoidTypeAnnotation, - UnionTypeAnnotation, - TupleTypeAnnotation, - StringTypeAnnotation, - StringLiteralTypeAnnotation, - NumberTypeAnnotation, - NumberLiteralTypeAnnotation, - NullLiteralTypeAnnotation, - IntersectionTypeAnnotation, - GenericTypeAnnotation, - BooleanTypeAnnotation, - BooleanLiteralTypeAnnotation, - ArrayTypeAnnotation, - AnyType, -} from './type-annotation'; -import type { - AnyTypeAnnotation, - NullableTypeAnnotation, - LiteralTypeAnnotation, - FunctionTypeAnnotation, - FunctionTypeParam, - ObjectTypeProperty, - ObjectTypeAnnotation, -} from './type-annotation.js'; -import type {SourceLocation} from '@babel/types'; - -import nullthrows from 'nullthrows'; - -type ComparisonResult = $ReadOnly<{ - message: string, - newTypeLoc: ?SourceLocation, - oldTypeLoc: ?SourceLocation, -}>; - -function removeNullable( - annotation: NullableTypeAnnotation, -): - | AnyType - | BooleanTypeAnnotation - | NumberTypeAnnotation - | StringTypeAnnotation - | VoidTypeAnnotation - | TupleTypeAnnotation - | GenericTypeAnnotation - | UnionTypeAnnotation - | IntersectionTypeAnnotation - | ArrayTypeAnnotation - | StringLiteralTypeAnnotation - | NumberLiteralTypeAnnotation - | BooleanLiteralTypeAnnotation - | NullLiteralTypeAnnotation - | FunctionTypeAnnotation - | ObjectTypeAnnotation { - if (annotation.typeAnnotation.type === 'NullableTypeAnnotation') { - return removeNullable(annotation.typeAnnotation); - } - return annotation.typeAnnotation; -} - -function getSimplifiedType(annotation: AnyTypeAnnotation): string { - switch (annotation.type) { - case 'BooleanTypeAnnotation': - return 'boolean'; - case 'StringTypeAnnotation': - return 'string'; - case 'NumberTypeAnnotation': - return 'number'; - case 'VoidTypeAnnotation': - return 'void'; - case 'StringLiteralTypeAnnotation': - return 'string literal'; - case 'NumberLiteralTypeAnnotation': - return 'number literal'; - case 'BooleanLiteralTypeAnnotation': - return 'boolean literal'; - case 'NullLiteralTypeAnnotation': - return 'null'; - case 'NullableTypeAnnotation': - return `nullable ${getSimplifiedType(removeNullable(annotation))}`; - case 'FunctionTypeAnnotation': - return 'function'; - case 'ObjectTypeAnnotation': - return 'object'; - } - throw new Error(annotation.type + ' is not supported'); -} - -export function compareTypeAnnotation( - left: AnyTypeAnnotation, - right: AnyTypeAnnotation, - isInFunctionReturn: boolean, -): Array { - switch (left.type) { - case 'BooleanTypeAnnotation': - if ( - right.type === left.type || - right.type === 'BooleanLiteralTypeAnnotation' - ) { - return []; - } - return [basicError(left, right, isInFunctionReturn)]; - case 'NumberTypeAnnotation': - if ( - left.type === right.type || - right.type === 'NumberLiteralTypeAnnotation' - ) { - return []; - } - return [basicError(left, right, isInFunctionReturn)]; - case 'StringTypeAnnotation': - if ( - left.type === right.type || - right.type === 'StringLiteralTypeAnnotation' - ) { - return []; - } - return [basicError(left, right, isInFunctionReturn)]; - case 'VoidTypeAnnotation': - if (right.type === 'VoidTypeAnnotation') { - return []; - } - return [basicError(left, right, isInFunctionReturn)]; - case 'StringLiteralTypeAnnotation': - case 'BooleanLiteralTypeAnnotation': - case 'NumberLiteralTypeAnnotation': - if (right.type === left.type) { - if (right.value === left.value) { - return []; - } - return [ - literalError( - left, - // $FlowFixMe[incompatible-cast] - (right: LiteralTypeAnnotation), - isInFunctionReturn, - ), - ]; - } - return [basicError(left, right, isInFunctionReturn)]; - case 'NullLiteralTypeAnnotation': - if (right.type !== 'NullLiteralTypeAnnotation') { - return [basicError(left, right, isInFunctionReturn)]; - } - return []; - case 'NullableTypeAnnotation': - if (right.type === 'NullableTypeAnnotation') { - return compareTypeAnnotation( - left.typeAnnotation, - right.typeAnnotation, - isInFunctionReturn, - ); - } - if ( - right.type === 'NullLiteralTypeAnnotation' || - right.type === 'VoidTypeAnnotation' - ) { - return []; - } - return compareTypeAnnotation( - left.typeAnnotation, - right, - isInFunctionReturn, - ); - case 'FunctionTypeAnnotation': - if (right.type === 'FunctionTypeAnnotation') { - return compareFunctionType(left, right, isInFunctionReturn); - } - return [basicError(left, right, isInFunctionReturn)]; - case 'ObjectTypeAnnotation': - if (right.type === 'ObjectTypeAnnotation') { - return compareObjectType(left, right, isInFunctionReturn); - } - return [basicError(left, right, isInFunctionReturn)]; - default: - throw new Error(left.type + 'is not supported'); - } -} - -function unsafeMadeOptional( - leftOptional: boolean, - rightOptional: boolean, - isInFunctionReturn: boolean, -): boolean { - /* - * For object properties in an object that's part of function return - * statement we can't change from optional to required because the - * native code might still return a nullable value where js no longer expects it. - * For function parameters or object properties that are not - * in the function return we can't change from required to optional because - * native code still requires this parameter as part of its function signature. - */ - return ( - (leftOptional === false && rightOptional === true && !isInFunctionReturn) || - (leftOptional === true && rightOptional === false && isInFunctionReturn) - ); -} - -function compareObjectType( - left: ObjectTypeAnnotation, - right: ObjectTypeAnnotation, - isInFunctionReturn: boolean, -): Array { - const leftProps = new Map(); - const rightProps = new Map(); - const finalResult = []; - left.properties.forEach(prop => { - leftProps.set(prop.name, prop); - }); - right.properties.forEach(prop => { - rightProps.set(prop.name, prop); - }); - - for (const key of leftProps.keys()) { - const leftType = nullthrows(leftProps.get(key)); - const rightType = rightProps.get(key); - if (rightType != null) { - const leftOptional = leftType.optional; - const rightOptional = rightType.optional; - const comparisonResult = compareTypeAnnotation( - leftType.typeAnnotation, - rightType.typeAnnotation, - isInFunctionReturn, - ); - if (comparisonResult.length > 0) { - finalResult.push(...comparisonResult); - } - if (unsafeMadeOptional(leftOptional, rightOptional, isInFunctionReturn)) { - finalResult.push( - optionalError(leftType, rightType, isInFunctionReturn), - ); - } - } else if (leftType.optional === false) { - finalResult.push( - differentPropertiesError( - leftType.typeAnnotation, - right, - isInFunctionReturn, - ), - ); - } - } - for (const key of rightProps.keys()) { - const leftType = leftProps.get(key); - const rightType = nullthrows(rightProps.get(key)); - if (leftType == null && rightType.optional === false) { - finalResult.push( - differentPropertiesError( - left, - rightType.typeAnnotation, - isInFunctionReturn, - ), - ); - } - } - return finalResult; -} - -function compareFunctionType( - left: FunctionTypeAnnotation, - right: FunctionTypeAnnotation, - isInFunctionReturn: boolean, -): Array { - /* - * For the returned type comparison the comparison should be made - * other way around, because it will return from native something - * instead of native to be called from js - */ - const finalResult = []; - finalResult.push( - ...compareTypeAnnotation( - right.returnTypeAnnotation, - left.returnTypeAnnotation, - true, - ), - ); - let minimumLength = right.params.length; - if (left.params.length < right.params.length) { - minimumLength = left.params.length; - for (let index = left.params.length; index < right.params.length; ++index) { - if (right.params[index].optional !== true) { - finalResult.push( - addedRequiredParamError(left, right.params[index].typeAnnotation), - ); - } - } - } - for (let index = 0; index < minimumLength; ++index) { - finalResult.push( - ...compareTypeAnnotation( - left.params[index].typeAnnotation, - right.params[index].typeAnnotation, - isInFunctionReturn, - ), - ); - if ( - left.params[index].optional === false && - right.params[index].optional === true - ) { - finalResult.push( - optionalError( - left.params[index], - right.params[index], - isInFunctionReturn, - ), - ); - } - } - for (let index = right.params.length; index < left.params.length; ++index) { - if (left.params[index].optional !== true) { - finalResult.push( - removedRequiredParamError(left.params[index].typeAnnotation, right), - ); - } - } - return finalResult; -} - -function addedRequiredParamError( - oldType: FunctionTypeAnnotation, - newType: AnyTypeAnnotation, -): ComparisonResult { - const addedType = getSimplifiedType(newType); - return { - message: `Error: cannot add new required parameter ${addedType} because native will not provide it.`, - oldTypeLoc: oldType.loc, - newTypeLoc: newType.loc, - }; -} - -function removedRequiredParamError( - oldType: AnyTypeAnnotation, - newType: FunctionTypeAnnotation, -) { - const removedType = getSimplifiedType(oldType); - return { - message: `Error: cannot remove required parameter ${removedType} because native code will break when js calls it.`, - oldTypeLoc: oldType.loc, - newTypeLoc: newType.loc, - }; -} - -function optionalError( - left: FunctionTypeParam | ObjectTypeProperty, - right: FunctionTypeParam | ObjectTypeProperty, - isInFunctionReturn: boolean, -): ComparisonResult { - const newAnnotationType = isInFunctionReturn ? left : right; - const oldAnnotationType = isInFunctionReturn ? right : left; - const newOptionality = - newAnnotationType.optional === true ? 'optional' : 'required'; - const oldOptionality = - oldAnnotationType.optional === true ? 'optional' : 'required'; - const newType = getSimplifiedType(newAnnotationType.typeAnnotation); - const oldType = getSimplifiedType(oldAnnotationType.typeAnnotation); - const reason = isInFunctionReturn - ? 'is incompatible with what the native code returns' - : 'native code will break when js calls it'; - return { - message: `Error: cannot change ${oldOptionality} ${oldType} to ${newOptionality} ${newType} because ${reason}.`, - newTypeLoc: newAnnotationType.loc, - oldTypeLoc: oldAnnotationType.loc, - }; -} - -function basicError( - left: AnyTypeAnnotation, - right: AnyTypeAnnotation, - isInFunctionReturn: boolean, -): ComparisonResult { - const newAnnotationType = isInFunctionReturn ? left : right; - const oldAnnotationType = isInFunctionReturn ? right : left; - const newType = getSimplifiedType(newAnnotationType); - const oldType = getSimplifiedType(oldAnnotationType); - const reason = isInFunctionReturn - ? 'is incompatible with what the native code returns' - : 'native code will break when js calls it'; - return { - message: `Error: cannot change ${oldType} to ${newType} because ${reason}.`, - newTypeLoc: newAnnotationType.loc, - oldTypeLoc: oldAnnotationType.loc, - }; -} - -function getValueFromType(annotation: LiteralTypeAnnotation): string { - if (annotation.type === 'StringLiteralTypeAnnotation') { - return annotation.value; - } - return JSON.stringify(annotation.value); -} - -function literalError( - left: LiteralTypeAnnotation, - right: LiteralTypeAnnotation, - isInFunctionReturn: boolean, -): ComparisonResult { - const newAnnotationType = isInFunctionReturn ? left : right; - const oldAnnotationType = isInFunctionReturn ? right : left; - const newType = getSimplifiedType(newAnnotationType); - const oldType = getSimplifiedType(oldAnnotationType); - const newValue = getValueFromType(newAnnotationType); - const oldValue = getValueFromType(oldAnnotationType); - const reason = isInFunctionReturn - ? 'is incompatible with what the native code returns' - : 'native code will break when js calls it'; - return { - message: `Error: cannot change ${oldType} with value '${oldValue}' to ${newType} with value '${newValue}' because ${reason}.`, - newTypeLoc: newAnnotationType.loc, - oldTypeLoc: oldAnnotationType.loc, - }; -} - -function differentPropertiesError( - left: AnyTypeAnnotation, - right: AnyTypeAnnotation, - isInFunctionReturn: boolean, -): ComparisonResult { - const newAnnotationType = isInFunctionReturn ? left : right; - const oldAnnotationType = isInFunctionReturn ? right : left; - const newType = getSimplifiedType(newAnnotationType); - const oldType = getSimplifiedType(oldAnnotationType); - let message = ''; - const reason = isInFunctionReturn - ? 'it is incompatible with what the native code returns' - : 'native code will break when js calls it'; - if (newAnnotationType.type === 'ObjectTypeAnnotation') { - message = `Error: cannot remove ${oldType} from object properties because ${reason}.`; - } else { - message = `Error: cannot add ${newType} to object properties because ${reason}.`; - } - return { - message, - newTypeLoc: newAnnotationType.loc, - oldTypeLoc: oldAnnotationType.loc, - }; -}