mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 23:40:23 +00:00
Changed error handling so that better stack traces are displayed in the ng-errors
This commit is contained in:
parent
4af32de84a
commit
b2d63ac48b
14 changed files with 144 additions and 102 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet editPageId="org.eclipse.ui.resourceWorkingSetPage" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1262905463390_2" label="workingSet" name="workingSet"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/test" type="2"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/src" type="2"/> </launchConfigurationWorkingSet>}"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet editPageId="org.eclipse.ui.resourceWorkingSetPage" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1262905463390_2" label="workingSet" name="workingSet"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/test" type="2"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/src" type="2"/> </launchConfigurationWorkingSet>}"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/build" type="2"/> </resources>}"/>
|
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/build" type="2"/> </resources>}"/>
|
||||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
border: 2px solid #FF0000;
|
border: 2px solid #FF0000;
|
||||||
font-family: "Courier New", Courier, monospace;
|
font-family: "Courier New", Courier, monospace;
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ng-validation-error {
|
.ng-validation-error {
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ var _undefined = undefined,
|
||||||
PRIORITY_WATCH = -1000,
|
PRIORITY_WATCH = -1000,
|
||||||
PRIORITY_LAST = 99999,
|
PRIORITY_LAST = 99999,
|
||||||
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
|
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
|
||||||
|
Error = window.Error,
|
||||||
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
|
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
|
||||||
_ = window['_'],
|
_ = window['_'],
|
||||||
/** holds major version number for IE or NaN for real browsers */
|
/** holds major version number for IE or NaN for real browsers */
|
||||||
|
|
@ -557,6 +558,18 @@ function foreachSorted(obj, iterator, context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatError(arg) {
|
||||||
|
if (arg instanceof Error) {
|
||||||
|
if (arg.stack) {
|
||||||
|
arg = arg.stack;
|
||||||
|
} else if (arg.sourceURL) {
|
||||||
|
arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function extend(dst) {
|
function extend(dst) {
|
||||||
foreach(arguments, function(obj){
|
foreach(arguments, function(obj){
|
||||||
if (obj !== dst) {
|
if (obj !== dst) {
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ function expressionCompile(exp){
|
||||||
}
|
}
|
||||||
|
|
||||||
function errorHandlerFor(element, error) {
|
function errorHandlerFor(element, error) {
|
||||||
elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error);
|
elementError(element, NG_EXCEPTION, isDefined(error) ? formatError(error) : error);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createScope(parent, providers, instanceCache) {
|
function createScope(parent, providers, instanceCache) {
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ angularDirective("ng:bind", function(expression, element){
|
||||||
oldElement = this.hasOwnProperty($$element) ? this.$element : _undefined;
|
oldElement = this.hasOwnProperty($$element) ? this.$element : _undefined;
|
||||||
this.$element = element;
|
this.$element = element;
|
||||||
value = this.$tryEval(expression, function(e){
|
value = this.$tryEval(expression, function(e){
|
||||||
error = toJson(e);
|
error = formatError(e);
|
||||||
});
|
});
|
||||||
this.$element = oldElement;
|
this.$element = oldElement;
|
||||||
// If we are HTML than save the raw HTML data so that we don't
|
// If we are HTML than save the raw HTML data so that we don't
|
||||||
|
|
@ -466,15 +466,15 @@ angularWidget("@ng:repeat", function(expression, element){
|
||||||
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
|
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
|
||||||
lhs, rhs, valueIdent, keyIdent;
|
lhs, rhs, valueIdent, keyIdent;
|
||||||
if (! match) {
|
if (! match) {
|
||||||
throw "Expected ng:repeat in form of 'item in collection' but got '" +
|
throw Error("Expected ng:repeat in form of 'item in collection' but got '" +
|
||||||
expression + "'.";
|
expression + "'.");
|
||||||
}
|
}
|
||||||
lhs = match[1];
|
lhs = match[1];
|
||||||
rhs = match[2];
|
rhs = match[2];
|
||||||
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
|
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw "'item' in 'item in collection' should be identifier or (key, value) but got '" +
|
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
|
||||||
keyValue + "'.";
|
keyValue + "'.");
|
||||||
}
|
}
|
||||||
valueIdent = match[3] || match[1];
|
valueIdent = match[3] || match[1];
|
||||||
keyIdent = match[2];
|
keyIdent = match[2];
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,7 @@ function lex(text, parseStringsForObjects){
|
||||||
tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
|
tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
|
||||||
index += 1;
|
index += 1;
|
||||||
} else {
|
} else {
|
||||||
throw "Lexer Error: Unexpected next character [" +
|
throwError("Unexpected next character ", index, index+1);
|
||||||
text.substring(index) +
|
|
||||||
"] in expression '" + text +
|
|
||||||
"' at column '" + (index+1) + "'.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastCh = ch;
|
lastCh = ch;
|
||||||
|
|
@ -103,6 +100,16 @@ function lex(text, parseStringsForObjects){
|
||||||
function isExpOperator(ch) {
|
function isExpOperator(ch) {
|
||||||
return ch == '-' || ch == '+' || isNumber(ch);
|
return ch == '-' || ch == '+' || isNumber(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function throwError(error, start, end) {
|
||||||
|
end = end || index;
|
||||||
|
throw Error("Lexer Error: " + error + " at column" +
|
||||||
|
(isDefined(start) ?
|
||||||
|
"s " + start + "-" + index + " [" + text.substring(start, end) + "]" :
|
||||||
|
" " + end) +
|
||||||
|
" in expression [" + text + "].");
|
||||||
|
}
|
||||||
|
|
||||||
function readNumber() {
|
function readNumber() {
|
||||||
var number = "";
|
var number = "";
|
||||||
var start = index;
|
var start = index;
|
||||||
|
|
@ -121,7 +128,7 @@ function lex(text, parseStringsForObjects){
|
||||||
} else if (isExpOperator(ch) &&
|
} else if (isExpOperator(ch) &&
|
||||||
(!peekCh || !isNumber(peekCh)) &&
|
(!peekCh || !isNumber(peekCh)) &&
|
||||||
number.charAt(number.length - 1) == 'e') {
|
number.charAt(number.length - 1) == 'e') {
|
||||||
throw 'Lexer found invalid exponential value "' + text + '"';
|
throwError('Invalid exponent');
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +158,7 @@ function lex(text, parseStringsForObjects){
|
||||||
}
|
}
|
||||||
tokens.push({index:start, text:ident, fn:fn, json: OPERATORS[ident]});
|
tokens.push({index:start, text:ident, fn:fn, json: OPERATORS[ident]});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readString(quote) {
|
function readString(quote) {
|
||||||
var start = index;
|
var start = index;
|
||||||
index++;
|
index++;
|
||||||
|
|
@ -165,9 +172,7 @@ function lex(text, parseStringsForObjects){
|
||||||
if (ch == 'u') {
|
if (ch == 'u') {
|
||||||
var hex = text.substring(index + 1, index + 5);
|
var hex = text.substring(index + 1, index + 5);
|
||||||
if (!hex.match(/[\da-f]{4}/i))
|
if (!hex.match(/[\da-f]{4}/i))
|
||||||
throw "Lexer Error: Invalid unicode escape [\\u" +
|
throwError( "Invalid unicode escape [\\u" + hex + "]");
|
||||||
hex + "] starting at column '" +
|
|
||||||
start + "' in expression '" + text + "'.";
|
|
||||||
index += 4;
|
index += 4;
|
||||||
string += String.fromCharCode(parseInt(hex, 16));
|
string += String.fromCharCode(parseInt(hex, 16));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -194,9 +199,7 @@ function lex(text, parseStringsForObjects){
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
throw "Lexer Error: Unterminated quote [" +
|
throwError("Unterminated quote", start);
|
||||||
text.substring(start) + "] starting at column '" +
|
|
||||||
(start+1) + "' in expression '" + text + "'.";
|
|
||||||
}
|
}
|
||||||
function readRegexp(quote) {
|
function readRegexp(quote) {
|
||||||
var start = index;
|
var start = index;
|
||||||
|
|
@ -227,9 +230,7 @@ function lex(text, parseStringsForObjects){
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
throw "Lexer Error: Unterminated RegExp [" +
|
throwError("Unterminated RegExp", start);
|
||||||
text.substring(start) + "] starting at column '" +
|
|
||||||
(start+1) + "' in expression '" + text + "'.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,17 +250,16 @@ function parser(text, json){
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
function throwError(msg, token) {
|
||||||
function error(msg, token) {
|
throw Error("Parse Error: Token '" + token.text +
|
||||||
throw "Token '" + token.text +
|
"' " + msg + " at column " +
|
||||||
"' is " + msg + " at column='" +
|
(token.index + 1) + " of expression [" +
|
||||||
(token.index + 1) + "' of expression '" +
|
text + "] starting at [" + text.substring(token.index) + "].");
|
||||||
text + "' starting at '" + text.substring(token.index) + "'.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function peekToken() {
|
function peekToken() {
|
||||||
if (tokens.length === 0)
|
if (tokens.length === 0)
|
||||||
throw "Unexpected end of expression: " + text;
|
throw Error("Unexpected end of expression: " + text);
|
||||||
return tokens[0];
|
return tokens[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,10 +280,7 @@ function parser(text, json){
|
||||||
if (token) {
|
if (token) {
|
||||||
if (json && !token.json) {
|
if (json && !token.json) {
|
||||||
index = token.index;
|
index = token.index;
|
||||||
throw "Expression at column='" +
|
throwError("is not valid json", token);
|
||||||
token.index + "' of expression '" +
|
|
||||||
text + "' starting at '" + text.substring(token.index) +
|
|
||||||
"' is not valid json.";
|
|
||||||
}
|
}
|
||||||
tokens.shift();
|
tokens.shift();
|
||||||
this.currentToken = token;
|
this.currentToken = token;
|
||||||
|
|
@ -294,11 +291,7 @@ function parser(text, json){
|
||||||
|
|
||||||
function consume(e1){
|
function consume(e1){
|
||||||
if (!expect(e1)) {
|
if (!expect(e1)) {
|
||||||
var token = peek();
|
throwError("is unexpected, expecting [" + e1 + "]", peek());
|
||||||
throw "Expecting '" + e1 + "' at column '" +
|
|
||||||
(token.index+1) + "' in '" +
|
|
||||||
text + "' got '" +
|
|
||||||
text.substring(token.index) + "'.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,8 +313,7 @@ function parser(text, json){
|
||||||
|
|
||||||
function assertAllConsumed(){
|
function assertAllConsumed(){
|
||||||
if (tokens.length !== 0) {
|
if (tokens.length !== 0) {
|
||||||
throw "Did not understand '" + text.substring(tokens[0].index) +
|
throwError("is extra token not part of expression", tokens[0]);
|
||||||
"' while evaluating '" + text + "'.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,18 +379,7 @@ function parser(text, json){
|
||||||
}
|
}
|
||||||
|
|
||||||
function expression(){
|
function expression(){
|
||||||
return throwStmt();
|
return assignment();
|
||||||
}
|
|
||||||
|
|
||||||
function throwStmt(){
|
|
||||||
if (expect('throw')) {
|
|
||||||
var throwExp = assignment();
|
|
||||||
return function (self) {
|
|
||||||
throw throwExp(self);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return assignment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignment(){
|
function assignment(){
|
||||||
|
|
@ -406,9 +387,8 @@ function parser(text, json){
|
||||||
var token;
|
var token;
|
||||||
if (token = expect('=')) {
|
if (token = expect('=')) {
|
||||||
if (!left.isAssignable) {
|
if (!left.isAssignable) {
|
||||||
throw "Left hand side '" +
|
throwError("implies assignment but [" +
|
||||||
text.substring(0, token.index) + "' of assignment '" +
|
text.substring(0, token.index) + "] can not be assigned to", token);
|
||||||
text.substring(token.index) + "' is not assignable.";
|
|
||||||
}
|
}
|
||||||
var ident = function(){return left.isAssignable;};
|
var ident = function(){return left.isAssignable;};
|
||||||
return binaryFn(ident, token.fn, logicalOR());
|
return binaryFn(ident, token.fn, logicalOR());
|
||||||
|
|
@ -498,8 +478,7 @@ function parser(text, json){
|
||||||
instance = instance[key];
|
instance = instance[key];
|
||||||
}
|
}
|
||||||
if (typeof instance != $function) {
|
if (typeof instance != $function) {
|
||||||
throw "Function '" + token.text + "' at column '" +
|
throwError("should be a function", token);
|
||||||
(token.index+1) + "' in '" + text + "' is not defined.";
|
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
@ -518,7 +497,7 @@ function parser(text, json){
|
||||||
var token = expect();
|
var token = expect();
|
||||||
primary = token.fn;
|
primary = token.fn;
|
||||||
if (!primary) {
|
if (!primary) {
|
||||||
error("not a primary expression", token);
|
throwError("not a primary expression", token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var next;
|
var next;
|
||||||
|
|
@ -530,7 +509,7 @@ function parser(text, json){
|
||||||
} else if (next.text === '.') {
|
} else if (next.text === '.') {
|
||||||
primary = fieldAccess(primary);
|
primary = fieldAccess(primary);
|
||||||
} else {
|
} else {
|
||||||
throw "IMPOSSIBLE";
|
throwError("IMPOSSIBLE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return primary;
|
return primary;
|
||||||
|
|
|
||||||
|
|
@ -311,8 +311,6 @@ angularServiceInject("$location", function(browser) {
|
||||||
<button ng:click="$log.error(message)">error</button>
|
<button ng:click="$log.error(message)">error</button>
|
||||||
*/
|
*/
|
||||||
angularServiceInject("$log", function($window){
|
angularServiceInject("$log", function($window){
|
||||||
var console = $window.console || {log: noop, warn: noop, info: noop, error: noop},
|
|
||||||
log = console.log || noop;
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
|
|
@ -322,7 +320,7 @@ angularServiceInject("$log", function($window){
|
||||||
* @description
|
* @description
|
||||||
* Write a log message
|
* Write a log message
|
||||||
*/
|
*/
|
||||||
log: bind(console, log),
|
log: consoleLog('log'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
|
|
@ -332,7 +330,7 @@ angularServiceInject("$log", function($window){
|
||||||
* @description
|
* @description
|
||||||
* Write a warning message
|
* Write a warning message
|
||||||
*/
|
*/
|
||||||
warn: bind(console, console.warn || log),
|
warn: consoleLog('warn'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
|
|
@ -342,7 +340,7 @@ angularServiceInject("$log", function($window){
|
||||||
* @description
|
* @description
|
||||||
* Write an information message
|
* Write an information message
|
||||||
*/
|
*/
|
||||||
info: bind(console, console.info || log),
|
info: consoleLog('info'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
|
|
@ -352,8 +350,25 @@ angularServiceInject("$log", function($window){
|
||||||
* @description
|
* @description
|
||||||
* Write an error message
|
* Write an error message
|
||||||
*/
|
*/
|
||||||
error: bind(console, console.error || log)
|
error: consoleLog('error')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function consoleLog(type) {
|
||||||
|
var console = $window.console || {};
|
||||||
|
var logFn = console[type] || console.log || noop;
|
||||||
|
if (logFn.apply) {
|
||||||
|
return function(){
|
||||||
|
var args = [];
|
||||||
|
foreach(arguments, function(arg){
|
||||||
|
args.push(formatError(arg));
|
||||||
|
});
|
||||||
|
return logFn.apply(console, args);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// we are IE, in which case there is nothing we can do
|
||||||
|
return logFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
}, ['$window'], EAGER_PUBLISHED);
|
}, ['$window'], EAGER_PUBLISHED);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -276,15 +276,15 @@ BinderTest.prototype.testIfTextBindingThrowsErrorDecorateTheSpan = function(){
|
||||||
a.scope.$eval();
|
a.scope.$eval();
|
||||||
var span = childNode(doc, 0);
|
var span = childNode(doc, 0);
|
||||||
assertTrue(span.hasClass('ng-exception'));
|
assertTrue(span.hasClass('ng-exception'));
|
||||||
assertEquals('ErrorMsg1', fromJson(span.text()));
|
assertTrue(!!span.text().match(/ErrorMsg1/));
|
||||||
assertEquals('"ErrorMsg1"', span.attr('ng-exception'));
|
assertTrue(!!span.attr('ng-exception').match(/ErrorMsg1/));
|
||||||
|
|
||||||
a.scope.$set('error.throw', function(){throw "MyError";});
|
a.scope.$set('error.throw', function(){throw "MyError";});
|
||||||
a.scope.$eval();
|
a.scope.$eval();
|
||||||
span = childNode(doc, 0);
|
span = childNode(doc, 0);
|
||||||
assertTrue(span.hasClass('ng-exception'));
|
assertTrue(span.hasClass('ng-exception'));
|
||||||
assertTrue(span.text(), span.text().match('MyError') !== null);
|
assertTrue(span.text(), span.text().match('MyError') !== null);
|
||||||
assertEquals('"MyError"', span.attr('ng-exception'));
|
assertEquals('MyError', span.attr('ng-exception'));
|
||||||
|
|
||||||
a.scope.$set('error.throw', function(){return "ok";});
|
a.scope.$set('error.throw', function(){return "ok";});
|
||||||
a.scope.$eval();
|
a.scope.$eval();
|
||||||
|
|
@ -438,13 +438,12 @@ BinderTest.prototype.testActionOnAHrefThrowsError = function(){
|
||||||
var model = {books:[]};
|
var model = {books:[]};
|
||||||
var c = this.compile('<a ng:click="action()">Add Phone</a>', model);
|
var c = this.compile('<a ng:click="action()">Add Phone</a>', model);
|
||||||
c.scope.action = function(){
|
c.scope.action = function(){
|
||||||
throw {a:'abc', b:2};
|
throw new Error('MyError');
|
||||||
};
|
};
|
||||||
var input = c.node;
|
var input = c.node;
|
||||||
browserTrigger(input, 'click');
|
browserTrigger(input, 'click');
|
||||||
var error = fromJson(input.attr('ng-exception'));
|
var error = input.attr('ng-exception');
|
||||||
assertEquals("abc", error.a);
|
assertTrue(!!error.match(/MyError/));
|
||||||
assertEquals(2, error.b);
|
|
||||||
assertTrue("should have an error class", input.hasClass('ng-exception'));
|
assertTrue("should have an error class", input.hasClass('ng-exception'));
|
||||||
|
|
||||||
// TODO: I think that exception should never get cleared so this portion of test makes no sense
|
// TODO: I think that exception should never get cleared so this portion of test makes no sense
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ describe('json', function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should serialize $ properties', function() {
|
it('should serialize $ properties', function() {
|
||||||
var obj = {$a: 'a'}
|
var obj = {$a: 'a'};
|
||||||
expect(angular.toJson(obj)).toEqual('{"$a":"a"}');
|
expect(angular.toJson(obj)).toEqual('{"$a":"a"}');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -118,31 +118,38 @@ describe('json', function(){
|
||||||
|
|
||||||
describe('security', function(){
|
describe('security', function(){
|
||||||
it('should not allow naked expressions', function(){
|
it('should not allow naked expressions', function(){
|
||||||
expect(function(){fromJson('1+2');}).toThrow("Did not understand '+2' while evaluating '1+2'.");
|
expect(function(){fromJson('1+2');}).
|
||||||
|
toThrow(new Error("Parse Error: Token '+' is extra token not part of expression at column 2 of expression [1+2] starting at [+2]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow naked expressions group', function(){
|
it('should not allow naked expressions group', function(){
|
||||||
expect(function(){fromJson('(1+2)');}).toThrow("Expression at column='0' of expression '(1+2)' starting at '(1+2)' is not valid json.");
|
expect(function(){fromJson('(1+2)');}).
|
||||||
|
toThrow(new Error("Parse Error: Token '(' is not valid json at column 1 of expression [(1+2)] starting at [(1+2)]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow expressions in objects', function(){
|
it('should not allow expressions in objects', function(){
|
||||||
expect(function(){fromJson('{a:abc()}');}).toThrow("Expression at column='3' of expression '{a:abc()}' starting at 'abc()}' is not valid json.");
|
expect(function(){fromJson('{a:abc()}');}).
|
||||||
|
toThrow(new Error("Parse Error: Token 'abc' is not valid json at column 4 of expression [{a:abc()}] starting at [abc()}]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow expressions in arrays', function(){
|
it('should not allow expressions in arrays', function(){
|
||||||
expect(function(){fromJson('[1+2]');}).toThrow("Expression at column='2' of expression '[1+2]' starting at '+2]' is not valid json.");
|
expect(function(){fromJson('[1+2]');}).
|
||||||
|
toThrow(new Error("Parse Error: Token '+' is not valid json at column 3 of expression [[1+2]] starting at [+2]]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow vars', function(){
|
it('should not allow vars', function(){
|
||||||
expect(function(){fromJson('[1, x]');}).toThrow("Expression at column='4' of expression '[1, x]' starting at 'x]' is not valid json.");
|
expect(function(){fromJson('[1, x]');}).
|
||||||
|
toThrow(new Error("Parse Error: Token 'x' is not valid json at column 5 of expression [[1, x]] starting at [x]]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow dereference', function(){
|
it('should not allow dereference', function(){
|
||||||
expect(function(){fromJson('["".constructor]');}).toThrow("Expression at column='3' of expression '[\"\".constructor]' starting at '.constructor]' is not valid json.");
|
expect(function(){fromJson('["".constructor]');}).
|
||||||
|
toThrow(new Error("Parse Error: Token '.' is not valid json at column 4 of expression [[\"\".constructor]] starting at [.constructor]]."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow expressions ofter valid json', function(){
|
it('should not allow expressions ofter valid json', function(){
|
||||||
expect(function(){fromJson('[].constructor');}).toThrow("Expression at column='2' of expression '[].constructor' starting at '.constructor' is not valid json.");
|
expect(function(){fromJson('[].constructor');}).
|
||||||
|
toThrow(new Error("Parse Error: Token '.' is not valid json at column 3 of expression [[].constructor] starting at [.constructor]."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,11 +158,11 @@ describe('parser', function() {
|
||||||
it('should throws exception for invalid exponent', function() {
|
it('should throws exception for invalid exponent', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("0.5E-");
|
lex("0.5E-");
|
||||||
}).toThrow('Lexer found invalid exponential value "0.5E-"');
|
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-].'));
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("0.5E-A");
|
lex("0.5E-A");
|
||||||
}).toThrow('Lexer found invalid exponential value "0.5E-A"');
|
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-A].'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should tokenize number starting with a dot', function() {
|
it('should tokenize number starting with a dot', function() {
|
||||||
|
|
@ -173,7 +173,7 @@ describe('parser', function() {
|
||||||
it('should throw error on invalid unicode', function() {
|
it('should throw error on invalid unicode', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
lex("'\\u1''bla'");
|
lex("'\\u1''bla'");
|
||||||
}).toThrow("Lexer Error: Invalid unicode escape [\\u1''b] starting at column '0' in expression ''\\u1''bla''.");
|
}).toThrow(new Error("Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla']."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -225,7 +225,7 @@ describe('parser', function() {
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
scope.$eval("1|nonExistant");
|
scope.$eval("1|nonExistant");
|
||||||
}).toThrow("Function 'nonExistant' at column '3' in '1|nonExistant' is not defined.");
|
}).toThrow(new Error("Parse Error: Token 'nonExistant' should be a function at column 3 of expression [1|nonExistant] starting at [nonExistant]."));
|
||||||
|
|
||||||
scope.$set('offset', 3);
|
scope.$set('offset', 3);
|
||||||
expect(scope.$eval("'abcd'|upper._case")).toEqual("ABCD");
|
expect(scope.$eval("'abcd'|upper._case")).toEqual("ABCD");
|
||||||
|
|
@ -312,14 +312,6 @@ describe('parser', function() {
|
||||||
expect(scope.$eval(";;1;;")).toEqual(1);
|
expect(scope.$eval(";;1;;")).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should evaluate throw', function() {
|
|
||||||
scope.$set('e', 'abc');
|
|
||||||
|
|
||||||
expect(function() {
|
|
||||||
scope.$eval("throw e");
|
|
||||||
}).toThrow('abc');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should evaluate object methods in correct context (this)', function() {
|
it('should evaluate object methods in correct context (this)', function() {
|
||||||
var C = function () {
|
var C = function () {
|
||||||
this.a = 123;
|
this.a = 123;
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ describe('scope/model', function(){
|
||||||
model.$watch('name', function(newVal, oldVal){
|
model.$watch('name', function(newVal, oldVal){
|
||||||
count ++;
|
count ++;
|
||||||
nameNewVal = newVal;
|
nameNewVal = newVal;
|
||||||
nameOldVal = oldVal
|
nameOldVal = oldVal;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(count).toBe(1);
|
expect(count).toBe(1);
|
||||||
|
|
@ -123,12 +123,12 @@ describe('scope/model', function(){
|
||||||
model.$watch('name', function(newVal, oldVal){
|
model.$watch('name', function(newVal, oldVal){
|
||||||
count ++;
|
count ++;
|
||||||
nameNewVal = newVal;
|
nameNewVal = newVal;
|
||||||
nameOldVal = oldVal
|
nameOldVal = oldVal;
|
||||||
}, undefined, false);
|
}, undefined, false);
|
||||||
|
|
||||||
expect(count).toBe(0);
|
expect(count).toBe(0);
|
||||||
expect(nameNewVal).toBe('crazy val 1');
|
expect(nameNewVal).toBe('crazy val 1');
|
||||||
expect(nameOldVal).toBe('crazy val 2')
|
expect(nameOldVal).toBe('crazy val 2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -143,17 +143,17 @@ describe('scope/model', function(){
|
||||||
describe('$tryEval', function(){
|
describe('$tryEval', function(){
|
||||||
it('should report error on element', function(){
|
it('should report error on element', function(){
|
||||||
var scope = createScope();
|
var scope = createScope();
|
||||||
scope.$tryEval('throw "myerror";', function(error){
|
scope.$tryEval(function(){throw "myError";}, function(error){
|
||||||
scope.error = error;
|
scope.error = error;
|
||||||
});
|
});
|
||||||
expect(scope.error).toEqual('myerror');
|
expect(scope.error).toEqual('myError');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report error on visible element', function(){
|
it('should report error on visible element', function(){
|
||||||
var element = jqLite('<div></div>');
|
var element = jqLite('<div></div>');
|
||||||
var scope = createScope();
|
var scope = createScope();
|
||||||
scope.$tryEval('throw "myError"', element);
|
scope.$tryEval(function(){throw "myError";}, element);
|
||||||
expect(element.attr('ng-exception')).toEqual('"myError"'); // errors are jsonified
|
expect(element.attr('ng-exception')).toEqual('myError');
|
||||||
expect(element.hasClass('ng-exception')).toBeTruthy();
|
expect(element.hasClass('ng-exception')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ describe('scope/model', function(){
|
||||||
scope.$exceptionHandler = function(e){
|
scope.$exceptionHandler = function(e){
|
||||||
this.error = e;
|
this.error = e;
|
||||||
};
|
};
|
||||||
scope.$tryEval('throw "myError"');
|
scope.$tryEval(function(){throw "myError";});
|
||||||
expect(scope.error).toEqual("myError");
|
expect(scope.error).toEqual("myError");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ describe("directives", function(){
|
||||||
var log = "";
|
var log = "";
|
||||||
log += element.attr('ng-exception') + ';';
|
log += element.attr('ng-exception') + ';';
|
||||||
log += element.hasClass('ng-exception') + ';';
|
log += element.hasClass('ng-exception') + ';';
|
||||||
expect(log).toEqual("\"Expected ng:repeat in form of 'item in collection' but got 'i dont parse'.\";true;");
|
expect(log.match(/Expected ng:repeat in form of 'item in collection' but got 'i dont parse'./)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expose iterator offset as $index when iterating over arrays', function() {
|
it('should expose iterator offset as $index when iterating over arrays', function() {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,42 @@ describe("service", function(){
|
||||||
scope.$log.info();
|
scope.$log.info();
|
||||||
scope.$log.error();
|
scope.$log.error();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Error', function(){
|
||||||
|
var e, $log, $console, errorArgs;
|
||||||
|
beforeEach(function(){
|
||||||
|
e = new Error('');
|
||||||
|
e.message = undefined;
|
||||||
|
e.sourceURL = undefined;
|
||||||
|
e.line = undefined;
|
||||||
|
e.stack = undefined;
|
||||||
|
|
||||||
|
$console = angular.service('$log')({console:{error:function(){
|
||||||
|
errorArgs = arguments;
|
||||||
|
}}});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass error if does not have trace', function(){
|
||||||
|
$console.error('abc', e);
|
||||||
|
expect(errorArgs).toEqual(['abc', e]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should print stack', function(){
|
||||||
|
e.stack = 'stack';
|
||||||
|
$console.error('abc', e);
|
||||||
|
expect(errorArgs).toEqual(['abc', 'stack']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should print line', function(){
|
||||||
|
e.message = 'message';
|
||||||
|
e.sourceURL = 'sourceURL';
|
||||||
|
e.line = '123';
|
||||||
|
$console.error('abc', e);
|
||||||
|
expect(errorArgs).toEqual(['abc', 'message\nsourceURL:123']);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("$exceptionHandler", function(){
|
describe("$exceptionHandler", function(){
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue