@react-navigation/core 8.0.0-alpha.30 → 8.0.0-alpha.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/lib/module/BaseNavigationContainer.js +132 -82
  2. package/lib/module/BaseNavigationContainer.js.map +1 -1
  3. package/lib/module/DataLoading.js +3 -1
  4. package/lib/module/DataLoading.js.map +1 -1
  5. package/lib/module/NavigationBuilderContext.js +2 -1
  6. package/lib/module/NavigationBuilderContext.js.map +1 -1
  7. package/lib/module/NavigationIndependentTree.js +21 -11
  8. package/lib/module/NavigationIndependentTree.js.map +1 -1
  9. package/lib/module/NavigationProvider.js +10 -1
  10. package/lib/module/NavigationProvider.js.map +1 -1
  11. package/lib/module/NavigationRootContext.js +8 -0
  12. package/lib/module/NavigationRootContext.js.map +1 -0
  13. package/lib/module/NavigationStateContext.js +3 -0
  14. package/lib/module/NavigationStateContext.js.map +1 -1
  15. package/lib/module/SceneView.js +3 -1
  16. package/lib/module/SceneView.js.map +1 -1
  17. package/lib/module/StaticNavigation.js +54 -19
  18. package/lib/module/StaticNavigation.js.map +1 -1
  19. package/lib/module/createNavigationContainerRef.js +1 -1
  20. package/lib/module/createNavigationContainerRef.js.map +1 -1
  21. package/lib/module/findFocusedRoute.js.map +1 -1
  22. package/lib/module/getActionFromState.js.map +1 -1
  23. package/lib/module/getStateFromPath.js +15 -16
  24. package/lib/module/getStateFromPath.js.map +1 -1
  25. package/lib/module/getStateFromRouteParams.js +0 -1
  26. package/lib/module/getStateFromRouteParams.js.map +1 -1
  27. package/lib/module/index.js +1 -1
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/internal.js +2 -0
  30. package/lib/module/internal.js.map +1 -0
  31. package/lib/module/types.js +0 -1
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/useDescriptors.js +6 -4
  34. package/lib/module/useDescriptors.js.map +1 -1
  35. package/lib/module/useKeyedChildListeners.js +1 -0
  36. package/lib/module/useKeyedChildListeners.js.map +1 -1
  37. package/lib/module/useNavigation.js +2 -2
  38. package/lib/module/useNavigation.js.map +1 -1
  39. package/lib/module/useNavigationBuilder.js +14 -4
  40. package/lib/module/useNavigationBuilder.js.map +1 -1
  41. package/lib/module/useNavigationCache.js +23 -31
  42. package/lib/module/useNavigationCache.js.map +1 -1
  43. package/lib/module/useNavigationHelpers.js +18 -37
  44. package/lib/module/useNavigationHelpers.js.map +1 -1
  45. package/lib/module/useNavigationState.js +85 -33
  46. package/lib/module/useNavigationState.js.map +1 -1
  47. package/lib/module/useOnGetNavigation.js +26 -0
  48. package/lib/module/useOnGetNavigation.js.map +1 -0
  49. package/lib/module/useSyncState.js +25 -6
  50. package/lib/module/useSyncState.js.map +1 -1
  51. package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
  52. package/lib/typescript/src/DataLoading.d.ts.map +1 -1
  53. package/lib/typescript/src/NavigationBuilderContext.d.ts +4 -1
  54. package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
  55. package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
  56. package/lib/typescript/src/NavigationProvider.d.ts +9 -5
  57. package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
  58. package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
  59. package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
  60. package/lib/typescript/src/NavigationStateContext.d.ts +1 -0
  61. package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
  62. package/lib/typescript/src/SceneView.d.ts +2 -1
  63. package/lib/typescript/src/SceneView.d.ts.map +1 -1
  64. package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
  65. package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
  66. package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
  67. package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
  68. package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
  69. package/lib/typescript/src/getStateFromPath.d.ts +1 -4
  70. package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
  71. package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -1
  72. package/lib/typescript/src/index.d.ts +1 -1
  73. package/lib/typescript/src/index.d.ts.map +1 -1
  74. package/lib/typescript/src/internal.d.ts +3 -0
  75. package/lib/typescript/src/internal.d.ts.map +1 -0
  76. package/lib/typescript/src/types.d.ts +3 -6
  77. package/lib/typescript/src/types.d.ts.map +1 -1
  78. package/lib/typescript/src/useDescriptors.d.ts +2 -1
  79. package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
  80. package/lib/typescript/src/useKeyedChildListeners.d.ts +1 -0
  81. package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
  82. package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
  83. package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
  84. package/lib/typescript/src/useNavigationHelpers.d.ts +1 -2
  85. package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
  86. package/lib/typescript/src/useNavigationState.d.ts +7 -2
  87. package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
  88. package/lib/typescript/src/useOnGetNavigation.d.ts +12 -0
  89. package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
  90. package/lib/typescript/src/useSyncState.d.ts +1 -0
  91. package/lib/typescript/src/useSyncState.d.ts.map +1 -1
  92. package/package.json +11 -5
  93. package/src/BaseNavigationContainer.tsx +194 -97
  94. package/src/DataLoading.tsx +4 -1
  95. package/src/NavigationBuilderContext.tsx +10 -1
  96. package/src/NavigationIndependentTree.tsx +27 -16
  97. package/src/NavigationProvider.tsx +13 -6
  98. package/src/NavigationRootContext.tsx +11 -0
  99. package/src/NavigationStateContext.tsx +4 -0
  100. package/src/SceneView.tsx +4 -0
  101. package/src/StaticNavigation.tsx +77 -19
  102. package/src/createNavigationContainerRef.tsx +0 -2
  103. package/src/findFocusedRoute.tsx +7 -12
  104. package/src/getActionFromState.tsx +2 -1
  105. package/src/getStateFromPath.tsx +31 -43
  106. package/src/getStateFromRouteParams.tsx +0 -1
  107. package/src/index.tsx +1 -0
  108. package/src/internal.tsx +2 -0
  109. package/src/types.tsx +3 -7
  110. package/src/useDescriptors.tsx +6 -3
  111. package/src/useKeyedChildListeners.tsx +1 -0
  112. package/src/useNavigation.tsx +2 -2
  113. package/src/useNavigationBuilder.tsx +14 -4
  114. package/src/useNavigationCache.tsx +24 -33
  115. package/src/useNavigationHelpers.tsx +19 -38
  116. package/src/useNavigationState.tsx +104 -31
  117. package/src/useOnGetNavigation.tsx +29 -0
  118. package/src/useSyncState.tsx +27 -6
  119. package/lib/module/checkSerializable.js +0 -51
  120. package/lib/module/checkSerializable.js.map +0 -1
  121. package/lib/typescript/src/checkSerializable.d.ts +0 -14
  122. package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
  123. package/src/checkSerializable.tsx +0 -90
