refactor(parser): turn parser into a service (keep compatibility hack)

This commit is contained in:
Misko Hevery 2011-11-03 13:53:37 -07:00
parent c6d2549a52
commit 7c11531902
9 changed files with 52 additions and 45 deletions

2
angularFiles.js vendored
View file

@ -19,7 +19,7 @@ angularFiles = {
'src/service/location.js',
'src/service/log.js',
'src/service/resource.js',
'src/service/parser.js',
'src/service/parse.js',
'src/service/route.js',
'src/service/routeParams.js',
'src/service/scope.js',

View file

@ -1059,6 +1059,7 @@ function ngModule($provide, $injector) {
$provide.service('$location', $LocationProvider);
$provide.service('$locationConfig', $LocationConfigProvider);
$provide.service('$log', $LogProvider);
$provide.service('$parse', $ParseProvider);
$provide.service('$resource', $ResourceProvider);
$provide.service('$route', $RouteProvider);
$provide.service('$routeParams', $RouteParamsProvider);

View file

@ -41,7 +41,7 @@ function fromJson(json, useNative) {
if (useNative && window.JSON && window.JSON.parse) {
obj = JSON.parse(json);
} else {
obj = parser(json, true).primary()();
obj = parseJson(json, true)();
}
return transformDates(obj);
} catch (e) {

View file

@ -235,9 +235,10 @@ angularDirective("ng:controller", function(expression){
*/
angularDirective("ng:bind", function(expression, element){
element.addClass('ng-binding');
var exprFn = parser(expression).statements();
return ['$exceptionHandler', '$element', function($exceptionHandler, element) {
var lastValue = Number.NaN;
return ['$exceptionHandler', '$parse', '$element', function($exceptionHandler, $parse, element) {
var exprFn = parser(expression),
lastValue = Number.NaN;
this.$watch(function(scope) {
// TODO(misko): remove error handling https://github.com/angular/angular.js/issues/347
var value, html, isHtml, isDomElement,

View file

@ -98,8 +98,9 @@
*/
function $FormFactoryProvider() {
this.$get = ['$rootScope', function($rootScope) {
var $parse;
this.$get = ['$rootScope', '$parse', function($rootScope, $parse_) {
$parse = $parse_;
/**
* @ngdoc proprety
* @name rootForm
@ -352,10 +353,14 @@ function $FormFactoryProvider() {
modelScope = params.scope,
onChange = params.onChange,
alias = params.alias,
scopeGet = parser(params.model).assignable(),
scopeGet = $parse(params.model),
scopeSet = scopeGet.assign,
widget = this.$new(params.controller, params.controllerArgs);
if (!scopeSet) {
throw Error("Expression '" + params.model + "' is not assignable!");
};
widget.$error = {};
// Set the state to something we know will change to get the process going.
widget.$modelValue = Number.NaN;

View file

@ -219,6 +219,7 @@ function lex(text){
function parser(text, json){
var ZERO = valueFn(0),
value,
tokens = lex(text),
assignment = _assignment,
assignable = logicalOR,
@ -240,24 +241,14 @@ function parser(text, json){
functionIdent =
pipeFunction =
function() { throwError("is not valid json", {text:text, index:0}); };
value = primary();
} else {
value = statements();
}
//TODO: Shouldn't all of the public methods have assertAllConsumed?
//TODO: I think these should be public as part of the parser api instead of scope.$eval().
return {
assignable: assertConsumed(assignable),
primary: assertConsumed(primary),
statements: assertConsumed(statements)
};
function assertConsumed(fn) {
return function() {
var value = fn();
if (tokens.length !== 0) {
throwError("is an unexpected token", tokens[0]);
}
return value;
};
if (tokens.length !== 0) {
throwError("is an unexpected token", tokens[0]);
}
return value;
///////////////////////////////////
function throwError(msg, token) {
@ -680,7 +671,6 @@ function getter(obj, path, bindFnToScope) {
}
var getterFnCache = {},
compileCache = {},
JS_KEYWORDS = {};
forEach(
@ -727,13 +717,28 @@ function getterFn(path) {
///////////////////////////////////
// TODO(misko): Deprecate? Remove!
// I think that compilation should be a service.
function expressionCompile(exp) {
if (isFunction(exp)) return exp;
var fn = compileCache[exp];
if (!fn) {
fn = compileCache[exp] = parser(exp).statements();
}
return fn;
function $ParseProvider() {
var cache = {};
this.$get = ['$injector', function($injector) {
return function(exp) {
switch(typeof exp) {
case 'string':
return cache.hasOwnProperty(exp)
? cache[exp]
: cache[exp] = parser(exp);
case 'function':
return exp;
default:
return noop;
}
};
}];
}
// This is a special access for JSON parser which bypasses the injector
var parseJson = function(json) {
return parser(json, true);
};
// TODO(misko): temporary hack, until we get rid of the type augmentation
var expressionCompile = new $ParseProvider().$get[1](null);

View file

@ -25,8 +25,8 @@
* are expensive to construct.
*/
function $RootScopeProvider(){
this.$get = ['$injector', '$exceptionHandler',
function( $injector, $exceptionHandler){
this.$get = ['$injector', '$exceptionHandler', '$parse',
function( $injector, $exceptionHandler, $parse){
/**
* @ngdoc function
* @name angular.scope
@ -416,10 +416,7 @@ function $RootScopeProvider(){
* @returns {*} The result of evaluating the expression.
*/
$eval: function(expr) {
var fn = isString(expr)
? expressionCompile(expr)
: expr || noop;
return fn(this);
return $parse(expr)(this);
},
/**

View file

@ -413,12 +413,12 @@ describe('parser', function() {
describe('assignable', function() {
it('should expose assignment function', function() {
var fn = parser('a').assignable();
it('should expose assignment function', inject(function($parse) {
var fn = $parse('a');
expect(fn.assign).toBeTruthy();
var scope = {};
fn.assign(scope, 123);
expect(scope).toEqual({a:123});
});
}));
});
});

View file

@ -49,8 +49,6 @@ function dumpScope(scope, offset) {
publishExternalAPI(angular)
beforeEach(function() {
publishExternalAPI(angular)
// This is to reset parsers global cache of expressions.
compileCache = {};
// workaround for IE bug https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
// IE overwrite window.jQuery with undefined because of empty jQuery var statement, so we have to