2016-07-11 13:05:51 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RCTJSStackFrame.h"
|
|
|
|
#import "RCTLog.h"
|
2016-08-26 16:47:25 +00:00
|
|
|
#import "RCTUtils.h"
|
2016-07-11 13:05:51 +00:00
|
|
|
|
|
|
|
static NSRegularExpression *RCTJSStackFrameRegex()
|
|
|
|
{
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
static NSRegularExpression *_regex;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
NSError *regexError;
|
|
|
|
_regex = [NSRegularExpression regularExpressionWithPattern:@"^([^@]+)@(.*):(\\d+):(\\d+)$" options:0 error:®exError];
|
|
|
|
if (regexError) {
|
|
|
|
RCTLogError(@"Failed to build regex: %@", [regexError localizedDescription]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return _regex;
|
|
|
|
}
|
|
|
|
|
|
|
|
@implementation RCTJSStackFrame
|
|
|
|
|
|
|
|
- (instancetype)initWithMethodName:(NSString *)methodName file:(NSString *)file lineNumber:(NSInteger)lineNumber column:(NSInteger)column
|
|
|
|
{
|
|
|
|
if (self = [super init]) {
|
|
|
|
_methodName = methodName;
|
|
|
|
_file = file;
|
|
|
|
_lineNumber = lineNumber;
|
|
|
|
_column = column;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)toDictionary
|
|
|
|
{
|
|
|
|
return @{
|
2016-08-26 16:47:25 +00:00
|
|
|
@"methodName": RCTNullIfNil(self.methodName),
|
|
|
|
@"file": RCTNullIfNil(self.file),
|
|
|
|
@"lineNumber": @(self.lineNumber),
|
|
|
|
@"column": @(self.column)
|
|
|
|
};
|
2016-07-11 13:05:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (instancetype)stackFrameWithLine:(NSString *)line
|
|
|
|
{
|
|
|
|
NSTextCheckingResult *match = [RCTJSStackFrameRegex() firstMatchInString:line options:0 range:NSMakeRange(0, line.length)];
|
|
|
|
if (!match) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *methodName = [line substringWithRange:[match rangeAtIndex:1]];
|
|
|
|
NSString *file = [line substringWithRange:[match rangeAtIndex:2]];
|
|
|
|
NSString *lineNumber = [line substringWithRange:[match rangeAtIndex:3]];
|
|
|
|
NSString *column = [line substringWithRange:[match rangeAtIndex:4]];
|
|
|
|
|
|
|
|
return [[self alloc] initWithMethodName:methodName
|
|
|
|
file:file
|
|
|
|
lineNumber:[lineNumber integerValue]
|
|
|
|
column:[column integerValue]];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (instancetype)stackFrameWithDictionary:(NSDictionary *)dict
|
|
|
|
{
|
|
|
|
return [[self alloc] initWithMethodName:dict[@"methodName"]
|
|
|
|
file:dict[@"file"]
|
|
|
|
lineNumber:[dict[@"lineNumber"] integerValue]
|
|
|
|
column:[dict[@"column"] integerValue]];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithLines:(NSString *)lines
|
|
|
|
{
|
|
|
|
NSMutableArray *stack = [NSMutableArray new];
|
|
|
|
for (NSString *line in [lines componentsSeparatedByString:@"\n"]) {
|
|
|
|
RCTJSStackFrame *frame = [self stackFrameWithLine:line];
|
|
|
|
if (frame) {
|
|
|
|
[stack addObject:frame];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithDictionaries:(NSArray<NSDictionary *> *)dicts
|
|
|
|
{
|
|
|
|
NSMutableArray *stack = [NSMutableArray new];
|
|
|
|
for (NSDictionary *dict in dicts) {
|
|
|
|
RCTJSStackFrame *frame = [self stackFrameWithDictionary:dict];
|
|
|
|
if (frame) {
|
|
|
|
[stack addObject:frame];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|