Stop aggressively using the reviver option on JSON.parse, part 1

This commit is contained in:
Ben Gotow 2017-07-07 12:12:57 -07:00
parent bad1e27c2f
commit e529197701
8 changed files with 30 additions and 44 deletions

View file

@ -11,7 +11,7 @@ function safeDecode(str) {
function _runOnImageNode(node) {
if (node.src && node.dataset.nylasFile) {
node.addEventListener('error', () => {
const file = JSON.parse(safeDecode(node.dataset.nylasFile), Utils.registeredObjectReviver);
const file = Utils.convertToModel(JSON.parse(safeDecode(node.dataset.nylasFile)));
const initialDisplay = node.style.display;
const downloadButton = document.createElement('a');
downloadButton.classList.add('inline-download-prompt')
@ -28,7 +28,7 @@ function _runOnImageNode(node) {
});
node.addEventListener('load', () => {
const file = JSON.parse(safeDecode(node.dataset.nylasFile), Utils.registeredObjectReviver);
const file = Utils.convertToModel(JSON.parse(safeDecode(node.dataset.nylasFile)));
node.addEventListener('dblclick', () => {
Actions.fetchAndOpenFile(file);
});
@ -37,7 +37,7 @@ function _runOnImageNode(node) {
}
export function encodedAttributeForFile(file) {
return safeEncode(JSON.stringify(file, Utils.registeredObjectReplacer));
return safeEncode(JSON.stringify(file));
}
export function addInlineImageListeners(doc) {

View file

@ -18,7 +18,7 @@ class Bar extends Foo
describe 'Utils', ->
describe "registeredObjectReviver / registeredObjectReplacer", ->
describe "modelTypesReviver", ->
beforeEach ->
@testThread = new Thread
id: 'local-1'
@ -33,18 +33,18 @@ describe 'Utils', ->
it "should serialize and de-serialize models correctly", ->
expectedString = '[{"client_id":"local-1","account_id":"1","metadata":[],"subject":"Test 1234","participants":[{"client_id":"local-a","account_id":"1","name":"Juan","email":"juan@nylas.com","thirdPartyData":{},"is_search_indexed":false,"id":"local-a"},{"client_id":"local-b","account_id":"1","name":"Ben","email":"ben@nylas.com","thirdPartyData":{},"is_search_indexed":false,"id":"local-b"}],"in_all_mail":true,"is_search_indexed":false,"id":"local-1","__cls":"Thread"}]'
jsonString = JSON.stringify([@testThread], Utils.registeredObjectReplacer)
jsonString = JSON.stringify([@testThread])
expect(jsonString).toEqual(expectedString)
revived = JSON.parse(jsonString, Utils.registeredObjectReviver)
revived = JSON.parse(jsonString, Utils.modelTypesReviver)
expect(revived).toEqual([@testThread])
it "should re-inflate Models in places they're not explicitly declared types", ->
b = new JSONBlob({id: "ThreadsToProcess", json: [@testThread]})
jsonString = JSON.stringify(b, Utils.registeredObjectReplacer)
jsonString = JSON.stringify(b)
expectedString = '{"client_id":"ThreadsToProcess","server_id":"ThreadsToProcess","json":[{"client_id":"local-1","account_id":"1","metadata":[],"subject":"Test 1234","participants":[{"client_id":"local-a","account_id":"1","name":"Juan","email":"juan@nylas.com","thirdPartyData":{},"is_search_indexed":false,"id":"local-a"},{"client_id":"local-b","account_id":"1","name":"Ben","email":"ben@nylas.com","thirdPartyData":{},"is_search_indexed":false,"id":"local-b"}],"in_all_mail":true,"is_search_indexed":false,"id":"local-1","__cls":"Thread"}],"id":"ThreadsToProcess","__cls":"JSONBlob"}'
expect(jsonString).toEqual(expectedString)
revived = JSON.parse(jsonString, Utils.registeredObjectReviver)
revived = JSON.parse(jsonString, Utils.modelTypesReviver)
expect(revived).toEqual(b)
expect(revived.json[0] instanceof Thread).toBe(true)
expect(revived.json[0].participants[0] instanceof Contact).toBe(true)

View file

@ -430,7 +430,7 @@ export default class TokenizingTextField extends React.Component {
let items = null;
try {
items = JSON.parse(json, Utils.registeredObjectReviver);
items = JSON.parse(json).map(Utils.convertToModel);
} catch (err) {
console.error(err)
items = null;
@ -663,7 +663,7 @@ export default class TokenizingTextField extends React.Component {
if (tokens.length === 0) {
tokens = [token];
}
const json = JSON.stringify(tokens, Utils.registeredObjectReplacer);
const json = JSON.stringify(tokens);
event.dataTransfer.setData('nylas-token-items', json);
event.dataTransfer.setData('text/plain', tokens.map(t => t.toString()).join(', '));
event.dataTransfer.dropEffect = "move";
@ -755,7 +755,7 @@ export default class TokenizingTextField extends React.Component {
_onAttachToClipboard = (event) => {
const text = this.state.selectedKeys.join(', ')
if (event.clipboardData) {
const json = JSON.stringify(this._selectedTokens(), Utils.registeredObjectReplacer);
const json = JSON.stringify(this._selectedTokens());
event.clipboardData.setData('text/plain', text);
event.clipboardData.setData('nylas-token-items', json);

View file

@ -296,7 +296,7 @@ export default class ModelQuery {
try {
return result.map((row) => {
const object = JSON.parse(row.data, Utils.registeredObjectReviver)
const object = Utils.convertToModel(JSON.parse(row.data));
for (const attrName of Object.keys(this._klass.attributes)) {
const attr = this._klass.attributes[attrName];
if (!attr.needsColumn() || !attr.loadFromColumn) {

View file

@ -32,7 +32,7 @@ Utils =
html = html.slice(0, maxLength)
(new DOMParser()).parseFromString(html, "text/html").body.innerText
registeredObjectReviver: (k,v) ->
modelTypesReviver: (k,v) ->
type = v?.__cls
return v unless type
@ -40,13 +40,15 @@ Utils =
return DatabaseObjectRegistry.deserialize(type, v)
return v
registeredObjectReplacer: (k, v) ->
if _.isObject(v)
type = this[k].constructor.name
if DatabaseObjectRegistry.isInRegistry(type)
v.__cls = type
return v
convertToModel: (json) ->
if not json
return null
if not json.__cls
throw new Error("convertToModel: no __cls found on object.")
if not DatabaseObjectRegistry.isInRegistry(json.__cls)
throw new Error("convertToModel: __cls is not a known class.")
return DatabaseObjectRegistry.deserialize(json.__cls, json)
fastOmit: (props, without) ->
otherProps = Object.assign({}, props)

View file

@ -1,5 +1,3 @@
import Utils from '../models/utils';
/*
DatabaseChangeRecord is the object emitted from the DatabaseStore when it triggers.
The DatabaseChangeRecord contains information about what type of model changed,
@ -8,27 +6,13 @@ change records.
*/
export default class DatabaseChangeRecord {
constructor(options) {
this.options = options;
this._objects = options.objects
this._objectsString = options.objectsString;
this._objects = this._objects || JSON.parse(this._objectsString, Utils.registeredObjectReviver);
Object.defineProperty(this, 'type', {
get: () => options.type,
})
Object.defineProperty(this, 'objectClass', {
get: () => options.objectClass,
})
Object.defineProperty(this, 'objects', {
get: () => {
return this._objects;
},
})
constructor({type, objectClass, objects}) {
this.objects = objects;
this.type = type;
this.objectClass = objectClass;
}
toJSON() {
this._objectsString = this._objectsString || JSON.stringify(this._objects, Utils.registeredObjectReplacer);
return {
type: this.type,
objectClass: this.objectClass,

View file

@ -61,10 +61,10 @@ class MailboxPerspective
@fromJSON: (json) =>
try
if json.type is CategoryMailboxPerspective.name
categories = JSON.parse(json.serializedCategories, Utils.registeredObjectReviver)
categories = JSON.parse(json.serializedCategories).map(Utils.convertToModel)
return @forCategories(categories)
else if json.type is UnreadMailboxPerspective.name
categories = JSON.parse(json.serializedCategories, Utils.registeredObjectReviver)
categories = JSON.parse(json.serializedCategories).map(Utils.convertToModel)
return @forUnread(categories)
else if json.type is StarredMailboxPerspective.name
return @forStarred(json.accountIds)
@ -262,7 +262,7 @@ class CategoryMailboxPerspective extends MailboxPerspective
toJSON: =>
json = super
json.serializedCategories = JSON.stringify(@_categories, Utils.registeredObjectReplacer)
json.serializedCategories = JSON.stringify(@_categories)
json
isEqual: (other) =>

View file

@ -105,7 +105,7 @@ export default class MailsyncProcess extends EventEmitter {
sendMessage(json) {
if (!Utils) { Utils = require('nylas-exports').Utils; }
const msg = `${JSON.stringify(json, Utils.registeredObjectReplacer)}\n`;
const msg = `${JSON.stringify(json)}\n`;
const contentBuffer = Buffer.from(msg);
this._proc.stdin.write(contentBuffer);
}