diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK index 1a8a4f6ac..b3a6aaf95 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK @@ -15,5 +15,6 @@ android_library( react_native_target("java/com/facebook/react/devsupport:interfaces"), react_native_target("java/com/facebook/react/jstasks:jstasks"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/util:util"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java index b92d22ad7..af6e133e5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java @@ -9,26 +9,21 @@ package com.facebook.react.modules.core; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import com.facebook.common.logging.FLog; import com.facebook.react.bridge.BaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableType; -import com.facebook.react.devsupport.interfaces.DevSupportManager; import com.facebook.react.common.JavascriptException; import com.facebook.react.common.ReactConstants; +import com.facebook.react.devsupport.interfaces.DevSupportManager; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.util.JSStackTrace; @ReactModule(name = ExceptionsManagerModule.NAME) public class ExceptionsManagerModule extends BaseJavaModule { protected static final String NAME = "ExceptionsManager"; - static private final Pattern mJsModuleIdPattern = Pattern.compile("(?:^|[/\\\\])(\\d+\\.js)$"); private final DevSupportManager mDevSupportManager; public ExceptionsManagerModule(DevSupportManager devSupportManager) { @@ -40,44 +35,6 @@ public class ExceptionsManagerModule extends BaseJavaModule { return NAME; } - // If the file name of a stack frame is numeric (+ ".js"), we assume it's a lazily injected module - // coming from a "random access bundle". We are using special source maps for these bundles, so - // that we can symbolicate stack traces for multiple injected files with a single source map. - // We have to include the module id in the stack for that, though. The ".js" suffix is kept to - // avoid ambiguities between "module-id:line" and "line:column". - static private String stackFrameToModuleId(ReadableMap frame) { - if (frame.hasKey("file") && - !frame.isNull("file") && - frame.getType("file") == ReadableType.String) { - final Matcher matcher = mJsModuleIdPattern.matcher(frame.getString("file")); - if (matcher.find()) { - return matcher.group(1) + ":"; - } - } - return ""; - } - - private String stackTraceToString(String message, ReadableArray stack) { - StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n"); - for (int i = 0; i < stack.size(); i++) { - ReadableMap frame = stack.getMap(i); - stringBuilder - .append(frame.getString("methodName")) - .append("@") - .append(stackFrameToModuleId(frame)) - .append(frame.getInt("lineNumber")); - if (frame.hasKey("column") && - !frame.isNull("column") && - frame.getType("column") == ReadableType.Number) { - stringBuilder - .append(":") - .append(frame.getInt("column")); - } - stringBuilder.append("\n"); - } - return stringBuilder.toString(); - } - @ReactMethod public void reportFatalException(String title, ReadableArray details, int exceptionId) { showOrThrowError(title, details, exceptionId); @@ -88,7 +45,7 @@ public class ExceptionsManagerModule extends BaseJavaModule { if (mDevSupportManager.getDevSupportEnabled()) { mDevSupportManager.showNewJSError(title, details, exceptionId); } else { - FLog.e(ReactConstants.TAG, stackTraceToString(title, details)); + FLog.e(ReactConstants.TAG, JSStackTrace.format(title, details)); } } @@ -96,7 +53,7 @@ public class ExceptionsManagerModule extends BaseJavaModule { if (mDevSupportManager.getDevSupportEnabled()) { mDevSupportManager.showNewJSError(title, details, exceptionId); } else { - throw new JavascriptException(stackTraceToString(title, details)); + throw new JavascriptException(JSStackTrace.format(title, details)); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/util/BUCK b/ReactAndroid/src/main/java/com/facebook/react/util/BUCK new file mode 100644 index 000000000..a159d59dd --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/util/BUCK @@ -0,0 +1,12 @@ +include_defs("//ReactAndroid/DEFS") + +android_library( + name = "util", + srcs = glob(["**/*.java"]), + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_target("java/com/facebook/react/bridge:bridge"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java b/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java new file mode 100644 index 000000000..d3ebe6132 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2017-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. + */ +package com.facebook.react.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; + +public class JSStackTrace { + + final private static Pattern mJsModuleIdPattern = Pattern.compile("(?:^|[/\\\\])(\\d+\\.js)$"); + + public static String format(String message, ReadableArray stack) { + StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n"); + for (int i = 0; i < stack.size(); i++) { + ReadableMap frame = stack.getMap(i); + stringBuilder + .append(frame.getString("methodName")) + .append("@") + .append(stackFrameToModuleId(frame)) + .append(frame.getInt("lineNumber")); + if (frame.hasKey("column") && + !frame.isNull("column") && + frame.getType("column") == ReadableType.Number) { + stringBuilder + .append(":") + .append(frame.getInt("column")); + } + stringBuilder.append("\n"); + } + return stringBuilder.toString(); + } + + // If the file name of a stack frame is numeric (+ ".js"), we assume it's a lazily injected module + // coming from a "random access bundle". We are using special source maps for these bundles, so + // that we can symbolicate stack traces for multiple injected files with a single source map. + // We have to include the module id in the stack for that, though. The ".js" suffix is kept to + // avoid ambiguities between "module-id:line" and "line:column". + private static String stackFrameToModuleId(ReadableMap frame) { + if (frame.hasKey("file") && + !frame.isNull("file") && + frame.getType("file") == ReadableType.String) { + final Matcher matcher = mJsModuleIdPattern.matcher(frame.getString("file")); + if (matcher.find()) { + return matcher.group(1) + ":"; + } + } + return ""; + } +}