UNPKG

3.31 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 * @flow strict
9 * @polyfill
10 */
11
12let _inGuard = 0;
13
14type ErrorHandler = (error: mixed, isFatal: boolean) => void;
15type Fn<Args, Return> = (...Args) => Return;
16
17/**
18 * This is the error handler that is called when we encounter an exception
19 * when loading a module. This will report any errors encountered before
20 * ExceptionsManager is configured.
21 */
22let _globalHandler: ErrorHandler = function onError(
23 e: mixed,
24 isFatal: boolean,
25) {
26 throw e;
27};
28
29/**
30 * The particular require runtime that we are using looks for a global
31 * `ErrorUtils` object and if it exists, then it requires modules with the
32 * error handler specified via ErrorUtils.setGlobalHandler by calling the
33 * require function with applyWithGuard. Since the require module is loaded
34 * before any of the modules, this ErrorUtils must be defined (and the handler
35 * set) globally before requiring anything.
36 */
37const ErrorUtils = {
38 setGlobalHandler(fun: ErrorHandler): void {
39 _globalHandler = fun;
40 },
41 getGlobalHandler(): ErrorHandler {
42 return _globalHandler;
43 },
44 reportError(error: mixed): void {
45 _globalHandler && _globalHandler(error, false);
46 },
47 reportFatalError(error: mixed): void {
48 // NOTE: This has an untyped call site in Metro.
49 _globalHandler && _globalHandler(error, true);
50 },
51 applyWithGuard<TArgs: $ReadOnlyArray<mixed>, TOut>(
52 fun: Fn<TArgs, TOut>,
53 context?: ?mixed,
54 args?: ?TArgs,
55 // Unused, but some code synced from www sets it to null.
56 unused_onError?: null,
57 // Some callers pass a name here, which we ignore.
58 unused_name?: ?string,
59 ): ?TOut {
60 try {
61 _inGuard++;
62 // $FlowFixMe: TODO T48204745 (1) apply(context, null) is fine. (2) array -> rest array should work
63 return fun.apply(context, args);
64 } catch (e) {
65 ErrorUtils.reportError(e);
66 } finally {
67 _inGuard--;
68 }
69 return null;
70 },
71 applyWithGuardIfNeeded<TArgs: $ReadOnlyArray<mixed>, TOut>(
72 fun: Fn<TArgs, TOut>,
73 context?: ?mixed,
74 args?: ?TArgs,
75 ): ?TOut {
76 if (ErrorUtils.inGuard()) {
77 // $FlowFixMe: TODO T48204745 (1) apply(context, null) is fine. (2) array -> rest array should work
78 return fun.apply(context, args);
79 } else {
80 ErrorUtils.applyWithGuard(fun, context, args);
81 }
82 return null;
83 },
84 inGuard(): boolean {
85 return !!_inGuard;
86 },
87 guard<TArgs: $ReadOnlyArray<mixed>, TOut>(
88 fun: Fn<TArgs, TOut>,
89 name?: ?string,
90 context?: ?mixed,
91 ): ?(...TArgs) => ?TOut {
92 // TODO: (moti) T48204753 Make sure this warning is never hit and remove it - types
93 // should be sufficient.
94 if (typeof fun !== 'function') {
95 console.warn('A function must be passed to ErrorUtils.guard, got ', fun);
96 return null;
97 }
98 const guardName = name ?? fun.name ?? '<generated guard>';
99 function guarded(...args: TArgs): ?TOut {
100 return ErrorUtils.applyWithGuard(
101 fun,
102 context ?? this,
103 args,
104 null,
105 guardName,
106 );
107 }
108
109 return guarded;
110 },
111};
112
113global.ErrorUtils = ErrorUtils;
114
115export type ErrorUtilsT = typeof ErrorUtils;