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
14 changes: 13 additions & 1 deletion agent/Agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import type Bridge from './Bridge';
* - mount
* - update
* - unmount
* - sendGetterValue
*/
class Agent extends EventEmitter {
// the window or global -> used to "make a value available in the console"
Expand Down Expand Up @@ -153,6 +154,7 @@ class Agent extends EventEmitter {
bridge.on('setState', this._setState.bind(this));
bridge.on('setProps', this._setProps.bind(this));
bridge.on('setContext', this._setContext.bind(this));
bridge.on('evalGetter', this._evalGetter.bind(this));
bridge.on('makeGlobal', this._makeGlobal.bind(this));
bridge.on('highlight', id => this.highlight(id));
bridge.on('highlightMany', id => this.highlightMany(id));
Expand Down Expand Up @@ -216,6 +218,7 @@ class Agent extends EventEmitter {
bridge.forget(id);
});
this.on('setSelection', data => bridge.send('select', data));
this.on('sendGetterValue', (data) => bridge.send('evalgetterresult', data));
this.on('setInspectEnabled', data => bridge.send('setInspectEnabled', data));
}

Expand Down Expand Up @@ -338,6 +341,15 @@ class Agent extends EventEmitter {
}
}

_evalGetter({id, path}: {id: ElementID, path: Array<string>}) {
var data = this.elementData.get(id);
if (!data) {
return;
}
var value = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, data);
this.emit('sendGetterValue', {id, path, value});
}

_makeGlobal({id, path}: {id: ElementID, path: Array<string>}) {
var data = this.elementData.get(id);
if (!data) {
Expand Down Expand Up @@ -449,7 +461,7 @@ class Agent extends EventEmitter {
if (!id) {
return;
}

this.highlight(id);
}
}
Expand Down
14 changes: 14 additions & 0 deletions agent/__tests__/dehydrate-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,18 @@ describe('dehydrate', () => {
var result = dehydrate(object, cleaned);
expect(result.a).toEqual({type: 'date', name: d.toString(), meta: {uninspectable: true}});
});

it('cleans getters', () => {
var grand = {
get getter() {
return 'a';
},
};

var parent = Object.create(grand);
var object = Object.create(parent);
var cleaned = [];
var result = dehydrate(object, cleaned);
expect(result.getter).toEqual( { name: 'getter', type: 'getter' });
});
});
20 changes: 19 additions & 1 deletion agent/dehydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,15 @@ function dehydrate(data: Object, cleaned: Array<Array<string>>, path?: Array<str

var res = {};
for (var name in data) {
res[name] = dehydrate(data[name], cleaned, path.concat([name]), level + 1);
if (isPropertyGetter(data, name)) {
cleaned.push(path.concat([name]));
res[name] = {
name: name,
type: 'getter',
};
} else {
res[name] = dehydrate(data[name], cleaned, path.concat([name]), level + 1);
}
}
return res;
}
Expand All @@ -165,4 +173,14 @@ function dehydrate(data: Object, cleaned: Array<Array<string>>, path?: Array<str
}
}

function isPropertyGetter(obj, prop) {
/* eslint-disable no-proto */
while (!obj.hasOwnProperty(prop)) {
obj = obj.__proto__;
}
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
return descriptor.get !== undefined;
/* eslint-enable no-proto */
}

module.exports = dehydrate;
12 changes: 12 additions & 0 deletions backend/__tests__/copyWithSet-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,16 @@ describe('copyWithSet', function() {
var res = copyWithSet([0, 1, {2: {3: [4, 5, {6: {7: 8}}, 9], 10: 11}}, 12], [2, '2', '3', 2, '6', '7'], 'moose');
expect(res).toEqual([0, 1, {2: {3: [4, 5, {6: {7: 'moose'}}, 9], 10: 11}}, 12]);
});

it('must copy descriptors', function() {
var obj = {
_name: 'foo',
get name() {
return this._name + 'bar';
},
};

var res = copyWithSet(obj, ['a'], 'b');
expect(res.name).toEqual('foobar');
});
});
18 changes: 17 additions & 1 deletion backend/copyWithSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function copyWithSetImpl(obj, path, idx, value) {
return value;
}
var key = path[idx];
var updated = Array.isArray(obj) ? obj.slice() : {...obj};
var updated = Array.isArray(obj) ? obj.slice() : assignWithDescriptors(obj);
// $FlowFixMe number or string is fine here
updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
return updated;
Expand All @@ -25,4 +25,20 @@ function copyWithSet(obj: Object | Array<any>, path: Array<string | number>, val
return copyWithSetImpl(obj, path, 0, value);
}

