mirror of
https://github.com/morten-olsen/react-native-debug-console.git
synced 2026-02-08 00:36:26 +01:00
init
This commit is contained in:
16
lib/package.json
Normal file
16
lib/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "react-native-debug-console",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-native-json-tree": "^1.2.0",
|
||||
"styled-components": "^3.4.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.4.2",
|
||||
"react-native": "^0.56.0"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
57
lib/src/components/DevTool/Console/Input.js
Normal file
57
lib/src/components/DevTool/Console/Input.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
Button,
|
||||
TextInput,
|
||||
} from 'react-native';
|
||||
import State from '../../data/State';
|
||||
import log from '../../../log';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderColor: '#ccc',
|
||||
borderTopWidth: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const Input = ({
|
||||
logs,
|
||||
}) => (
|
||||
<State>
|
||||
{({
|
||||
text = '',
|
||||
}, setState) => (
|
||||
<View style={styles.container}>
|
||||
<TextInput
|
||||
multiline
|
||||
style={styles.input}
|
||||
value={text}
|
||||
onChangeText={text => setState({ text })}
|
||||
/>
|
||||
<Button
|
||||
title="eval"
|
||||
onPress={() => {
|
||||
const fn = new Function(text);
|
||||
try {
|
||||
const response = eval(text);
|
||||
log.info(response);
|
||||
setState({
|
||||
text: '',
|
||||
});
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</State>
|
||||
);
|
||||
|
||||
export default Input;
|
||||
60
lib/src/components/DevTool/Console/Output.js
Normal file
60
lib/src/components/DevTool/Console/Output.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
View,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import JSONTree from 'react-native-json-tree'
|
||||
import prune from './tools';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const getCircularReplacer = () => {
|
||||
const seen = [];
|
||||
return (key, val) => {
|
||||
if (val != null && typeof val == "object") {
|
||||
if (seen.indexOf(val) >= 0) {
|
||||
return;
|
||||
}
|
||||
seen.push(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
const formatData = (data) => {
|
||||
if (typeof data === 'undefined') {
|
||||
return <Text>undefined</Text>;
|
||||
}
|
||||
if (data instanceof Error) {
|
||||
return <Text>Error {data.toString()} {data.stack.toString()}</Text>;
|
||||
}
|
||||
if (typeof data === 'object') {
|
||||
return <JSONTree data={prune(data, null, ' ')} />
|
||||
}
|
||||
return <Text>{data.toString()}</Text>;
|
||||
}
|
||||
|
||||
const Console = ({
|
||||
logs,
|
||||
}) => (
|
||||
<ScrollView style={styles.container}>
|
||||
<View>
|
||||
{logs.map((log, i) => (
|
||||
<View key={i}>
|
||||
<Text>
|
||||
{log.type}
|
||||
</Text>
|
||||
{formatData(log.data)}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
export default Console;
|
||||
28
lib/src/components/DevTool/Console/index.js
Normal file
28
lib/src/components/DevTool/Console/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import Log from '../../data/Log';
|
||||
import Output from './Output';
|
||||
import Input from './Input';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const Console = () => (
|
||||
<Log>
|
||||
{({ logs }) => (
|
||||
<View style={styles.container}>
|
||||
<Output logs={logs} />
|
||||
<Input />
|
||||
</View>
|
||||
)}
|
||||
</Log>
|
||||
);
|
||||
|
||||
export default Console;
|
||||
94
lib/src/components/DevTool/Console/tools.js
Normal file
94
lib/src/components/DevTool/Console/tools.js
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
var DEFAULT_MAX_DEPTH = 3;
|
||||
var DEFAULT_ARRAY_MAX_LENGTH = 50;
|
||||
var seen; // Same variable used for all stringifications
|
||||
|
||||
Date.prototype.toPrunedJSON = Date.prototype.toJSON;
|
||||
String.prototype.toPrunedJSON = String.prototype.toJSON;
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
|
||||
function quote(string) {
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string'
|
||||
? c
|
||||
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
|
||||
function str(key, holder, depthDecr, arrayMaxLength) {
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
partial,
|
||||
value = holder[key];
|
||||
if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') {
|
||||
value = value.toPrunedJSON(key);
|
||||
}
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
case 'number':
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
return String(value);
|
||||
case 'object':
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
if (depthDecr<=0 || seen.indexOf(value)!==-1) {
|
||||
return '"-pruned-"';
|
||||
}
|
||||
seen.push(value);
|
||||
partial = [];
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
length = Math.min(value.length, arrayMaxLength);
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value, depthDecr-1, arrayMaxLength) || 'null';
|
||||
}
|
||||
v = partial.length === 0
|
||||
? '[]'
|
||||
: '[' + partial.join(',') + ']';
|
||||
return v;
|
||||
}
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
try {
|
||||
v = str(k, value, depthDecr-1, arrayMaxLength);
|
||||
if (v) partial.push(quote(k) + ':' + v);
|
||||
} catch (e) {
|
||||
// this try/catch due to some "Accessing selectionEnd on an input element that cannot have a selection." on Chrome
|
||||
}
|
||||
}
|
||||
}
|
||||
v = partial.length === 0
|
||||
? '{}'
|
||||
: '{' + partial.join(',') + '}';
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
export default function (value, depthDecr, arrayMaxLength) {
|
||||
seen = [];
|
||||
depthDecr = depthDecr || DEFAULT_MAX_DEPTH;
|
||||
arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH;
|
||||
const raw = str('', {'': value}, depthDecr, arrayMaxLength);
|
||||
// return JSON.stringify(JSON.parse(raw.root), null, ' ');
|
||||
return raw;
|
||||
};
|
||||
64
lib/src/components/DevTool/Modal.js
Normal file
64
lib/src/components/DevTool/Modal.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
} from 'react-native';
|
||||
import events from '../../events';
|
||||
import DevTool from './index';
|
||||
|
||||
|
||||
class Events extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
visible: false,
|
||||
};
|
||||
this.listen = this.listen.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
events.listen(this.listen);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
events.unlisten(this.listen);
|
||||
}
|
||||
|
||||
listen(type, data) {
|
||||
if (type === 'SHOW_DEVTOOLS') {
|
||||
return this.setState({
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (type === 'HIDE_DEVTOOLS') {
|
||||
return this.setState({
|
||||
visible: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal
|
||||
animationType="slide"
|
||||
transparent={false}
|
||||
visible={this.state.visible}
|
||||
onRequestClose={() => {
|
||||
}}
|
||||
>
|
||||
<Fragment>
|
||||
<DevTool />
|
||||
<Button
|
||||
title="close"
|
||||
onPress={() => {
|
||||
events.publish('HIDE_DEVTOOLS');
|
||||
}}
|
||||
/>
|
||||
</Fragment>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Events;
|
||||
58
lib/src/components/DevTool/Requests/Details.js
Normal file
58
lib/src/components/DevTool/Requests/Details.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
View,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import Tab from '../Tab';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const Data = ({
|
||||
url,
|
||||
method,
|
||||
status,
|
||||
args = [],
|
||||
}) => (
|
||||
<ScrollView style={styles.container}>
|
||||
<View>
|
||||
<Text>Status: {status}</Text>
|
||||
<Text>Method: {method}</Text>
|
||||
<Text>Url: {url}</Text>
|
||||
<Text>Request Body:</Text>
|
||||
{args[0] && (
|
||||
<Text>{args[0].toString()}</Text>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const Response = ({
|
||||
request,
|
||||
}) => (
|
||||
<ScrollView style={styles.container}>
|
||||
<View>
|
||||
<Text>Response: {request.responseText}</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
|
||||
const RequestDetails = (props) => (
|
||||
<Tab
|
||||
tabs={[{
|
||||
name: 'overview',
|
||||
view: <Data {...props} />
|
||||
}, {
|
||||
name: 'response',
|
||||
view: <Response {...props} />
|
||||
}]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default RequestDetails;
|
||||
58
lib/src/components/DevTool/Requests/List.js
Normal file
58
lib/src/components/DevTool/Requests/List.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
borderColor: '#ccc',
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
padding: 10,
|
||||
},
|
||||
method: {
|
||||
padding: 5,
|
||||
},
|
||||
url: {
|
||||
flex: 1,
|
||||
padding: 5,
|
||||
},
|
||||
status: {
|
||||
padding: 5,
|
||||
},
|
||||
});
|
||||
|
||||
const RequestDetails = ({
|
||||
requests,
|
||||
onSelect,
|
||||
}) => (
|
||||
<ScrollView style={styles.container}>
|
||||
<View>
|
||||
{requests.map(({
|
||||
status,
|
||||
method,
|
||||
url,
|
||||
}, i) => (
|
||||
<TouchableOpacity
|
||||
key={i}
|
||||
onPress={() => onSelect(i)}
|
||||
>
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.method}>{method}</Text>
|
||||
<Text style={styles.url}>{url}</Text>
|
||||
<Text style={styles.status}>{status}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
export default RequestDetails;
|
||||
50
lib/src/components/DevTool/Requests/index.js
Normal file
50
lib/src/components/DevTool/Requests/index.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import State from '../../data/State';
|
||||
import Network from '../../data/Network';
|
||||
import Details from './Details';
|
||||
import List from './List';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
list: {
|
||||
flex: 1,
|
||||
borderColor: '#ccc',
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
details: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const Console = () => (
|
||||
<State>
|
||||
{({
|
||||
active,
|
||||
}, setState) => (
|
||||
<Network>
|
||||
{({ requests }) => {
|
||||
const selected = active >= 0 ? requests[active] : undefined;
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<List
|
||||
requests={requests}
|
||||
onSelect={(i) => setState({ active: i })}
|
||||
/>
|
||||
{selected && <Details {...selected} />}
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</Network>
|
||||
)}
|
||||
</State>
|
||||
);
|
||||
|
||||
export default Console;
|
||||
76
lib/src/components/DevTool/Tab.js
Normal file
76
lib/src/components/DevTool/Tab.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import State from '../data/State';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
tabs: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tabInactive: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 10,
|
||||
borderBottomWidth: 1,
|
||||
borderColor: '#ccc',
|
||||
},
|
||||
tabActive: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 10,
|
||||
borderBottomWidth: 4,
|
||||
borderColor: 'red',
|
||||
},
|
||||
});
|
||||
|
||||
const Console = ({
|
||||
tabs,
|
||||
}) => (
|
||||
<State
|
||||
initState={{
|
||||
active: 0,
|
||||
}}
|
||||
>
|
||||
{({ active }, setState) => (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.tabs}>
|
||||
{tabs.map(({ name }, i) => (
|
||||
<TouchableOpacity
|
||||
key={name}
|
||||
style={active === i ? styles.tabActive : styles.tabInactive}
|
||||
onPress={() => {
|
||||
setState({ active: i });
|
||||
}}
|
||||
>
|
||||
<Text>{name}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
{tabs[active] && tabs[active].view}
|
||||
</View>
|
||||
)}
|
||||
</State>
|
||||
);
|
||||
|
||||
Console.propTypes = {
|
||||
tabs: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
})),
|
||||
};
|
||||
|
||||
Console.defaultProps = {
|
||||
tabs: [],
|
||||
};
|
||||
|
||||
export default Console;
|
||||
32
lib/src/components/DevTool/index.js
Normal file
32
lib/src/components/DevTool/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Tab from './Tab';
|
||||
import Console from './Console';
|
||||
import Requests from './Requests';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const DevTool = ({
|
||||
style,
|
||||
}) => (
|
||||
<View style={style || styles.container}>
|
||||
<Tab
|
||||
tabs={[{
|
||||
name: 'console',
|
||||
view: <Console />,
|
||||
}, {
|
||||
name: 'network',
|
||||
view: <Requests />,
|
||||
}]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default DevTool;
|
||||
43
lib/src/components/data/Log.js
Normal file
43
lib/src/components/data/Log.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Component } from 'react';
|
||||
import log from '../../log';
|
||||
|
||||
class Log extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
logs: [],
|
||||
};
|
||||
this.addLog = this.addLog.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
log.listen(this.addLog);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
log.unlisten(this.addLog);
|
||||
}
|
||||
|
||||
addLog(entry) {
|
||||
entry = Array.isArray(entry) ? entry : [entry];
|
||||
const logs = [
|
||||
...this.state.logs,
|
||||
...entry,
|
||||
];
|
||||
this.setState({
|
||||
logs,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
} = this.props;
|
||||
const component = children(
|
||||
this.state,
|
||||
);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
export default Log;
|
||||
43
lib/src/components/data/Network.js
Normal file
43
lib/src/components/data/Network.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Component } from 'react';
|
||||
import network from '../../network';
|
||||
|
||||
class Network extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
requests: [],
|
||||
};
|
||||
this.addRequest = this.addRequest.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
network.listen(this.addRequest);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
network.unlisten(this.addRequest);
|
||||
}
|
||||
|
||||
addRequest(request) {
|
||||
request = Array.isArray(request) ? request : [request];
|
||||
const requests = [
|
||||
...this.state.requests,
|
||||
...request,
|
||||
];
|
||||
this.setState({
|
||||
requests,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
} = this.props;
|
||||
const component = children(
|
||||
this.state,
|
||||
);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
export default Network;
|
||||
20
lib/src/components/data/State.js
Normal file
20
lib/src/components/data/State.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class State extends Component {
|
||||
constructor(props, ...others) {
|
||||
super(props, ...others);
|
||||
this.state = props.initState || {};
|
||||
this.setState = this.setState.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const component = children(
|
||||
this.state,
|
||||
this.setState,
|
||||
);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
export default State;
|
||||
21
lib/src/events.js
Normal file
21
lib/src/events.js
Normal file
@@ -0,0 +1,21 @@
|
||||
class Events {
|
||||
constructor() {
|
||||
this.listeners = [];
|
||||
}
|
||||
|
||||
listen(fn) {
|
||||
this.listeners.push(fn);
|
||||
}
|
||||
|
||||
unlisten(fn) {
|
||||
this.listeners = this.listeners(l => l !== fn);
|
||||
}
|
||||
|
||||
publish(type, data) {
|
||||
this.listeners.forEach(l => l(type, data));
|
||||
}
|
||||
}
|
||||
|
||||
const events = new Events();
|
||||
|
||||
export default events;
|
||||
17
lib/src/index.js
Normal file
17
lib/src/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import DevTool from './components/DevTool/index';
|
||||
import DevToolModal from './components/DevTool/Modal';
|
||||
import log from './log';
|
||||
import network from './network';
|
||||
import events from './events';
|
||||
|
||||
const show = () => events.publish('SHOW_DEVTOOLS');
|
||||
const hide = () => events.publish('HIDE_DEVTOOLS');
|
||||
|
||||
export {
|
||||
DevTool,
|
||||
DevToolModal,
|
||||
log,
|
||||
network,
|
||||
show,
|
||||
hide,
|
||||
};
|
||||
74
lib/src/log.js
Normal file
74
lib/src/log.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/* const overrides = [
|
||||
'log',
|
||||
];
|
||||
|
||||
const proxies = overrides.reduce((output, key) => ({
|
||||
...output,
|
||||
[key]: window.console[key],
|
||||
}), {}); */
|
||||
|
||||
const proxyConsole = window.console;
|
||||
|
||||
class Log {
|
||||
constructor() {
|
||||
this.logs = [];
|
||||
this.listeners = [];
|
||||
}
|
||||
|
||||
listen(fn) {
|
||||
this.listeners.push(fn);
|
||||
fn(this.logs);
|
||||
}
|
||||
|
||||
unlisten(fn) {
|
||||
this.listeners = this.listeners.filter(l => l !== fn);
|
||||
}
|
||||
|
||||
log(type, data) {
|
||||
const entry = {
|
||||
type,
|
||||
data,
|
||||
};
|
||||
this.logs.push(entry);
|
||||
this.listeners.forEach(l => l(entry));
|
||||
}
|
||||
|
||||
info(data) {
|
||||
this.log('info', data);
|
||||
}
|
||||
|
||||
error(error) {
|
||||
this.log('error', error);
|
||||
}
|
||||
|
||||
warn(data) {
|
||||
this.log('warn', data);
|
||||
}
|
||||
|
||||
debug(data) {
|
||||
this.log('debug', data);
|
||||
}
|
||||
|
||||
attach(keep) {
|
||||
window.console = {
|
||||
error: (...data) => this.error(...data),
|
||||
warn: (data) => this.warn(data),
|
||||
info: (data) => this.info(data),
|
||||
log: (data) => this.info(data),
|
||||
debug: (data) => this.debug(data),
|
||||
};
|
||||
ErrorUtils.setGlobalHandler((err, fatal) => {
|
||||
this.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
detach() {
|
||||
overrides.forEach((key) => {
|
||||
window.console[key] = proxies[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const log = new Log();
|
||||
|
||||
export default log;
|
||||
66
lib/src/network.js
Normal file
66
lib/src/network.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const proxied = window.XMLHttpRequest.prototype.open;
|
||||
|
||||
class Network {
|
||||
constructor() {
|
||||
this.requests = [];
|
||||
this.listeners = [];
|
||||
}
|
||||
|
||||
listen(fn) {
|
||||
this.listeners.push(fn);
|
||||
fn(this.requests);
|
||||
}
|
||||
|
||||
unlisten(fn) {
|
||||
this.listeners = this.listeners.filter(l => l !== fn);
|
||||
}
|
||||
|
||||
addRequest(request) {
|
||||
this.requests.push(request);
|
||||
this.listeners.forEach(l => l(request));
|
||||
}
|
||||
|
||||
attach() {
|
||||
const me = this;
|
||||
window.XMLHttpRequest.prototype.open = function proxyOpen (...args) {
|
||||
let sendArgs;
|
||||
const [
|
||||
method,
|
||||
url,
|
||||
] = args;
|
||||
this.addEventListener('load', () => {
|
||||
me.addRequest({
|
||||
url,
|
||||
method,
|
||||
args: sendArgs,
|
||||
request: this,
|
||||
status: this.status,
|
||||
});
|
||||
})
|
||||
this.addEventListener('error', (error) => {
|
||||
me.addRequest({
|
||||
url,
|
||||
method,
|
||||
error,
|
||||
args: sendArgs,
|
||||
request: this,
|
||||
status: this.status || 'CONN ERR',
|
||||
});
|
||||
})
|
||||
const proxiedSend = this.send;
|
||||
this.send = function proxySend (...sendargs) {
|
||||
sendArgs = sendargs;
|
||||
return proxiedSend.apply(this, [].slice.call(arguments));
|
||||
}
|
||||
return proxied.apply(this, [].slice.call(arguments));
|
||||
};
|
||||
}
|
||||
|
||||
detach() {
|
||||
window.XMLHttpRequest.prototype.open = proxied;
|
||||
}
|
||||
}
|
||||
|
||||
const network = new Network();
|
||||
|
||||
export default network;
|
||||
221
lib/yarn.lock
Normal file
221
lib/yarn.lock
Normal file
@@ -0,0 +1,221 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
almost-equal@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/almost-equal/-/almost-equal-1.1.0.tgz#f851c631138757994276aa2efbe8dfa3066cccdd"
|
||||
|
||||
asap@~2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
|
||||
base16@Dean177/base16-js:
|
||||
version "1.0.1"
|
||||
resolved "https://codeload.github.com/Dean177/base16-js/tar.gz/6c5e5f3b63990b580ffdc036bc672f8987d5b93d"
|
||||
|
||||
base64-js@^1.0.2:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
||||
|
||||
buffer@^5.0.3:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.0.tgz#53cf98241100099e9eeae20ee6d51d21b16e541e"
|
||||
dependencies:
|
||||
base64-js "^1.0.2"
|
||||
ieee754 "^1.1.4"
|
||||
|
||||
color-space@^1.14.3:
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/color-space/-/color-space-1.16.0.tgz#611781bca41cd8582a1466fd9e28a7d3d89772a2"
|
||||
dependencies:
|
||||
hsluv "^0.0.3"
|
||||
mumath "^3.3.4"
|
||||
|
||||
core-js@^1.0.0:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
|
||||
css-to-react-native@^2.0.3:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.1.tgz#7f3f4c95de65501b8720c87bf0caf1f39073b88e"
|
||||
dependencies:
|
||||
css-color-keywords "^1.0.0"
|
||||
fbjs "^0.8.5"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
encoding@^0.1.11:
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
|
||||
dependencies:
|
||||
iconv-lite "~0.4.13"
|
||||
|
||||
fbjs@^0.8.16, fbjs@^0.8.5:
|
||||
version "0.8.17"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
isomorphic-fetch "^2.1.1"
|
||||
loose-envify "^1.0.0"
|
||||
object-assign "^4.1.0"
|
||||
promise "^7.1.1"
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.18"
|
||||
|
||||
has-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
|
||||
hoist-non-react-statics@^2.5.0:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
|
||||
|
||||
hsluv@^0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/hsluv/-/hsluv-0.0.3.tgz#829107dafb4a9f8b52a1809ed02e091eade6754c"
|
||||
|
||||
iconv-lite@~0.4.13:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.12"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
|
||||
|
||||
is-stream@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
isomorphic-fetch@^2.1.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
|
||||
dependencies:
|
||||
node-fetch "^1.0.1"
|
||||
whatwg-fetch ">=0.10.0"
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
|
||||
lodash.curry@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
|
||||
|
||||
lodash.flow@^3.3.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.3.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
mumath@^3.3.4:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/mumath/-/mumath-3.3.4.tgz#48d4a0f0fd8cad4e7b32096ee89b161a63d30bbf"
|
||||
dependencies:
|
||||
almost-equal "^1.1.0"
|
||||
|
||||
node-fetch@^1.0.1:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
||||
dependencies:
|
||||
encoding "^0.1.11"
|
||||
is-stream "^1.0.1"
|
||||
|
||||
object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
postcss-value-parser@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
|
||||
|
||||
promise@^7.1.1:
|
||||
version "7.3.1"
|
||||
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.5.4, prop-types@^15.6.0:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||
dependencies:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
pure-color@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
|
||||
|
||||
"react-base16-styling@github:dean177/react-base16-styling#fbc6593":
|
||||
version "0.4.6"
|
||||
resolved "https://codeload.github.com/dean177/react-base16-styling/tar.gz/fbc6593cc58c5f4662c40b85964c7f9fbcb3984d"
|
||||
dependencies:
|
||||
base16 Dean177/base16-js
|
||||
color-space "^1.14.3"
|
||||
lodash.curry "^4.0.1"
|
||||
lodash.flow "^3.3.0"
|
||||
pure-color "^1.2.0"
|
||||
|
||||
react-is@^16.3.1:
|
||||
version "16.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.2.tgz#84891b56c2b6d9efdee577cc83501dfc5ecead88"
|
||||
|
||||
react-native-json-tree@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-json-tree/-/react-native-json-tree-1.2.0.tgz#4600310bff1934026edbe77fc621230866fe7182"
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
react-base16-styling "github:dean177/react-base16-styling#fbc6593"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
|
||||
setimmediate@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||
|
||||
styled-components@^3.4.2:
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.4.2.tgz#8f518419932327e47fe9144824e3184b3e2da95d"
|
||||
dependencies:
|
||||
buffer "^5.0.3"
|
||||
css-to-react-native "^2.0.3"
|
||||
fbjs "^0.8.16"
|
||||
hoist-non-react-statics "^2.5.0"
|
||||
prop-types "^15.5.4"
|
||||
react-is "^16.3.1"
|
||||
stylis "^3.5.0"
|
||||
stylis-rule-sheet "^0.0.10"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
stylis-rule-sheet@^0.0.10:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
|
||||
|
||||
stylis@^3.5.0:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.3.tgz#99fdc46afba6af4deff570825994181a5e6ce546"
|
||||
|
||||
supports-color@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
ua-parser-js@^0.7.18:
|
||||
version "0.7.18"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
|
||||
|
||||
whatwg-fetch@>=0.10.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
|
||||
Reference in New Issue
Block a user