@@ -7,6 +7,7 @@ import {
7
7
  } from '@react-navigation/routers';
8
8
  import * as React from 'react';
9
9
 
10
+ import { NavigationBuilderContext } from './NavigationBuilderContext';
10
11
  import { NavigationContext } from './NavigationProvider';
11
12
  import { type NavigationHelpers, PrivateValueStore } from './types';
12
13
  import type { NavigationEventEmitter } from './useEventEmitter';
@@ -19,7 +20,6 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
19
20
  onAction: (action: NavigationAction) => boolean;
20
21
  onUnhandledAction: (action: NavigationAction) => void;
21
22
  getState: () => State;
22
- state: State;
23
23
  emitter: NavigationEventEmitter<any>;
24
24
  router: Router<State, Action>;
25
25
  };
@@ -37,38 +37,23 @@ export function useNavigationHelpers<
37
37
  onAction,
38
38
  onUnhandledAction,
39
39
  getState,
40
- state,
41
40
  emitter,
42
41
  router,
43
42
  }: Options<State, Action>) {
44
43
  const parentNavigationHelpers = React.use(NavigationContext);
45
-
46
- // In some cases (e.g. route names change), internal state might have changed
47
- // But it hasn't been committed yet, so hasn't propagated to any listeners
48
- // During this time, we need to return the internal state in `getState`
49
- // Otherwise it can return an inconsistent state during render in children
50
- // This may affect hooks like `useNavigationState` that need to read the state during render
51
- // To avoid this, we use a ref for render phase, and immediately clear it on commit
52
- // The ref won't be cleared if the render is discarded, e.g. when interrupted
53
- // So we also track the stored state the render was based on
54
- // Then ignore the ref once the stored state changes due to another dispatch
55
- const stateRef = React.useRef<{ state: State; base: State } | null>(null);
56
-
57
- stateRef.current = { state, base: getState() };
58
-
59
- React.useInsertionEffect(() => {
60
- stateRef.current = null;
61
- });
44
+ const { withStackTrace } = React.use(NavigationBuilderContext);
62
45
 
63
46
  return React.useMemo(() => {
64
47
  const dispatch = (op: Action | ((state: State) => Action)) => {
65
- const action = typeof op === 'function' ? op(getState()) : op;
48
+ withStackTrace(dispatch, () => {
49
+ const action = typeof op === 'function' ? op(getState()) : op;
66
50
 
67
- const handled = onAction(action);
51
+ const handled = onAction(action);
68
52
 
69
- if (!handled) {
70
- onUnhandledAction?.(action);
71
- }
53
+ if (!handled) {
54
+ onUnhandledAction?.(action);
55
+ }
56
+ });
72
57
  };
73
58
 
74
59
  const actions = {
@@ -77,8 +62,15 @@ export function useNavigationHelpers<
77
62
  };
78
63
 
79
64
  const helpers = Object.keys(actions).reduce((acc, name) => {
65
+ const helper = (...args: any) =>
66
+ withStackTrace(helper, () =>
67
+ // @ts-expect-error: name is a valid key, but TypeScript is dumb
68
+ dispatch(actions[name](...args))
69
+ );
70
+
80
71
  // @ts-expect-error: name is a valid key, but TypeScript is dumb
81
- acc[name] = (...args: any) => dispatch(actions[name](...args));
72
+ acc[name] = helper;
73
+
82
74
  return acc;
83
75
  }, {} as ActionHelpers);
84
76
 
@@ -103,18 +95,7 @@ export function useNavigationHelpers<
103
95
  false
104
96
  );
105
97
  },
106
- getState: (): State => {
107
- const current = getState();
108
- const pending = stateRef.current;
109
-
110
- // FIXME: Workaround for when the state is read during render
111
- // Apart from subscriptions, `getState` should never be called during render
112
- if (pending != null && pending.base === current) {
113
- return pending.state;
114
- }
115
-
116
- return current;
117
- },
98
+ getState,
118
99
  } as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
