Iterative version of the serializer

Summary: Iterative version of the custom serializer. The recursive implementation led to call stack overflow for news feed surface in fb4a.

Reviewed By: danielbuechele

Differential Revision: D15251643

fbshipit-source-id: b8af921b1a4d85c52d4d45a7abf95a5bb5f283f7
This commit is contained in:
Pritesh Nandgaonkar
2019-05-09 06:34:05 -07:00
committed by Facebook Github Bot
parent 3fa0a92754
commit 4dcb41f5e6

View File

@@ -13,33 +13,149 @@ export function deserialize(str: string): Object {
return deserializeObject(JSON.parse(str));
}
function processArray(
element: any,
array: [any],
stack: Array<any>,
dict: Map<any, any>,
): {premature: boolean, outputArr: Array<any>} {
let outputArr = [];
let premature = false;
for (const item of array) {
if (!dict.has(item)) {
if (!(item instanceof Object)) {
dict.set(item, item);
} else {
stack.push(element);
stack.push(item);
premature = true;
break;
}
}
if (dict.has(item)) {
dict.set(item, dict.get(item));
outputArr.push(dict.get(item));
}
}
return {premature, outputArr};
}
function processKeyValuePair(
element: any,
key: any,
value: any,
stack: Array<any>,
dict: Map<any, any>,
): {premature: boolean} {
let premature = false;
if (!dict.has(key)) {
if (!(key instanceof Object)) {
dict.set(key, key);
} else {
stack.push(element);
stack.push(key);
premature = true;
return {premature};
}
}
if (!dict.has(value)) {
if (!(value instanceof Object)) {
dict.set(value, value);
} else {
stack.push(element);
stack.push(value);
premature = true;
}
}
return {premature};
}
export function makeObjectSerializable(obj: any): any {
if (!(obj instanceof Object)) {
return obj;
}
if (obj instanceof Map) {
return {
__flipper_object_type__: 'Map',
data: [...obj].map(makeObjectSerializable),
};
} else if (obj instanceof Set) {
return {
__flipper_object_type__: 'Set',
data: [...obj].map(makeObjectSerializable),
};
} else if (obj instanceof Date) {
return {
__flipper_object_type__: 'Date',
data: obj.toString(),
};
} else if (obj instanceof Array) {
return obj.map(makeObjectSerializable);
let stack = [obj];
const dict: Map<any, any> = new Map();
while (stack.length > 0) {
const element = stack.pop();
if (element instanceof Map) {
const arr = [];
let premature = false;
for (const item of [...element]) {
const key = item[0];
const value = item[1];
premature = processKeyValuePair(element, key, value, stack, dict)
.premature;
if (premature) {
break;
}
if (dict.has(key) && dict.has(value)) {
dict.set(item, [dict.get(key), dict.get(value)]);
arr.push([dict.get(key), dict.get(value)]);
}
}
if (premature) {
continue;
}
dict.set(element, {
__flipper_object_type__: 'Map',
data: arr,
});
} else if (element instanceof Set) {
const {premature, outputArr} = processArray(
element,
[...element],
stack,
dict,
);
if (premature) {
continue;
}
dict.set(element, {
__flipper_object_type__: 'Set',
data: outputArr,
});
} else if (element instanceof Date) {
dict.set(element, {
__flipper_object_type__: 'Date',
data: element.toString(),
});
} else if (element instanceof Array) {
const {premature, outputArr} = processArray(
element,
element,
stack,
dict,
);
if (premature) {
continue;
}
dict.set(element, outputArr);
} else if (element instanceof Object) {
const array = Object.entries(element);
let obj = {};
let premature = false;
for (const item of array) {
const key = item[0];
const value = item[1];
premature = processKeyValuePair(element, key, value, stack, dict)
.premature;
if (premature) {
break;
}
const serializedKey = dict.get(key);
const serializedValue = dict.get(value);
if (serializedValue && serializedKey) {
obj = {...obj, [serializedKey]: serializedValue};
}
}
if (premature) {
continue;
}
dict.set(element, obj);
}
}
return Object.entries(obj).reduce(
(acc, [key, value]) => ({...acc, [key]: makeObjectSerializable(value)}),
{},
);
return dict.get(obj);
}
export function deserializeObject(obj: any): any {