import type {Wakeable, Thenable, ReactDebugInfo} from 'shared/ReactTypes';
import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';
const Uninitialized = -1;
const Pending = 0;
const Resolved = 1;
const Rejected = 2;
type UninitializedPayload<T> = {
_status: -1,
_result: () => Thenable<{default: T, ...}>,
};
type PendingPayload = {
_status: 0,
_result: Wakeable,
};
type ResolvedPayload<T> = {
_status: 1,
_result: {default: T, ...},
};
type RejectedPayload = {
_status: 2,
_result: mixed,
};
type Payload<T> =
| UninitializedPayload<T>
| PendingPayload
| ResolvedPayload<T>
| RejectedPayload;
export type LazyComponent<T, P> = {
$$typeof: symbol | number,
_payload: P,
_init: (payload: P) => T,
_debugInfo?: null | ReactDebugInfo,
};
function lazyInitializer<T>(payload: Payload<T>): T {
if (payload._status === Uninitialized) {
const ctor = payload._result;
const thenable = ctor();
thenable.then(
moduleObject => {
if (
(payload: Payload<T>)._status === Pending ||
payload._status === Uninitialized
) {
const resolved: ResolvedPayload<T> = (payload: any);
resolved._status = Resolved;
resolved._result = moduleObject;
}
},
error => {
if (
(payload: Payload<T>)._status === Pending ||
payload._status === Uninitialized
) {
const rejected: RejectedPayload = (payload: any);
rejected._status = Rejected;
rejected._result = error;
}
},
);
if (payload._status === Uninitialized) {
const pending: PendingPayload = (payload: any);
pending._status = Pending;
pending._result = thenable;
}
}
if (payload._status === Resolved) {
const moduleObject = payload._result;
if (__DEV__) {
if (moduleObject === undefined) {
console.error(
'lazy: Expected the result of a dynamic imp' +
'ort() call. ' +
'Instead received: %s\n\nYour code should look like: \n ' +
'const MyComponent = lazy(() => imp' +
"ort('./MyComponent'))\n\n" +
'Did you accidentally put curly braces around the import?',
moduleObject,
);
}
}
if (__DEV__) {
if (!('default' in moduleObject)) {
console.error(
'lazy: Expected the result of a dynamic imp' +
'ort() call. ' +
'Instead received: %s\n\nYour code should look like: \n ' +
'const MyComponent = lazy(() => imp' +
"ort('./MyComponent'))",
moduleObject,
);
}
}
return moduleObject.default;
} else {
throw payload._result;
}
}
export function lazy<T>(
ctor: () => Thenable<{default: T, ...}>,
): LazyComponent<T, Payload<T>> {
const payload: Payload<T> = {
_status: Uninitialized,
_result: ctor,
};
const lazyType: LazyComponent<T, Payload<T>> = {
$$typeof: REACT_LAZY_TYPE,
_payload: payload,
_init: lazyInitializer,
};
return lazyType;
}