From b108b170dc06294c6b10f318314ac21660530273 Mon Sep 17 00:00:00 2001 From: Sokovikov Date: Tue, 3 May 2016 10:54:31 +0300 Subject: [PATCH] show code line in warning --- .../__mocks__/SourceMapsCache.js | 19 +++++++++++ .../__mocks__/parseErrorStack.js | 22 ++++++++++++ .../__tests__/exceptionOccurHint-test.js | 22 ++++++++++++ .../Initialization/exceptionOccurHint.js | 34 +++++++++++++++++++ Libraries/ReactIOS/YellowBox.js | 34 +++++++++++++++---- 5 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 Libraries/JavaScriptAppEngine/Initialization/__mocks__/SourceMapsCache.js create mode 100644 Libraries/JavaScriptAppEngine/Initialization/__mocks__/parseErrorStack.js create mode 100644 Libraries/JavaScriptAppEngine/Initialization/__tests__/exceptionOccurHint-test.js create mode 100644 Libraries/JavaScriptAppEngine/Initialization/exceptionOccurHint.js diff --git a/Libraries/JavaScriptAppEngine/Initialization/__mocks__/SourceMapsCache.js b/Libraries/JavaScriptAppEngine/Initialization/__mocks__/SourceMapsCache.js new file mode 100644 index 000000000000..665283eff78f --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/__mocks__/SourceMapsCache.js @@ -0,0 +1,19 @@ +/** + * 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. + */ +'use strict'; + +const SourceMapsCache = jest.genMockFromModule('SourceMapsCache'); + +var getSourceMaps = jest.genMockFunction(); +const promise = new Promise((resolve, reject) => resolve({})); + +getSourceMaps.mockReturnValue(promise); +SourceMapsCache.getSourceMaps = getSourceMaps; + +module.exports = SourceMapsCache; diff --git a/Libraries/JavaScriptAppEngine/Initialization/__mocks__/parseErrorStack.js b/Libraries/JavaScriptAppEngine/Initialization/__mocks__/parseErrorStack.js new file mode 100644 index 000000000000..7ca670559d4d --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/__mocks__/parseErrorStack.js @@ -0,0 +1,22 @@ +/** + * 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. + */ +'use strict'; + +const parseErrorStack = jest.genMockFunction(); + +const frame = [{ + file: '/Examples/UIExplorer/ViewExample.js', + methodName: 'Constructor.render', + lineNumber: 42, + column: 0 +}]; + +parseErrorStack.mockReturnValue(frame); + +module.exports = parseErrorStack; diff --git a/Libraries/JavaScriptAppEngine/Initialization/__tests__/exceptionOccurHint-test.js b/Libraries/JavaScriptAppEngine/Initialization/__tests__/exceptionOccurHint-test.js new file mode 100644 index 000000000000..9155efdb68fd --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/__tests__/exceptionOccurHint-test.js @@ -0,0 +1,22 @@ +/** + * 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. + */ +'use strict'; + +jest.unmock('../exceptionOccurHint'); + +const exceptionOccurHint = require('exceptionOccurHint'); + +describe('exceptionOccurHint', () => { + + pit('give a hint', () => { + return exceptionOccurHint().then(hint => { + expect(hint).toEqual('At: ViewExample.js:42'); + }); + }); +}); diff --git a/Libraries/JavaScriptAppEngine/Initialization/exceptionOccurHint.js b/Libraries/JavaScriptAppEngine/Initialization/exceptionOccurHint.js new file mode 100644 index 000000000000..438a4a86a4c8 --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/exceptionOccurHint.js @@ -0,0 +1,34 @@ +/** + * 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. + * + * @providesModule exceptionOccurHint + */ + +'use strict'; + +const SourceMapsCache = require('SourceMapsCache'); +const parseErrorStack = require('parseErrorStack'); + +function exceptionOccurHint() { + const stack = parseErrorStack(new Error()); + const renderFrame = stack.find((frame) => frame.methodName.endsWith('render')); + + if (renderFrame) { + return SourceMapsCache.getSourceMaps().then(sourceMaps => { + const prettyStack = parseErrorStack({stack: [renderFrame]}, sourceMaps); + const prettyFrame = prettyStack[0]; + const fileParts = prettyFrame.file.split('/'); + const fileName = fileParts[fileParts.length - 1]; + return `At: ${fileName }:${prettyFrame.lineNumber}`; + }); + } else { + return new Promise((resolve, reject) => resolve(null)); + } +} + +module.exports = exceptionOccurHint; diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js index 3aa51d537c82..d31c0a2165a7 100644 --- a/Libraries/ReactIOS/YellowBox.js +++ b/Libraries/ReactIOS/YellowBox.js @@ -17,6 +17,7 @@ import type EmitterSubscription from 'EmitterSubscription'; const Platform = require('Platform'); const React = require('React'); const StyleSheet = require('StyleSheet'); +const exceptionOccurHint = require('exceptionOccurHint'); const _warningEmitter = new EventEmitter(); const _warningMap = new Map(); @@ -82,9 +83,23 @@ function updateWarningMap(format, ...args): void { ...args.slice(argCount).map(stringifySafe), ].join(' '); - const count = _warningMap.has(warning) ? _warningMap.get(warning) : 0; - _warningMap.set(warning, count + 1); + var warningInfo = _warningMap.get(warning); + if (warningInfo) { + warningInfo.count += 1; + } else { + warningInfo = {count: 1, frame: ''}; + } + + _warningMap.set(warning, warningInfo); _warningEmitter.emit('warning', _warningMap); + + exceptionOccurHint().then((frame) => { + warningInfo = _warningMap.get(warning); + if (warningInfo && frame) { + warningInfo.frame = frame; + _warningEmitter.emit('warning', _warningMap); + } + }); } function isWarningIgnored(warning: string): boolean { @@ -123,6 +138,7 @@ const WarningRow = ({count, warning, onPress}) => { const WarningInspector = ({ count, + frame, warning, onClose, onDismiss, @@ -145,6 +161,7 @@ const WarningInspector = ({ {countSentence} + {frame} {warning} @@ -230,9 +247,12 @@ class YellowBox extends React.Component { const View = require('View'); const inspecting = this.state.inspecting; - const inspector = inspecting !== null ? + const inspectingWarningInfo = this.state.warningMap.get(inspecting); + + const inspector = inspecting !== null && inspectingWarningInfo !== null ? this.setState({inspecting: null})} onDismiss={() => this.dismissWarning(inspecting)} @@ -241,12 +261,12 @@ class YellowBox extends React.Component { null; const rows = []; - this.state.warningMap.forEach((count, warning) => { + this.state.warningMap.forEach((warningInfo, warning) => { if (!isWarningIgnored(warning)) { rows.push( this.setState({inspecting: warning})} onDismiss={() => this.dismissWarning(warning)} @@ -324,7 +344,7 @@ var styles = StyleSheet.create({ inspectorWarning: { padding: 15, position: 'absolute', - top: 39, + top: 50, bottom: 60, }, inspectorWarningText: {