Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion agent/Agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

var {EventEmitter} = require('events');
var assign = require('object-assign');
var immutableUtils = require('./immutableUtils');

import type {RendererID, DataType, OpaqueNodeHandle, NativeType, Helpers} from '../backend/types';

Expand Down Expand Up @@ -378,7 +379,11 @@ function randid() {

function getIn(base, path) {
return path.reduce((obj, attr) => {
return obj ? obj[attr] : null;
var alt;
if (obj !== null && immutableUtils.isImmutable(obj) && obj.get) {
alt = obj.get(attr);
}
return obj ? alt || obj[attr] : null;
}, base);
}

Expand Down
13 changes: 12 additions & 1 deletion agent/Bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
var consts = require('./consts');
var hydrate = require('./hydrate');
var dehydrate = require('./dehydrate');
var immutableUtils = require('../agent/immutableUtils');

type AnyFn = (...x: any) => any;
export type Wall = {
Expand Down Expand Up @@ -103,6 +104,7 @@ type PayloadType = {
* determined that an object is no longer needed, call `.forget(id)` to clean
* up.
*/

class Bridge {
_buffer: Array<{evt: string, data: any}>;
_cbs: Map;
Expand Down Expand Up @@ -318,6 +320,11 @@ class Bridge {
if (val) {
var protod = false;
var isFn = typeof val === 'function';

if (immutableUtils.isImmutable(val)) {
val = immutableUtils.shallowToJS(val);
}

Object.getOwnPropertyNames(val).forEach(name => {
if (name === '__proto__') {
protod = true;
Expand Down Expand Up @@ -354,7 +361,11 @@ class Bridge {

function getIn(base, path) {
return path.reduce((obj, attr) => {
return obj ? obj[attr] : null;
var alt;
if (obj !== null && immutableUtils.isImmutable(obj) && obj.get) {
alt = obj.get(attr);
}
return obj ? alt || obj[attr] : null;
}, base);
}

Expand Down
27 changes: 26 additions & 1 deletion agent/__tests__/dehydrate-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
'use strict';

jest.dontMock('../dehydrate');
var dehydrate = require('../dehydrate');
jest.dontMock('../immutableUtils');
jest.dontMock('immutable');
var dehydrate = require('../dehydrate'),
Immutable = require('immutable');

describe('dehydrate', () => {
it('leaves an empty object alone', () => {
Expand Down Expand Up @@ -55,4 +58,26 @@ describe('dehydrate', () => {
expect(result.a.b.c).toEqual({type: 'array', name: 'Array', meta: {length: 2}});
expect(result.a.b.d).toEqual({type: 'object', name: 'Something', meta: null});
});

it('cleans a shallowly nested Immutable objects with the appropriate name', function() {
var object = {c: Immutable.List([1, 3]), d: Immutable.Map(), e: Immutable.Set()};
var cleaned = [];
var result = dehydrate(object, cleaned);

expect(cleaned).toEqual([['c'], ['d'], ['e']]);
expect(result.c).toEqual({type: 'object', name: 'Immutable.List'});
expect(result.d).toEqual({type: 'object', name: 'Immutable.Map'});
expect(result.e).toEqual({type: 'object', name: 'Immutable.Set'});
});

it('cleans a deeply nested Immutable objects with the appropriate name', function() {
var object = {a: {b: {c: Immutable.List([1, 3]), d: Immutable.Map(), e: Immutable.Set()}}};
var cleaned = [];
var result = dehydrate(object, cleaned);

expect(cleaned).toEqual([['a', 'b', 'c'], ['a', 'b', 'd'], ['a', 'b', 'e']]);
expect(result.a.b.c).toEqual({type: 'object', name: 'Immutable.List', meta: null});
expect(result.a.b.d).toEqual({type: 'object', name: 'Immutable.Map', meta: null});
expect(result.a.b.e).toEqual({type: 'object', name: 'Immutable.Set', meta: null});
});
});
86 changes: 86 additions & 0 deletions agent/__tests__/immutableUtils-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. a additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
'use strict';

jest.dontMock('../immutableUtils');
jest.dontMock('immutable');
var immutableUtils = require('../immutableUtils'),
Immutable = require('immutable');

describe('immutableUtils', () => {

describe('getImmutableName()', function() {
it('generates the right name for an OrderedMap', () => {
var name = immutableUtils.getImmutableName(Immutable.OrderedMap());
expect(name).toBe('Immutable.OrderedMap');
});

it('generates the right name for an OrderedSet', () => {
var name = immutableUtils.getImmutableName(Immutable.OrderedSet());
expect(name).toBe('Immutable.OrderedSet');
});

it('generates the right name for a Map', () => {
var name = immutableUtils.getImmutableName(Immutable.Map());
expect(name).toBe('Immutable.Map');
});

it('generates the right name for a Set', () => {
var name = immutableUtils.getImmutableName(Immutable.Set());
expect(name).toBe('Immutable.Set');
});

it('generates the right name for a List', () => {
var name = immutableUtils.getImmutableName(Immutable.List());
expect(name).toBe('Immutable.List');
});

it('generates the right name for a Stack', () => {
var name = immutableUtils.getImmutableName(Immutable.Stack());
expect(name).toBe('Immutable.Stack');
});

it('generates the right name for a Seq', () => {
var name = immutableUtils.getImmutableName(Immutable.Seq());
expect(name).toBe('Immutable.Seq');
});
});

describe('shallowToJS()', function() {
it('converts a Map correctly', function() {
var map = Immutable.Map({
a: 1,
b: 2,
c: Immutable.Map()
});
var result = immutableUtils.shallowToJS(map);
expect(result.a).toBe(1);
expect(result.b).toBe(2);
expect(Immutable.Map.isMap(result.c)).toBe(true);
});

it('converts a List correctly', function() {
var list = Immutable.List(['a', 'b', Immutable.Map()]);
var result = immutableUtils.shallowToJS(list);
expect(result[0]).toBe('a');
expect(result[1]).toBe('b');
expect(Immutable.Map.isMap(result[2])).toBe(true);
});

it('converts a Set correctly', function() {
var set = Immutable.Set([1, 2, 3, Immutable.List()]);
var result = immutableUtils.shallowToJS(set);

expect(Array.isArray(result)).toBe(true);
expect(result.filter(Immutable.List.isList).length > 0).toBe(true);
});
});

});
14 changes: 11 additions & 3 deletions agent/dehydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
* }
* and cleaned = [["some", "attr"], ["other"]]
*/

var immutableUtils = require('./immutableUtils');

function dehydrate(data: Object, cleaned: Array<Array<string>>, path?: Array<string>, level?: number): string | Object {
level = level || 0;
path = path || [];
Expand Down Expand Up @@ -60,11 +63,16 @@ function dehydrate(data: Object, cleaned: Array<Array<string>>, path?: Array<str
// React Fragments error if you try to inspect them.
return 'A react fragment';
}

var name = immutableUtils.isImmutable(data) ?
immutableUtils.getImmutableName(data) :
data.constructor.name;

if (level > 2) {
cleaned.push(path);
return {
type: Array.isArray(data) ? 'array' : 'object',
name: data.constructor.name === 'Object' ? '' : data.constructor.name,
name: data.constructor.name === 'Object' ? '' : name,
meta: Array.isArray(data) ? {
length: data.length,
} : null,
Expand All @@ -78,8 +86,8 @@ function dehydrate(data: Object, cleaned: Array<Array<string>>, path?: Array<str
if (data.constructor && typeof data.constructor === 'function' && data.constructor.name !== 'Object') {
cleaned.push(path);
return {
name: data.constructor.name,
type: 'object',
name: name,
type: 'object'
};
}
var res = {};
Expand Down
50 changes: 50 additions & 0 deletions agent/immutableUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
*/
'use strict';

var Immutable = require('immutable');

var types = ['OrderedMap', 'OrderedSet',
'Map', 'Set', 'List', 'Stack',
'Seq'];

module.exports = {
isImmutable: Immutable.Iterable.isIterable,
getImmutableName(data: any): string {
if (Immutable.Iterable.isIterable(data)) {
var name = 'Immutable.',
typelen = types.length;
for (var i = 0; i < typelen; i++) {
if (Immutable[types[i]]['is' + types[i]](data)) {
name += types[i];
break;
}
}
return name;
} else {
return data.constructor.name;
}
},
shallowToJS(dataStructure: any): any {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I ask your rationale behind providing a shallowToJS here but not a deepToJS that calls Iterable.toJS()? For example, if a particular prop is an Immutable.KeyedIterable with a property value that is itself an Immutable object, then it seems that shallowToJS would not convert the property value to a mutable object.

Edit - I see that your test for this module already asserts the above. Would it not be valuable to do a deep .toJS() call for any immutable object so that the dev tool user can more easily navigate nested immutable properties and state values?

Edit 2 - After digging a bit deeper, it looks like you're doing a shallow conversion at each level so that the user can easily see whether or not some nested property is immutable or not while also being able to easily inspect its child properties. If that's the case, 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was just about to write that. The reason in edit 2 is precisely why.

if (!Immutable.Iterable.isIterable(dataStructure)) {
return dataStructure;
}

if (Immutable.Iterable.isKeyed(dataStructure)) {
return dataStructure.toObject();
} else if (Immutable.Iterable.isIndexed(dataStructure) ||
Immutable.Set.isSet(dataStructure)) {
return dataStructure.toArray();
}

return dataStructure;
}
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"babel-loader": "^5.1.4",
"eslint": "^0.24.1",
"eslint-plugin-react": "^3.0.0",
"jest-cli": "facebook/jest#0.5.x",
"jest-cli": "0.5.0",
"json-loader": "^0.5.2",
"node-libs-browser": "^0.5.2",
"webpack": "^1.9.10"
Expand Down