var VnObject = require('./object'); /** * Base class for compilers. */ module.exports = new Class({ Extends: VnObject ,compile: function() {} ,postCompile: function() {} ,instantiate: function() {} ,preLink: function() {} ,link: function() {} ,connect: function() {} ,postLink: function() {} ,setProperty: function() {} ,free: function() {} ,initialize: function(builder) { this._builder = builder; this._interpoler = builder._interpoler; this.parent(); } /** * Checks if the passed attribute name it's an event. * * @param {String} attribute The attribute name * @return {Boolean} %true if it's an event, otherwise %false */ ,isEvent: function(attribute) { return /^on-\w+/.test(attribute); } ,isIdentifier: function(value) { return /^[a-zA-Z_$][\w$]*$/.test(value); } /** * Logs an error parsing the node. * * @param {String} error The error message template * @param {...} varArgs The message template arguments */ ,showError: function() { this._builder.showError.apply(this._builder, arguments); } ,_getMethod: function(value) { // XXX: Compatibility with old methods return this.isIdentifier(value) ? value : this.fnExpr(value); } ,bindMethod(handler, scope, isEvent) { // XXX: Compatibility with old methods if (typeof handler === 'string') { const method = scope.thisArg[handler]; if (!method) { this.showError(`Function '${handler}' not found`); return undefined; } return method.bind(scope.thisArg); } return function($event) { let handlerScope; if (isEvent) { handlerScope = Object.create(scope.$); Object.assign(handlerScope, {$event}); } else handlerScope = scope.$; handler.call(this, handlerScope); }.bind(scope.thisArg); } ,matchExpr(value) { const match = /^{{(.*)}}$/.exec(value); if (!match) return null; return this.fnExpr(match[1]); } ,modelExpr(expr) { try { return new Function('$scope', '$value', `"use strict"; $scope.${expr} = $value;` ); } catch (err) { this.showError(`${err.message}:`, expr); } } ,exprRegex: /^{{((?:(?!}}).)*)}}$/ ,exprRegexMulti: /{{((?:(?!}}).)*)}}/g ,isExpr(expr, isMulti) { return isMulti ? this.exprRegexMulti.test(expr) : this.exprRegex.test(expr); } ,compileExpr(context, property, value, isMulti) { const exprContext = { context, property, value }; if (isMulti) { let i = 0; const self = this; exprContext.exprs = []; exprContext.template = value.replace(this.exprRegexMulti, function(match, capture) { exprContext.exprs.push(self.fnExpr(capture)); return `{{${i++}}}`; }); } else { const match = this.exprRegex.exec(value); exprContext.expr = this.fnExpr(match[1]); } this._builder._exprContexts.push(exprContext); } ,fnExpr(expr) { try { return new Function('$scope', `with($scope) { return ${expr}; }` ); } catch (err) { this.showError(`${err.message}:`, expr); } } ,_translateValue: function(value) { var chr = value.charAt(0); if (chr === '_') return _(value.substr(1)); else if (chr === '\\' && value.charAt(1) === '_') return value.substr(1); return value; } });