119
100
 
120
101
  return navigationHelpers;
@@ -125,6 +106,6 @@ export function useNavigationHelpers<
125
106
  getState,
126
107
  onAction,
127
108
  onUnhandledAction,
128
- stateRef,
109
+ withStackTrace,
129
110
  ]);
130
111
  }
@@ -1,12 +1,19 @@
1
1
  import type { NavigationState, ParamListBase } from '@react-navigation/routers';
2
2
  import * as React from 'react';
3
- import useLatestCallback from 'use-latest-callback';
4
3
 
5
4
  import type { NavigationListForNested, RootNavigator } from './types';
6
5
 
6
+ type NavigationStateEvent = 'update' | 'commit';
7
+
7
8
  type NavigationStateListener = {
8
9
  getState: () => NavigationState<ParamListBase>;
9
- subscribe: (callback: () => void) => () => void;
10
+ getSnapshot: () => NavigationState<ParamListBase>;
11
+ subscribe: (callback: (event: NavigationStateEvent) => void) => () => void;
12
+ };
13
+
14
+ type NavigationStateEntry = {
15
+ listener: NavigationStateListener;
16
+ state: NavigationState<ParamListBase>;
10
17
  };
11
18
 
12
19
  type NavigationStateForNested<
@@ -74,68 +81,134 @@ export function useNavigationState(...args: unknown[]): unknown {
74
81
  }
75
82
  }
76
83
 
77
- const { getState, subscribe } = listener;
84
+ const { getState, getSnapshot, subscribe } = listener;
85
+
86
+ // The store can contain state from a transition that hasn't committed yet.
87
+ // Reading it during render can show state that doesn't match the navigator in that render.
88
+ // The reducer lets React process state in the same render lane as the navigator.
89
+ const [entry, dispatch] = React.useReducer(
90
+ (previous: NavigationStateEntry, event: NavigationStateEvent) => {
91
+ // Navigation state can change between the dispatch and the reducer running.
92
+ // Reading here ensures the processed event uses the state for that render.
93
+ const state = event === 'update' ? getState() : getSnapshot();
94
+
95
+ if (
96
+ previous.listener === listener &&
97
+ (previous.state === state ||
98
+ (event === 'update' &&
99
+ Object.is(select(previous.state), select(state))))
100
+ ) {
101
+ return previous;
102
+ }
78
103
 
79
- const [, forceUpdate] = React.useReducer((count: number) => count + 1, 0);
104
+ return { listener, state };
105
+ },
106
+ undefined,
107
+ () => ({ listener, state: getState() })
108
+ );
80
109
 
