Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Codemod invariant -> throw new Error #22435

Merged
merged 9 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,41 @@ module.exports = {
},

overrides: [
{
// By default, anything error message that appears the packages directory
// must have a corresponding error code. The exceptions are defined
// in the next override entry.
files: ['packages/**/*.js'],
rules: {
'react-internal/prod-error-codes': ERROR,
},
},
{
// These are files where it's OK to have unminified error messages. These
// are environments where bundle size isn't a concern, like tests
// or Node.
files: [
'packages/react-dom/src/test-utils/**/*.js',
'packages/react-devtools-shared/**/*.js',
'packages/react-noop-renderer/**/*.js',
'packages/react-pg/**/*.js',
'packages/react-fs/**/*.js',
'packages/react-refresh/**/*.js',
'packages/react-server-dom-webpack/**/*.js',
'packages/react-test-renderer/**/*.js',
'packages/react-debug-tools/**/*.js',
'packages/react-devtools-extensions/**/*.js',
'packages/react-devtools-scheduling-profiler/**/*.js',
'packages/react-native-renderer/**/*.js',
'packages/eslint-plugin-react-hooks/**/*.js',
'packages/jest-react/**/*.js',
'packages/**/__tests__/*.js',
'packages/**/npm/*.js',
],
rules: {
'react-internal/prod-error-codes': OFF,
},
},
{
// We apply these settings to files that we ship through npm.
// They must be ES5.
Expand Down
11 changes: 6 additions & 5 deletions packages/create-subscription/src/createSubscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/

import * as React from 'react';
import invariant from 'shared/invariant';

type Unsubscribe = () => void;

Expand Down Expand Up @@ -128,10 +127,12 @@ export function createSubscription<Property, Value>(

// Store the unsubscribe method for later (in case the subscribable prop changes).
const unsubscribe = subscribe(source, callback);
invariant(
typeof unsubscribe === 'function',
'A subscription must return an unsubscribe function.',
);

if (typeof unsubscribe !== 'function') {
throw new Error(
'A subscription must return an unsubscribe function.',
);
}

// It's safe to store unsubscribe on the instance because
// We only read or write that property during the "commit" phase.
Expand Down
12 changes: 6 additions & 6 deletions packages/jest-react/src/JestReact.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';

import invariant from 'shared/invariant';
import isArray from 'shared/isArray';

export {act} from './internalAct';
Expand All @@ -31,11 +30,12 @@ function captureAssertion(fn) {
function assertYieldsWereCleared(root) {
const Scheduler = root._Scheduler;
const actualYields = Scheduler.unstable_clearYields();
invariant(
actualYields.length === 0,
'Log of yielded values is not empty. ' +
'Call expect(ReactTestRenderer).unstable_toHaveYielded(...) first.',
);
if (actualYields.length !== 0) {
throw new Error(
'Log of yielded values is not empty. ' +
'Call expect(ReactTestRenderer).unstable_toHaveYielded(...) first.',
);
}
}

export function unstable_toMatchRenderedOutput(root, expectedJSX) {
Expand Down
34 changes: 17 additions & 17 deletions packages/react-art/src/ReactARTHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import Transform from 'art/core/transform';
import Mode from 'art/modes/current';
import invariant from 'shared/invariant';

import {TYPES, EVENT_TYPES, childrenAsString} from './ReactARTInternals';

Expand Down Expand Up @@ -248,8 +247,7 @@ export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMicrotasks';
export function appendInitialChild(parentInstance, child) {
if (typeof child === 'string') {
// Noop for string children of Text (eg <Text>{'foo'}{'bar'}</Text>)
invariant(false, 'Text children should already be flattened.');
return;
throw new Error('Text children should already be flattened.');
}

child.inject(parentInstance);
Expand Down Expand Up @@ -282,7 +280,9 @@ export function createInstance(type, props, internalInstanceHandle) {
break;
}

invariant(instance, 'ReactART does not support the type "%s"', type);
if (!instance) {
throw new Error(`ReactART does not support the type "${type}"`);
}

instance._applyProps(instance, props);

Expand Down Expand Up @@ -367,18 +367,18 @@ export function appendChildToContainer(parentInstance, child) {
}

export function insertBefore(parentInstance, child, beforeChild) {
invariant(
child !== beforeChild,
'ReactART: Can not insert node before itself',
);
if (child === beforeChild) {
throw new Error('ReactART: Can not insert node before itself');
}

child.injectBefore(beforeChild);
}

export function insertInContainerBefore(parentInstance, child, beforeChild) {
invariant(
child !== beforeChild,
'ReactART: Can not insert node before itself',
);
if (child === beforeChild) {
throw new Error('ReactART: Can not insert node before itself');
}

child.injectBefore(beforeChild);
}

Expand Down Expand Up @@ -433,25 +433,25 @@ export function clearContainer(container) {
}

export function getInstanceFromNode(node) {
throw new Error('Not yet implemented.');
throw new Error('Not implemented.');
}

export function isOpaqueHydratingObject(value: mixed): boolean {
throw new Error('Not yet implemented');
throw new Error('Not implemented.');
}

export function makeOpaqueHydratingObject(
attemptToReadValue: () => void,
): OpaqueIDType {
throw new Error('Not yet implemented.');
throw new Error('Not implemented.');
}

export function makeClientId(): OpaqueIDType {
throw new Error('Not yet implemented');
throw new Error('Not implemented.');
}

export function makeClientIdInDEV(warnOnAccessInDEV: () => void): OpaqueIDType {
throw new Error('Not yet implemented');
throw new Error('Not implemented.');
}

export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
Expand Down
2 changes: 2 additions & 0 deletions packages/react-cache/src/ReactCacheOld.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const ReactCurrentDispatcher =
function readContext(Context) {
const dispatcher = ReactCurrentDispatcher.current;
if (dispatcher === null) {
// This wasn't being minified but we're going to retire this package anyway.
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'react-cache: read and preload may only be called from within a ' +
"component's render. They are not supported in event handlers or " +
Expand Down
1 change: 1 addition & 0 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ export function resolveError(
message: string,
stack: string,
): void {
// eslint-disable-next-line react-internal/prod-error-codes
const error = new Error(message);
error.stack = stack;
const chunks = response._chunks;
Expand Down
6 changes: 2 additions & 4 deletions packages/react-client/src/ReactFlightClientHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
* @flow
*/

/* eslint-disable react-internal/invariant-args */

import invariant from 'shared/invariant';
/* eslint-disable react-internal/prod-error-codes */

// We expect that our Rollup, Jest, and Flow configurations
// always shim this module with the corresponding host config
Expand All @@ -19,4 +17,4 @@ import invariant from 'shared/invariant';
// sure that if we *do* accidentally break the configuration,
// the failure isn't silent.

invariant(false, 'This module must be shimmed by a specific renderer.');
throw new Error('This module must be shimmed by a specific renderer.');
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ export type StringDecoder = void;
export const supportsBinaryStreams = false;

export function createStringDecoder(): void {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error('Should never be called');
}

export function readPartialStringChunk(
decoder: StringDecoder,
buffer: Uint8Array,
): string {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error('Should never be called');
}

export function readFinalStringChunk(
decoder: StringDecoder,
buffer: Uint8Array,
): string {
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error('Should never be called');
}
3 changes: 1 addition & 2 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
import {NoMode} from 'react-reconciler/src/ReactTypeOfMode';

import ErrorStackParser from 'error-stack-parser';
import invariant from 'shared/invariant';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
import {
Expand Down Expand Up @@ -107,7 +106,7 @@ function nextHook(): null | Hook {
}

function getCacheForType<T>(resourceType: () => T): T {
invariant(false, 'Not implemented.');
throw new Error('Not implemented.');
}

function readContext<T>(context: ReactContext<T>): T {
Expand Down
9 changes: 4 additions & 5 deletions packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import ReactVersion from 'shared/ReactVersion';
import invariant from 'shared/invariant';
import {
warnUnstableRenderSubtreeIntoContainer,
enableNewReconciler,
Expand Down Expand Up @@ -108,10 +107,10 @@ function createPortal(
container: Container,
key: ?string = null,
): React$Portal {
invariant(
isValidContainer(container),
'Target container is not a DOM element.',
);
if (!isValidContainer(container)) {
throw new Error('Target container is not a DOM element.');
}

// TODO: pass ReactDOM portal implementation as third argument
// $FlowFixMe The Flow type is opaque but there's no way to actually create it.
return createPortalImpl(children, container, null, key);
Expand Down
3 changes: 1 addition & 2 deletions packages/react-dom/src/client/ReactDOMComponentTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {

import {getParentSuspenseInstance} from './ReactDOMHostConfig';

import invariant from 'shared/invariant';
import {enableScopeAPI} from 'shared/ReactFeatureFlags';

const randomKey = Math.random()
Expand Down Expand Up @@ -190,7 +189,7 @@ export function getNodeFromInstance(inst: Fiber): Instance | TextInstance {

// Without this first invariant, passing a non-DOM-component triggers the next
// invariant for a missing parent, which is super confusing.
invariant(false, 'getNodeFromInstance: Invalid argument.');
throw new Error('getNodeFromInstance: Invalid argument.');
}

export function getFiberCurrentPropsFromNode(
Expand Down
26 changes: 13 additions & 13 deletions packages/react-dom/src/client/ReactDOMEventHandle.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
enableScopeAPI,
enableCreateEventHandleAPI,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';

type EventHandleOptions = {|
capture?: boolean,
Expand Down Expand Up @@ -73,8 +72,7 @@ function registerReactDOMEvent(
eventTarget,
);
} else {
invariant(
false,
throw new Error(
'ReactDOM.createEventHandle: setter called on an invalid ' +
'target. Provide a valid EventTarget or an element managed by React.',
);
Expand All @@ -97,11 +95,11 @@ export function createEventHandle(
// Unfortunately, the downside of this invariant is that *removing* a native
// event from the list of known events has now become a breaking change for
// any code relying on the createEventHandle API.
invariant(
allNativeEvents.has(domEventName),
'Cannot call unstable_createEventHandle with "%s", as it is not an event known to React.',
domEventName,
);
if (!allNativeEvents.has(domEventName)) {
throw new Error(
`Cannot call unstable_createEventHandle with "${domEventName}", as it is not an event known to React.`,
);
}

let isCapturePhaseListener = false;
if (options != null) {
Expand All @@ -115,11 +113,13 @@ export function createEventHandle(
target: EventTarget | ReactScopeInstance,
callback: (SyntheticEvent<EventTarget>) => void,
) => {
invariant(
typeof callback === 'function',
'ReactDOM.createEventHandle: setter called with an invalid ' +
'callback. The callback must be a function.',
);
if (typeof callback !== 'function') {
throw new Error(
'ReactDOM.createEventHandle: setter called with an invalid ' +
'callback. The callback must be a function.',
);
}

if (!doesTargetHaveEventHandle(target, eventHandle)) {
addEventHandleToTarget(target, eventHandle);
registerReactDOMEvent(target, domEventName, isCapturePhaseListener);
Expand Down
13 changes: 7 additions & 6 deletions packages/react-dom/src/client/ReactDOMInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

// TODO: direct imports like some-package/src/* are bad. Fix me.
import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
import invariant from 'shared/invariant';

import {setValueForProperty} from './DOMPropertyOperations';
import {getFiberCurrentPropsFromNode} from './ReactDOMComponentTree';
Expand Down Expand Up @@ -383,11 +382,13 @@ function updateNamedCousins(rootNode, props) {
// That's probably okay; we don't support it just as we don't support
// mixing React radio buttons with non-React ones.
const otherProps = getFiberCurrentPropsFromNode(otherNode);
invariant(
otherProps,
'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
'same `name` is not supported.',
);

if (!otherProps) {
throw new Error(
'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
'same `name` is not supported.',
);
}

// We need update the tracked value on the named cousin since the value
// was changed but the input saw no event or value set
Expand Down
Loading