function assignWithDescriptors(source) {
/* eslint-disable no-proto */
var target = Object.create(source.__proto__);
/* eslint-enable no-proto */

Object.defineProperties(target, Object.keys(source).reduce((descriptors, key) => {
var descriptor = Object.getOwnPropertyDescriptor(source, key);
if (descriptor.hasOwnProperty('writable')) {
descriptor.writable = true;
}
descriptors[key] = descriptor;
return descriptors;
}, {}));
return target;
}

module.exports = copyWithSet;
14 changes: 14 additions & 0 deletions frontend/DataView/DataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {Theme, DOMEvent} from '../types';
var {sansSerif} = require('../Themes/Fonts');
var React = require('react');
var Simple = require('./Simple');
var Getter = require('./Getter');

var consts = require('../../agent/consts');
var previewComplex = require('./previewComplex');
Expand Down Expand Up @@ -142,6 +143,7 @@ DataView.contextTypes = {
class DataItem extends React.Component {
context: {
onChange: (path: Array<string>, checked: boolean) => void,
isPropertyFrozen: (path: Array<string>) => boolean,
theme: Theme,
};
props: {
Expand Down Expand Up @@ -174,6 +176,14 @@ class DataItem extends React.Component {
}
}

shouldComponentUpdate(nextProps) {
if (nextProps.value[consts.type] === 'getter') {
return !this.context.isPropertyFrozen(nextProps.path);
} else {
return true;
}
}

inspect() {
this.setState({loading: true, open: true});
this.props.inspect(this.props.path, () => {
Expand Down Expand Up @@ -214,6 +224,9 @@ class DataItem extends React.Component {
/>
);
complex = false;
} else if (data[consts.type] === 'getter') {
preview = <Getter data={data} path={this.props.path} />;
complex = false;
} else {
preview = previewComplex(data, theme);
}
Expand Down Expand Up @@ -294,6 +307,7 @@ class DataItem extends React.Component {

DataItem.contextTypes = {
onChange: React.PropTypes.func,
isPropertyFrozen: React.PropTypes.func,
theme: React.PropTypes.object.isRequired,
};

Expand Down
41 changes: 41 additions & 0 deletions frontend/DataView/Getter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* 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 React = require('react');

class Getter extends React.Component {
handleClick() {
this.context.onEvalGetter(this.props.path);
}

constructor(props: Object) {
super(props);
}

render() {
return <div style={style} onClick={this.handleClick.bind(this)}>(…)</div>;
}
}

const style = {
'cursor': 'pointer',
};

Getter.propTypes = {
data: React.PropTypes.any,
path: React.PropTypes.array,
};

Getter.contextTypes = {
onEvalGetter: React.PropTypes.func,
};

module.exports = Getter;
15 changes: 15 additions & 0 deletions frontend/PropState.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ class PropState extends React.Component {
onChange: (path, val) => {
this.props.onChange(path, val);
},
onEvalGetter: (path) => {
this.props.onEvalGetter(path);
},
isPropertyFrozen: (path) => {
return this.props.isPathFrozen(path);
},
};
}

Expand Down Expand Up @@ -176,6 +182,9 @@ PropState.contextTypes = {

PropState.childContextTypes = {
onChange: React.PropTypes.func,
onEvalGetter: React.PropTypes.func,
isPropertyFrozen: React.PropTypes.func,

};

var WrappedPropState = decorate({
Expand All @@ -189,6 +198,9 @@ var WrappedPropState = decorate({
id: store.selected,
node,
canEditTextContent: store.capabilities.editTextContent,
isPathFrozen(path) {
return store.isPathFrozen(path);
},
onChangeText(text) {
store.changeTextContent(store.selected, text);
},
Expand All @@ -206,6 +218,9 @@ var WrappedPropState = decorate({
showMenu(e, val, path, name) {
store.showContextMenu('attr', e, store.selected, node, val, path, name);
},
onEvalGetter(path) {
store.evalGetter(store.selected, path);
},
inspect: store.inspect.bind(store, store.selected),
};
},
Expand Down
18 changes: 12 additions & 6 deletions frontend/PropVal.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,29 @@ function previewProp(val: any, nested: boolean, inverted: boolean, theme: Theme)
return <span style={style}>{`${val[consts.name]}[${val[consts.meta].length}]`}</span>;
}
case 'iterator': {
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
};
return <span style={style}>{val[consts.name] + '(…)'}</span>;
}
case 'symbol': {
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
};
// the name is "Symbol(something)"
return <span style={style}>{val[consts.name]}</span>;
}
case 'getter': {
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
};
return <span style={style}>(…)</span>;
}
}

if (nested) {
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
style = {
color: inverted ? getInvertedWeak(theme.state02) : theme.base05,
};
return <span style={style}>{'{…}'}</span>;
}
Expand Down
Loading