81
- const selected = select(getState());
110
+ let state = entry.state;
82
111
 
83
- const selectionRef = React.useRef({ select, selected });
112
+ const committedRef = React.useRef<{
113
+ entry: NavigationStateEntry | null;
114
+ state: NavigationState<ParamListBase>;
115
+ select: (state: NavigationState<ParamListBase>) => unknown;
116
+ }>({ entry: null, state, select });
84
117
 
85
- React.useLayoutEffect(() => {
86
- selectionRef.current = { select, selected };
118
+ React.useInsertionEffect(() => {
119
+ committedRef.current = { entry, state, select };
87
120
  });
88
121
 
89
- React.useEffect(() => {
90
- const checkForUpdates = () => {
91
- const selection = selectionRef.current;
122
+ const snapshot = getSnapshot();
123
+
124
+ const behind =
125
+ state !== snapshot &&
126
+ // A different listener means the state belongs to another navigator.
127
+ // This can happen when the passed route name changes.
128
+ (entry.listener !== listener ||
129
+ // An entry that advanced past the last commit is at least as new as the snapshot.
130
+ // An entry that didn't advance while the committed state changed is older.
131
+ entry === committedRef.current.entry);
92
132
 
93
- if (!Object.is(selection.selected, selection.select(getState()))) {
94
- forceUpdate();
133
+ if (behind) {
134
+ state = snapshot;
135
+ dispatch('commit');
136
+ }
137
+
138
+ React.useLayoutEffect(() => {
139
+ const check = (event: NavigationStateEvent) => {
140
+ const { state, select } = committedRef.current;
141
+
142
+ // An 'update' event follows the latest state in the lane the update was made in.
143
+ // A 'commit' event syncs the reducer to the state committed by the navigator.
144
+ const target = event === 'update' ? getState() : getSnapshot();
145
+
146
+ if (state !== target && !Object.is(select(state), select(target))) {
147
+ dispatch(event);
95
148
  }
96
149
  };
97
150
 
98
- const unsubscribe = subscribe(checkForUpdates);
151
+ const unsubscribe = subscribe(check);
99
152
 
100
- // The state may have changed between the render and the subscription
101
- checkForUpdates();
153
+ // The reducer may not match the committed state when the subscription starts.
154
+ // This happens on mount during a transition or an update before subscribing.
155
+ check('commit');
102
156
 
103
157
  return unsubscribe;
104
- }, [getState, subscribe]);
158
+ }, [getState, getSnapshot, subscribe]);
105
159
 
106
- return selected;
160
+ return select(state);
107
161
  }
108
162
 
109
163
  export function NavigationStateListenerProvider({
164
+ isSynced,
110
165
  state,
111
166
  getState,
167
+ subscribe,
112
168
  children,
113
169
  }: {
170
+ isSynced: boolean;
114
171
  state: NavigationState<ParamListBase>;
115
172
  getState: () => NavigationState<ParamListBase>;
173
+ subscribe: (callback: () => void) => () => void;
116
174
  children: React.ReactNode;
117
175
  }) {
118
- const listeners = React.useRef<(() => void)[]>([]);
176
+ const [listeners] = React.useState(
177
+ () => new Set<(event: NavigationStateEvent) => void>()
178
+ );
119
179
 
120
- const subscribe = useLatestCallback((callback: () => void) => {
121
- listeners.current.push(callback);
180
+ React.useLayoutEffect(() => {
181
+ listeners.forEach((listener) => listener('commit'));
182
+ }, [listeners, state]);
122
183
 
123
- return () => {
124
- listeners.current = listeners.current.filter((cb) => cb !== callback);
125
- };
126
- });
184
+ const snapshotRef = React.useRef(state);
127
185
 
128
- // Notify subscribers once the new state has committed
129
- React.useLayoutEffect(() => {
130
- listeners.current.forEach((callback) => callback());
186
+ React.useInsertionEffect(() => {
187
+ snapshotRef.current = state;
131
188
  }, [state]);
132
189
 
190
+ // Route config or nested params can produce new state during render.
191
+ // If the scheduled update hasn't synced that state to the store yet,
192
+ // We need to expose the rendered state so consumers match the navigator.
193
+ // We keep this `undefined` for other scenarios, so the context isn't recreated.
194
+ const nextState = isSynced ? undefined : state;
195
+
133
196
  const context = React.useMemo(
134
197
  () => ({
135
198
  getState,
136
- subscribe,
199
+ getSnapshot: () => nextState ?? snapshotRef.current,
200
+ subscribe: (callback: (event: NavigationStateEvent) => void) => {
201
+ const unsubscribe = subscribe(() => callback('update'));
202
+
203
+ listeners.add(callback);
204
+
205
+ return () => {
206
+ listeners.delete(callback);
207
+ unsubscribe();
208
+ };
209
+ },
137
210
  }),
138
- [getState, subscribe]
211
+ [getState, listeners, nextState, subscribe]
139
212
  );
140
213
 
141
214
  return (
@@ -177,7 +250,7 @@ export function NamedNavigationStateListenerProvider({
177
250
  );
178
251
  }
179
252
 
180
- const NavigationStateListenerContext = React.createContext<
253
+ export const NavigationStateListenerContext = React.createContext<
181
254
  NavigationStateListener | undefined
182
255
  >(undefined);
183
256
 
@@ -0,0 +1,29 @@
1
+ import type { ParamListBase } from '@react-navigation/routers';
2
+ import * as React from 'react';
3
+
4
+ import { NavigationBuilderContext } from './NavigationBuilderContext';
5
+ import { NavigationRouteContext } from './NavigationProvider';
6
+ import type { NavigationHelpers } from './types';
7
+
8
+ type Options = {
9
+ navigation: NavigationHelpers<ParamListBase>;
10
+ };
11
+
12
+ /**
13
+ * Hook which lets the container access the navigation object of the root navigator.
14
+ * It's used for the navigation object returned by `useNavigation` outside a screen.
15
+ */
16
+ export function useOnGetNavigation({ navigation }: Options) {
17
+ const { addKeyedListener } = React.use(NavigationBuilderContext);
18
+ const route = React.use(NavigationRouteContext);
19
+
20
+ React.useInsertionEffect(() => {
21
+ // We only register if this is the root navigator
22
+ // i.e. there is no parent route
23
+ if (route != null) {
24
+ return;
25
+ }
26
+
27
+ return addKeyedListener?.('getNavigation', 'root', () => navigation);
28
+ }, [addKeyedListener, navigation, route]);
29
+ }
@@ -24,13 +24,29 @@ const createStore = <T,>(getInitialState: () => T) => {
24
24
  let isBatching = false;
25
25
  let didUpdate = false;
26
26
 
27
+ const notify = () => {
28
+ let error: { value: unknown } | undefined;
29
+
30
+ listeners.forEach((listener) => {
31
+ try {
32
+ listener();
33
+ } catch (e) {
34
+ error = error ?? { value: e };
35
+ }
36
+ });
37
+
38
+ if (error) {
39
+ throw error.value;
40
+ }
41
+ };
42
+
27
43
  const setState = (newState: T) => {
28
44
  state = deepFreeze(newState);
29
45
 
30
46
  if (isBatching) {
31
47
  didUpdate = true;
32
48
  } else {
33
- listeners.forEach((listener) => listener());
49
+ notify();
34
50
  }
35
51
  };
36
52
 
@@ -44,12 +60,16 @@ const createStore = <T,>(getInitialState: () => T) => {
44
60
 
45
61
  const batchUpdates = (callback: () => void) => {
46
62
  isBatching = true;
47
- callback();
48
- isBatching = false;
49
63
 
50
- if (didUpdate) {
51
- didUpdate = false;
52
- listeners.forEach((listener) => listener());
64
+ try {
65
+ callback();
66
+ } finally {
67
+ isBatching = false;
68
+
69
+ if (didUpdate) {
70
+ didUpdate = false;
71
+ notify();
72
+ }
53
73
  }
54
74
  };
55
75
 
@@ -119,6 +139,7 @@ export function useSyncState<T>(getInitialState: () => T) {
119
139
  state,
120
140
  getState: store.getState,
121
141
  setState: store.setState,
142
+ subscribe: store.subscribe,
122
143
  scheduleUpdate,
123
144
  flushUpdates,
124
145
  } as const;
@@ -1,51 +0,0 @@
1
- "use strict";
2
-
3
- const checkSerializableWithoutCircularReference = (o, seen, location) => {
4
- if (o === undefined || o === null || typeof o === 'boolean' || typeof o === 'number' || typeof o === 'string') {
5
- return undefined;
6
- }
7
- if (Object.prototype.toString.call(o) !== '[object Object]' && !Array.isArray(o)) {
8
- return {
9
- serializable: false,
10
- location: location.slice(),
11
- reason: typeof o === 'function' ? 'Function' : String(o)
12
- };
13
- }
14
- if (seen.has(o)) {
15
- return {
16
- serializable: false,
17
- reason: 'Circular reference',
18
- location: location.slice()
19
- };
20
- }
21
- seen.add(o);
22
- if (Array.isArray(o)) {
23
- for (let i = 0; i < o.length; i++) {
24
- location.push(i);
25
- const childResult = checkSerializableWithoutCircularReference(o[i], seen, location);
26
- location.pop();
27
- if (childResult) {
28
- seen.delete(o);
29
- return childResult;
30
- }
31
- }
32
- } else {
33
- for (const key in o) {
34
- location.push(key);
35
- const childResult = checkSerializableWithoutCircularReference(o[key], seen, location);
36
- location.pop();
37
- if (childResult) {
38
- seen.delete(o);
39
- return childResult;
40
- }
41
- }
42
- }
43
- seen.delete(o);
44
- return undefined;
45
- };
46
- export function checkSerializable(o) {
47
- return checkSerializableWithoutCircularReference(o, new Set(), []) ?? {
48
- serializable: true
49
- };
50
- }
51
- //# sourceMappingURL=checkSerializable.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["checkSerializableWithoutCircularReference","o","seen","location","undefined","Object","prototype","toString","call","Array","isArray","serializable","slice","reason","String","has","add","i","length","push","childResult","pop","delete","key","checkSerializable","Set"],"sourceRoot":"../../src","sources":["checkSerializable.tsx"],"mappings":";;AAUA,MAAMA,yCAAyC,GAAGA,CAChDC,CAAyB,EACzBC,IAAc,EACdC,QAA6B,KACL;EACxB,IACEF,CAAC,KAAKG,SAAS,IACfH,CAAC,KAAK,IAAI,IACV,OAAOA,CAAC,KAAK,SAAS,IACtB,OAAOA,CAAC,KAAK,QAAQ,IACrB,OAAOA,CAAC,KAAK,QAAQ,EACrB;IACA,OAAOG,SAAS;EAClB;EAEA,IACEC,MAAM,CAACC,SAAS,CAACC,QAAQ,CAACC,IAAI,CAACP,CAAC,CAAC,KAAK,iBAAiB,IACvD,CAACQ,KAAK,CAACC,OAAO,CAACT,CAAC,CAAC,EACjB;IACA,OAAO;MACLU,YAAY,EAAE,KAAK;MACnBR,QAAQ,EAAEA,QAAQ,CAACS,KAAK,CAAC,CAAC;MAC1BC,MAAM,EAAE,OAAOZ,CAAC,KAAK,UAAU,GAAG,UAAU,GAAGa,MAAM,CAACb,CAAC;IACzD,CAAC;EACH;EAEA,IAAIC,IAAI,CAACa,GAAG,CAACd,CAAC,CAAC,EAAE;IACf,OAAO;MACLU,YAAY,EAAE,KAAK;MACnBE,MAAM,EAAE,oBAAoB;MAC5BV,QAAQ,EAAEA,QAAQ,CAACS,KAAK,CAAC;IAC3B,CAAC;EACH;EAEAV,IAAI,CAACc,GAAG,CAACf,CAAC,CAAC;EAEX,IAAIQ,KAAK,CAACC,OAAO,CAACT,CAAC,CAAC,EAAE;IACpB,KAAK,IAAIgB,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGhB,CAAC,CAACiB,MAAM,EAAED,CAAC,EAAE,EAAE;MACjCd,QAAQ,CAACgB,IAAI,CAACF,CAAC,CAAC;MAChB,MAAMG,WAAW,GAAGpB,yCAAyC,CAC3DC,CAAC,CAACgB,CAAC,CAAC,EACJf,IAAI,EACJC,QACF,CAAC;MACDA,QAAQ,CAACkB,GAAG,CAAC,CAAC;MAEd,IAAID,WAAW,EAAE;QACflB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;QACd,OAAOmB,WAAW;MACpB;IACF;EACF,CAAC,MAAM;IACL,KAAK,MAAMG,GAAG,IAAItB,CAAC,EAAE;MACnBE,QAAQ,CAACgB,IAAI,CAACI,GAAG,CAAC;MAClB,MAAMH,WAAW,GAAGpB,yCAAyC,CAC3DC,CAAC,CAACsB,GAAG,CAAC,EACNrB,IAAI,EACJC,QACF,CAAC;MACDA,QAAQ,CAACkB,GAAG,CAAC,CAAC;MAEd,IAAID,WAAW,EAAE;QACflB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;QACd,OAAOmB,WAAW;MACpB;IACF;EACF;EAEAlB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;EAEd,OAAOG,SAAS;AAClB,CAAC;AAED,OAAO,SAASoB,iBAAiBA,CAACvB,CAAyB,EAAU;EACnE,OACED,yCAAyC,CAACC,CAAC,EAAE,IAAIwB,GAAG,CAAM,CAAC,EAAE,EAAE,CAAC,IAAI;IAClEd,YAAY,EAAE;EAChB,CAAC;AAEL","ignoreList":[]}
@@ -1,14 +0,0 @@
1
- type Success = {
2
- serializable: true;
3
- };
4
- type Failure = {
5
- serializable: false;
6
- location: (string | number)[];
7
- reason: string;
8
- };
9
- type Result = Success | Failure;
10
- export declare function checkSerializable(o: {
11
- [key: string]: any;
12
- }): Result;
13
- export {};
14
- //# sourceMappingURL=checkSerializable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"checkSerializable.d.ts","sourceRoot":"","sources":["../../../src/checkSerializable.tsx"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,CAAC;AAEtC,KAAK,OAAO,GAAG;IACb,YAAY,EAAE,KAAK,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AA2EhC,wBAAgB,iBAAiB,CAAC,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,MAAM,CAMnE"}
@@ -1,90 +0,0 @@
1
- type Success = { serializable: true };
2
-
3
- type Failure = {
4
- serializable: false;
5
- location: (string | number)[];
6
- reason: string;
7
- };
8
-
9
- type Result = Success | Failure;
10
-
11
- const checkSerializableWithoutCircularReference = (
12
- o: { [key: string]: any },
13
- seen: Set<any>,
14
- location: (string | number)[]
15
- ): Failure | undefined => {
16
- if (
17
- o === undefined ||
18
- o === null ||
19
- typeof o === 'boolean' ||
20
- typeof o === 'number' ||
21
- typeof o === 'string'
22
- ) {
23
- return undefined;
24
- }
25
-
26
- if (
27
- Object.prototype.toString.call(o) !== '[object Object]' &&
28
- !Array.isArray(o)
29
- ) {
30
- return {
31
- serializable: false,
32
- location: location.slice(),
33
- reason: typeof o === 'function' ? 'Function' : String(o),
34
- };
35
- }
36
-
37
- if (seen.has(o)) {
38
- return {
39
- serializable: false,
40
- reason: 'Circular reference',
41
- location: location.slice(),
42
- };
43
- }
44
-
45
- seen.add(o);
46
-
47
- if (Array.isArray(o)) {
48
- for (let i = 0; i < o.length; i++) {
49
- location.push(i);
50
- const childResult = checkSerializableWithoutCircularReference(
51
- o[i],
52
- seen,
53
- location
54
- );
55
- location.pop();
56
-
57
- if (childResult) {
58
- seen.delete(o);
59
- return childResult;
60
- }
61
- }
62
- } else {
63
- for (const key in o) {
64
- location.push(key);
65
- const childResult = checkSerializableWithoutCircularReference(
66
- o[key],
67
- seen,
68
- location
69
- );
70
- location.pop();
71
-
72
- if (childResult) {
73
- seen.delete(o);
74
- return childResult;
75
- }
76
- }
77
- }
78
-
79
- seen.delete(o);
80
-
81
- return undefined;
82
- };
83
-
84
- export function checkSerializable(o: { [key: string]: any }): Result {
85
- return (
86
- checkSerializableWithoutCircularReference(o, new Set<any>(), []) ?? {
87
- serializable: true,
88
- }
89
- );
90
- }