mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
20d9d3aa6a
Summary:
We are working on making the empty object literal `{}` have the type `{}` - i.e. exact empty object - rather than being unsealed.
Some manual fixes, in particular to React Native code, which is used and can be synced to other repos (e.g. WWW).
With these changes, error diff in Xplat is down to ~1990 errors
Note that after I roll out `exact_empty_objects`, I'll codemod all the `{...null}` (the only way to get an exact empty object currently) back to `{}`
Changelog: [Internal]
Reviewed By: SamChou19815
Differential Revision: D36142838
fbshipit-source-id: 054caf370db230f42a4c5f5706c88979ef246537
123 lines
3.7 KiB
JavaScript
123 lines
3.7 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
* @flow strict
|
|
*/
|
|
|
|
import invariant from 'invariant';
|
|
|
|
/**
|
|
* Tries to stringify with JSON.stringify and toString, but catches exceptions
|
|
* (e.g. from circular objects) and always returns a string and never throws.
|
|
*/
|
|
export function createStringifySafeWithLimits(limits: {|
|
|
maxDepth?: number,
|
|
maxStringLimit?: number,
|
|
maxArrayLimit?: number,
|
|
maxObjectKeysLimit?: number,
|
|
|}): mixed => string {
|
|
const {
|
|
maxDepth = Number.POSITIVE_INFINITY,
|
|
maxStringLimit = Number.POSITIVE_INFINITY,
|
|
maxArrayLimit = Number.POSITIVE_INFINITY,
|
|
maxObjectKeysLimit = Number.POSITIVE_INFINITY,
|
|
} = limits;
|
|
const stack = [];
|
|
function replacer(key: string, value: mixed): mixed {
|
|
while (stack.length && this !== stack[0]) {
|
|
stack.shift();
|
|
}
|
|
|
|
if (typeof value === 'string') {
|
|
const truncatedString = '...(truncated)...';
|
|
if (value.length > maxStringLimit + truncatedString.length) {
|
|
return value.substring(0, maxStringLimit) + truncatedString;
|
|
}
|
|
return value;
|
|
}
|
|
if (typeof value !== 'object' || value === null) {
|
|
return value;
|
|
}
|
|
|
|
let retval:
|
|
| string
|
|
| {+[string]: mixed}
|
|
| $TEMPORARY$object<{'...(truncated keys)...': number}> = value;
|
|
if (Array.isArray(value)) {
|
|
if (stack.length >= maxDepth) {
|
|
retval = `[ ... array with ${value.length} values ... ]`;
|
|
} else if (value.length > maxArrayLimit) {
|
|
retval = value
|
|
.slice(0, maxArrayLimit)
|
|
.concat([
|
|
`... extra ${value.length - maxArrayLimit} values truncated ...`,
|
|
]);
|
|
}
|
|
} else {
|
|
// Add refinement after Array.isArray call.
|
|
invariant(typeof value === 'object', 'This was already found earlier');
|
|
let keys = Object.keys(value);
|
|
if (stack.length >= maxDepth) {
|
|
retval = `{ ... object with ${keys.length} keys ... }`;
|
|
} else if (keys.length > maxObjectKeysLimit) {
|
|
// Return a sample of the keys.
|
|
retval = ({}: {[string]: mixed});
|
|
for (let k of keys.slice(0, maxObjectKeysLimit)) {
|
|
retval[k] = value[k];
|
|
}
|
|
const truncatedKey = '...(truncated keys)...';
|
|
retval[truncatedKey] = keys.length - maxObjectKeysLimit;
|
|
}
|
|
}
|
|
stack.unshift(retval);
|
|
return retval;
|
|
}
|
|
|
|
return function stringifySafe(arg: mixed): string {
|
|
if (arg === undefined) {
|
|
return 'undefined';
|
|
} else if (arg === null) {
|
|
return 'null';
|
|
} else if (typeof arg === 'function') {
|
|
try {
|
|
return arg.toString();
|
|
} catch (e) {
|
|
return '[function unknown]';
|
|
}
|
|
} else if (arg instanceof Error) {
|
|
return arg.name + ': ' + arg.message;
|
|
} else {
|
|
// Perform a try catch, just in case the object has a circular
|
|
// reference or stringify throws for some other reason.
|
|
try {
|
|
const ret = JSON.stringify(arg, replacer);
|
|
if (ret === undefined) {
|
|
return '["' + typeof arg + '" failed to stringify]';
|
|
}
|
|
return ret;
|
|
} catch (e) {
|
|
if (typeof arg.toString === 'function') {
|
|
try {
|
|
// $FlowFixMe[incompatible-use] : toString shouldn't take any arguments in general.
|
|
return arg.toString();
|
|
} catch (E) {}
|
|
}
|
|
}
|
|
}
|
|
return '["' + typeof arg + '" failed to stringify]';
|
|
};
|
|
}
|
|
|
|
const stringifySafe: mixed => string = createStringifySafeWithLimits({
|
|
maxDepth: 10,
|
|
maxStringLimit: 100,
|
|
maxArrayLimit: 50,
|
|
maxObjectKeysLimit: 50,
|
|
});
|
|
|
|
export default stringifySafe;
|