Migrate files in Libraries/Core to export syntax (#48889)

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

## Motivation
Modernising the react-native codebase to allow for ingestion by modern Flow tooling.

## This diff
- Updates files in `Libraries/Core` to use `export` syntax
  - `export default` for qualified objects, many `export` statements for collections
- Appends `.default` to requires of the changed files.
- Changed `* as ExceptionsManager` to `ExceptionsManager` in import statements throughout product code.
- Updates test files.
- Updates the public API snapshot (intented breaking change)

Changelog:
[General][Breaking] - Files inside `Libraries/Core` use `export` syntax, which requires the addition of `.default` when imported with the CJS `require` syntax.
[General][Breaking] - `Libraries/Core/ExceptionsManager` now exports a default `ExceptionsManager` object, and `SyntheticError` as a secondary export.

Reviewed By: huntie

Differential Revision: D68553694

fbshipit-source-id: 51c9a404b2762cb1cdb5f56cae3a683ccdfffc7f
This commit is contained in:
Iwo Plaza
2025-01-24 05:43:28 -08:00
committed by Facebook GitHub Bot
parent d2adb976ab
commit e5818d92a8
30 changed files with 86 additions and 101 deletions
@@ -16,8 +16,9 @@ jest.useFakeTimers({legacyFakeTimers: true});
jest.mock('react-native/Libraries/Utilities/HMRClient');
jest.mock('react-native/Libraries/Core/Devtools/getDevServer', () =>
jest.fn(() => ({
jest.mock('react-native/Libraries/Core/Devtools/getDevServer', () => ({
__esModule: true,
default: jest.fn(() => ({
url: 'localhost:8042/',
fullBundleUrl:
'http://localhost:8042/EntryPoint.bundle?platform=' +
@@ -25,7 +26,7 @@ jest.mock('react-native/Libraries/Core/Devtools/getDevServer', () =>
'&dev=true&minify=false&unusedExtraParam=42',
bundleLoadedFromServer: true,
})),
);
}));
const loadingViewMock = {
showMessage: jest.fn(),
@@ -78,7 +79,7 @@ let mockDataResponse;
beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
loadBundleFromServer = require('../loadBundleFromServer');
loadBundleFromServer = require('../loadBundleFromServer').default;
});
test('loadBundleFromServer will throw for JSON responses', async () => {
@@ -10,7 +10,7 @@
'use strict';
const parseErrorStack = require('../parseErrorStack');
const parseErrorStack = require('../parseErrorStack').default;
function getFakeError() {
return new Error('Happy Cat');
@@ -11,7 +11,7 @@
'use strict';
const parseHermesStack = require('../parseHermesStack');
const parseHermesStack = require('../parseHermesStack').default;
describe('parseHermesStack', () => {
test('bytecode location', () => {
@@ -25,7 +25,7 @@ type DevServerInfo = {
* Many RN development tools rely on the development server (packager) running
* @return URL to packager with trailing slash
*/
function getDevServer(): DevServerInfo {
export default function getDevServer(): DevServerInfo {
if (_cachedDevServerURL === undefined) {
const scriptUrl = NativeSourceCode.getConstants().scriptURL;
const match = scriptUrl.match(/^https?:\/\/.*?\//);
@@ -39,5 +39,3 @@ function getDevServer(): DevServerInfo {
bundleLoadedFromServer: _cachedDevServerURL !== null,
};
}
module.exports = getDevServer;
@@ -103,7 +103,9 @@ function buildUrlForBundle(bundlePathAndQuery: string) {
);
}
module.exports = function (bundlePathAndQuery: string): Promise<void> {
export default function loadBundleFromServer(
bundlePathAndQuery: string,
): Promise<void> {
const requestUrl = buildUrlForBundle(bundlePathAndQuery);
let loadPromise = cachedPromisesByUrl.get(requestUrl);
@@ -149,4 +151,4 @@ module.exports = function (bundlePathAndQuery: string): Promise<void> {
cachedPromisesByUrl.set(requestUrl, loadPromise);
return loadPromise;
};
}
@@ -10,9 +10,9 @@
'use strict';
const getDevServer = require('./getDevServer');
const getDevServer = require('./getDevServer').default;
function openFileInEditor(file: string, lineNumber: number) {
export default function openFileInEditor(file: string, lineNumber: number) {
// $FlowFixMe[unused-promise]
fetch(getDevServer().url + 'open-stack-frame', {
method: 'POST',
@@ -22,5 +22,3 @@ function openFileInEditor(file: string, lineNumber: number) {
body: JSON.stringify({file, lineNumber}),
});
}
module.exports = openFileInEditor;
@@ -10,14 +10,12 @@
'use strict';
const getDevServer = require('./getDevServer');
const getDevServer = require('./getDevServer').default;
function openURLInBrowser(url: string) {
export default function openURLInBrowser(url: string) {
// $FlowFixMe[unused-promise]
fetch(getDevServer().url + 'open-url', {
method: 'POST',
body: JSON.stringify({url}),
});
}
module.exports = openURLInBrowser;
@@ -13,7 +13,7 @@
import type {StackFrame} from '../NativeExceptionsManager';
import type {HermesParsedStack} from './parseHermesStack';
const parseHermesStack = require('./parseHermesStack');
const parseHermesStack = require('./parseHermesStack').default;
function convertHermesStack(stack: HermesParsedStack): Array<StackFrame> {
const frames: Array<StackFrame> = [];
@@ -38,7 +38,9 @@ function convertHermesStack(stack: HermesParsedStack): Array<StackFrame> {
return frames;
}
function parseErrorStack(errorStack?: string): Array<StackFrame> {
export default function parseErrorStack(
errorStack?: string,
): Array<StackFrame> {
if (errorStack == null) {
return [];
}
@@ -55,5 +57,3 @@ function parseErrorStack(errorStack?: string): Array<StackFrame> {
return parsedStack;
}
module.exports = parseErrorStack;
@@ -119,7 +119,7 @@ function parseLine(line: string): ?HermesStackEntry {
}
}
module.exports = function parseHermesStack(stack: string): HermesParsedStack {
export default function parseHermesStack(stack: string): HermesParsedStack {
const lines = stack.split(/\n/);
let entries: Array<HermesStackEntryFrame | HermesStackEntrySkipped> = [];
let lastMessageLine = -1;
@@ -144,4 +144,4 @@ module.exports = function parseHermesStack(stack: string): HermesParsedStack {
}
const message = lines.slice(0, lastMessageLine + 1).join('\n');
return {message, entries};
};
}
@@ -12,7 +12,7 @@
import type {StackFrame} from '../NativeExceptionsManager';
const getDevServer = require('./getDevServer');
const getDevServer = require('./getDevServer').default;
export type CodeFrame = $ReadOnly<{
content: string,
@@ -29,7 +29,7 @@ export type SymbolicatedStackTrace = $ReadOnly<{
codeFrame: ?CodeFrame,
}>;
async function symbolicateStackTrace(
export default async function symbolicateStackTrace(
stack: Array<StackFrame>,
extraData?: mixed,
): Promise<SymbolicatedStackTrace> {
@@ -46,5 +46,3 @@ async function symbolicateStackTrace(
});
return await response.json();
}
module.exports = symbolicateStackTrace;
+6 -4
View File
@@ -13,7 +13,7 @@
import type {ExtendedError} from './ExtendedError';
import type {ExceptionData} from './NativeExceptionsManager';
class SyntheticError extends Error {
export class SyntheticError extends Error {
name: string = '';
}
@@ -62,7 +62,7 @@ function reportException(
isFatal: boolean,
reportToConsole: boolean, // only true when coming from handleException; the error has not yet been logged
) {
const parseErrorStack = require('./Devtools/parseErrorStack');
const parseErrorStack = require('./Devtools/parseErrorStack').default;
const stack = parseErrorStack(e?.stack);
const currentExceptionID = ++exceptionID;
const originalMessage = e.message || '';
@@ -273,10 +273,12 @@ function installConsoleErrorReporter() {
}
}
module.exports = {
const ExceptionsManager = {
decoratedExtraDataKey,
handleException,
installConsoleErrorReporter,
SyntheticError,
SyntheticError, // <- for backwards compatibility
unstable_setExceptionDecorator,
};
export default ExceptionsManager;
@@ -10,7 +10,7 @@
import type {ExtendedError} from './ExtendedError';
import {SyntheticError, handleException} from './ExceptionsManager';
import ExceptionsManager, {SyntheticError} from './ExceptionsManager';
export type CapturedError = {
+componentStack: string,
@@ -52,7 +52,7 @@ const ReactFiberErrorDialog = {
// Ignored.
}
handleException(error, false);
ExceptionsManager.handleException(error, false);
// Return false here to prevent ReactFiberErrorLogger default behavior of
// logging error details to console.error. Calls to console.error are
@@ -21,7 +21,7 @@ const ReactNativeVersion = require('./ReactNativeVersion');
* implementations for other platforms (ex: Windows) may override this module
* and rely on its existence as a separate module.
*/
const checkVersions = function checkVersions(): void {
export function checkVersions(): void {
const nativeVersion = Platform.constants.reactNativeVersion;
if (
ReactNativeVersion.version.major !== nativeVersion.major ||
@@ -37,7 +37,7 @@ const checkVersions = function checkVersions(): void {
'`watchman watch-del-all && npx react-native start --reset-cache`.',
);
}
};
}
function _formatVersion(
version: (typeof Platform)['constants']['reactNativeVersion'],
@@ -48,5 +48,3 @@ function _formatVersion(
(version.prerelease != undefined ? `-${version.prerelease}` : '')
);
}
module.exports = {checkVersions};
+1 -1
View File
@@ -484,4 +484,4 @@ BatchedBridge.setReactNativeMicrotasksCallback(
JSTimers.callReactNativeMicrotasks,
);
module.exports = ExportedJSTimers;
export default ExportedJSTimers;
@@ -24,7 +24,7 @@ jest
}))
.unmock('../JSTimers');
const JSTimers = require('../JSTimers');
const JSTimers = require('../JSTimers').default;
describe('JSTimers', function () {
beforeEach(function () {
@@ -21,7 +21,7 @@ const clearedImmediates: Set<number> = new Set();
* @param {function} func Callback to be invoked before the end of the
* current JavaScript execution loop.
*/
function setImmediate(callback: Function, ...args: any): number {
export function setImmediate(callback: Function, ...args: any): number {
if (arguments.length < 1) {
throw new TypeError(
'setImmediate must be called with at least one argument (a function to call)',
@@ -56,13 +56,6 @@ function setImmediate(callback: Function, ...args: any): number {
/**
* @param {number} immediateID The ID of the immediate to be clearred.
*/
function clearImmediate(immediateID: number) {
export function clearImmediate(immediateID: number) {
clearedImmediates.add(immediateID);
}
const immediateShim = {
setImmediate: setImmediate,
clearImmediate: clearImmediate,
};
module.exports = immediateShim;
@@ -10,7 +10,7 @@
'use strict';
const ExceptionsManager = require('../ExceptionsManager');
const ExceptionsManager = require('../ExceptionsManager').default;
const NativeExceptionsManager = require('../NativeExceptionsManager').default;
const ReactFiberErrorDialog = require('../ReactFiberErrorDialog').default;
const fs = require('fs');
@@ -71,13 +71,12 @@ function runExceptionsManagerTests() {
};
});
// Make symbolication a no-op.
jest.mock(
'../Devtools/symbolicateStackTrace',
() =>
async function symbolicateStackTrace(stack) {
return {stack};
},
);
jest.mock('../Devtools/symbolicateStackTrace', () => ({
__esModule: true,
default: async function symbolicateStackTrace(stack) {
return {stack};
},
}));
jest.spyOn(console, 'error').mockReturnValue(undefined);
nativeReportException = NativeExceptionsManager.reportException;
});
+1 -1
View File
@@ -14,7 +14,7 @@ import registerModule from './registerCallableModule';
registerModule('Systrace', () => require('../Performance/Systrace'));
if (!(global.RN$Bridgeless === true)) {
registerModule('JSTimers', () => require('./Timers/JSTimers'));
registerModule('JSTimers', () => require('./Timers/JSTimers').default);
}
registerModule('RCTLog', () => require('../Utilities/RCTLog'));
registerModule(
@@ -75,7 +75,6 @@ if (__DEV__) {
require('./setUpReactRefresh');
global[
`${global.__METRO_GLOBAL_PREFIX__ ?? ''}__loadBundleAsync`
] = require('./Devtools/loadBundleFromServer');
global[`${global.__METRO_GLOBAL_PREFIX__ ?? ''}__loadBundleAsync`] =
require('./Devtools/loadBundleFromServer').default;
}
+1 -1
View File
@@ -15,7 +15,7 @@ if (global.RN$useAlwaysAvailableJSErrorHandling !== true) {
* Sets up the console and exception handling (redbox) for React Native.
* You can use this module directly, or just require InitializeCore.
*/
const ExceptionsManager = require('./ExceptionsManager');
const ExceptionsManager = require('./ExceptionsManager').default;
ExceptionsManager.installConsoleErrorReporter();
// Set up error handler
+1 -1
View File
@@ -131,7 +131,7 @@ if (__DEV__) {
// TODO(t12832058) This check is broken
if (!window.document) {
const AppState = require('../AppState/AppState').default;
const getDevServer = require('./Devtools/getDevServer');
const getDevServer = require('./Devtools/getDevServer').default;
// Don't steal the DevTools from currently active app.
// Note: if you add any AppState subscriptions to this file,
+3 -3
View File
@@ -49,7 +49,7 @@ if (global.RN$Bridgeless !== true) {
| 'setInterval'
| 'setTimeout',
) => {
polyfillGlobal(name, () => require('./Timers/JSTimers')[name]);
polyfillGlobal(name, () => require('./Timers/JSTimers').default[name]);
};
defineLazyTimer('setTimeout');
defineLazyTimer('clearTimeout');
@@ -115,11 +115,11 @@ if (isEventLoopEnabled) {
if (global.RN$Bridgeless !== true) {
polyfillGlobal(
'setImmediate',
() => require('./Timers/JSTimers').queueReactNativeMicrotask,
() => require('./Timers/JSTimers').default.queueReactNativeMicrotask,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/JSTimers').clearReactNativeMicrotask,
() => require('./Timers/JSTimers').default.clearReactNativeMicrotask,
);
}
}
+1 -1
View File
@@ -105,7 +105,7 @@ export function reportLogBoxError(
error: ExtendedError,
componentStack?: string,
): void {
const ExceptionsManager = require('../../Core/ExceptionsManager');
const ExceptionsManager = require('../../Core/ExceptionsManager').default;
error.message = `${LOGBOX_ERROR_MESSAGE}\n\n${error.message}`;
if (componentStack != null) {
@@ -20,7 +20,8 @@ jest.mock('../../../Core/Devtools/parseErrorStack', () => {
jest.mock('../../../Core/ExceptionsManager');
const ExceptionsManager: any = require('../../../Core/ExceptionsManager');
const ExceptionsManager: any =
require('../../../Core/ExceptionsManager').default;
const LogBoxData = require('../LogBoxData');
const registry = () => {
@@ -21,7 +21,7 @@ jest.mock('../../../Core/Devtools/symbolicateStackTrace');
const symbolicateStackTrace: JestMockFn<
$ReadOnlyArray<Array<StackFrame>>,
Promise<SymbolicatedStackTrace>,
> = (require('../../../Core/Devtools/symbolicateStackTrace'): any);
> = (require('../../../Core/Devtools/symbolicateStackTrace').default: any);
const createStack = (methodNames: Array<string>) =>
methodNames.map((methodName): StackFrame => ({
@@ -16,7 +16,7 @@ import {
} from './__fixtures__/ReactWarningFixtures';
import * as React from 'react';
const ExceptionsManager = require('../../Core/ExceptionsManager.js');
const ExceptionsManager = require('../../Core/ExceptionsManager.js').default;
const LogBoxData = require('../Data/LogBoxData');
const TestRenderer = require('react-test-renderer');
@@ -11,7 +11,7 @@
'use strict';
const ExceptionsManager = require('../../Core/ExceptionsManager.js');
const ExceptionsManager = require('../../Core/ExceptionsManager.js').default;
const LogBoxData = require('../Data/LogBoxData');
const LogBox = require('../LogBox').default;
@@ -41,7 +41,7 @@ module.exports = {
return require('../BatchedBridge/BatchedBridge').default;
},
get ExceptionsManager(): ExceptionsManager {
return require('../Core/ExceptionsManager');
return require('../Core/ExceptionsManager').default;
},
get Platform(): Platform {
return require('../Utilities/Platform');
@@ -4258,31 +4258,34 @@ exports[`public API should not change unintentionally Libraries/Core/Devtools/ge
bundleLoadedFromServer: boolean,
...
};
declare function getDevServer(): DevServerInfo;
declare module.exports: getDevServer;
declare export default function getDevServer(): DevServerInfo;
"
`;
exports[`public API should not change unintentionally Libraries/Core/Devtools/loadBundleFromServer.js 1`] = `
"declare module.exports: (bundlePathAndQuery: string) => Promise<void>;
"declare export default function loadBundleFromServer(
bundlePathAndQuery: string
): Promise<void>;
"
`;
exports[`public API should not change unintentionally Libraries/Core/Devtools/openFileInEditor.js 1`] = `
"declare function openFileInEditor(file: string, lineNumber: number): void;
declare module.exports: openFileInEditor;
"declare export default function openFileInEditor(
file: string,
lineNumber: number
): void;
"
`;
exports[`public API should not change unintentionally Libraries/Core/Devtools/openURLInBrowser.js 1`] = `
"declare function openURLInBrowser(url: string): void;
declare module.exports: openURLInBrowser;
"declare export default function openURLInBrowser(url: string): void;
"
`;
exports[`public API should not change unintentionally Libraries/Core/Devtools/parseErrorStack.js 1`] = `
"declare function parseErrorStack(errorStack?: string): Array<StackFrame>;
declare module.exports: parseErrorStack;
"declare export default function parseErrorStack(
errorStack?: string
): Array<StackFrame>;
"
`;
@@ -4327,7 +4330,9 @@ export type HermesParsedStack = $ReadOnly<{
message: string,
entries: $ReadOnlyArray<HermesStackEntry>,
}>;
declare module.exports: (stack: string) => HermesParsedStack;
declare export default function parseHermesStack(
stack: string
): HermesParsedStack;
"
`;
@@ -4345,16 +4350,15 @@ export type SymbolicatedStackTrace = $ReadOnly<{
stack: Array<StackFrame>,
codeFrame: ?CodeFrame,
}>;
declare function symbolicateStackTrace(
declare export default function symbolicateStackTrace(
stack: Array<StackFrame>,
extraData?: mixed
): Promise<SymbolicatedStackTrace>;
declare module.exports: symbolicateStackTrace;
"
`;
exports[`public API should not change unintentionally Libraries/Core/ExceptionsManager.js 1`] = `
"declare class SyntheticError extends Error {
"declare export class SyntheticError extends Error {
name: string;
}
type ExceptionDecorator = (ExceptionData) => ExceptionData;
@@ -4364,13 +4368,14 @@ declare function unstable_setExceptionDecorator(
): void;
declare function handleException(e: mixed, isFatal: boolean): void;
declare function installConsoleErrorReporter(): void;
declare module.exports: {
declare const ExceptionsManager: {
decoratedExtraDataKey: decoratedExtraDataKey,
handleException: handleException,
installConsoleErrorReporter: installConsoleErrorReporter,
SyntheticError: SyntheticError,
unstable_setExceptionDecorator: unstable_setExceptionDecorator,
};
declare export default typeof ExceptionsManager;
"
`;
@@ -4439,8 +4444,7 @@ exports[`public API should not change unintentionally Libraries/Core/ReactNative
`;
exports[`public API should not change unintentionally Libraries/Core/ReactNativeVersionCheck.js 1`] = `
"declare const checkVersions: () => void;
declare module.exports: { checkVersions: checkVersions };
"declare export function checkVersions(): void;
"
`;
@@ -4473,7 +4477,7 @@ declare let ExportedJSTimers: {
setInterval: (func: any, duration: number, ...args: any) => number,
setTimeout: (func: any, duration: number, ...args: any) => number,
};
declare module.exports: ExportedJSTimers;
declare export default typeof ExportedJSTimers;
"
`;
@@ -4484,13 +4488,8 @@ declare export default typeof NativeTiming;
`;
exports[`public API should not change unintentionally Libraries/Core/Timers/immediateShim.js 1`] = `
"declare function setImmediate(callback: Function, ...args: any): number;
declare function clearImmediate(immediateID: number): void;
declare const immediateShim: {
setImmediate: setImmediate,
clearImmediate: clearImmediate,
};
declare module.exports: immediateShim;
"declare export function setImmediate(callback: Function, ...args: any): number;
declare export function clearImmediate(immediateID: number): void;
"
`;
@@ -10,9 +10,8 @@
import type {ExtendedError} from '../../../../Libraries/Core/ExtendedError';
import {
import ExceptionsManager, {
SyntheticError,
handleException,
} from '../../../../Libraries/Core/ExceptionsManager';
type ErrorInfo = {
@@ -60,14 +59,14 @@ export function onUncaughtError(errorValue: mixed, errorInfo: ErrorInfo): void {
const error = getExtendedError(errorValue, errorInfo);
// Uncaught errors are fatal.
handleException(error, true);
ExceptionsManager.handleException(error, true);
}
export function onCaughtError(errorValue: mixed, errorInfo: ErrorInfo): void {
const error = getExtendedError(errorValue, errorInfo);
// Caught errors are not fatal.
handleException(error, false);
ExceptionsManager.handleException(error, false);
}
export function onRecoverableError(