UNPKG

serverless-offline-msk

Version:

A serverless offline plugin that enables AWS MSK events

256 lines (208 loc) 6.65 kB
var debug = require('debug')('velocity'); module.exports = function(Velocity, utils) { 'use strict'; /** * escapeHTML */ function convert(str) { if (typeof str !== 'string') return str; var result = "" var escape = false var i, c, cstr; for (i = 0 ; i < str.length ; i++) { c = str.charAt(i); if ((' ' <= c && c <= '~') || (c === '\r') || (c === '\n')) { if (c === '&') { cstr = "&amp;" escape = true } else if (c === '"') { cstr = "&quot;" escape = true } else if (c === '<') { cstr = "&lt;" escape = true } else if (c === '>') { cstr = "&gt;" escape = true } else { cstr = c.toString() } } else { cstr = "&#" + c.charCodeAt().toString() + ";" } result = result + cstr } return escape ? result : str } var posUnknown = { first_line: "unknown", first_column: "unknown"}; utils.mixin(Velocity.prototype, { /** * get variable value * @param {object} ast ast data * @param {bool} isVal for example `$foo`, isVal value should be true, other condition, * `#set($foo = $bar)`, the $bar value get, isVal set to false */ getReferences: function(ast, isVal) { if (ast.prue) { var define = this.defines[ast.id]; if (utils.isArray(define)) { return this._render(define); } if (ast.id in this.config.unescape) ast.prue = false; } var escape = this.config.escape; var isSilent = this.silence || ast.leader === "$!"; var isfn = ast.args !== undefined; var context = this.context; var ret = context[ast.id]; var local = this.getLocal(ast); var text = Velocity.Helper.getRefText(ast); if (text in context) { return (ast.prue && escape) ? convert(context[text]) : context[text]; } if (ret !== undefined && isfn) { ret = this.getPropMethod(ast, context, ast); } if (local.isLocaled) ret = local['value']; if (ast.path) { utils.some(ast.path, function(property, i, len) { if (ret === undefined) { this._throw(ast, property); } // 第三个参数,返回后面的参数ast ret = this.getAttributes(property, ret, ast); }, this); } if (isVal && ret === undefined) { ret = isSilent ? '' : Velocity.Helper.getRefText(ast); } ret = (ast.prue && escape) ? convert(ret) : ret; return ret; }, /** * 获取局部变量,在macro和foreach循环中使用 */ getLocal: function(ast) { var id = ast.id; var local = this.local; var ret = false; var isLocaled = utils.some(this.conditions, function(contextId) { var _local = local[contextId]; if (id in _local) { ret = _local[id]; return true; } return false; }, this); return { value: ret, isLocaled: isLocaled }; }, /** * $foo.bar 属性求值,最后面两个参数在用户传递的函数中用到 * @param {object} property 属性描述,一个对象,主要包括id,type等定义 * @param {object} baseRef 当前执行链结果,比如$a.b.c,第一次baseRef是$a, * 第二次是$a.b返回值 * @private */ getAttributes: function(property, baseRef, ast) { // fix #54 if (baseRef === null || baseRef === undefined) { return undefined; } /** * type对应着velocity.yy中的attribute,三种类型: method, index, property */ var type = property.type; var ret; var id = property.id; if (type === 'method') { ret = this.getPropMethod(property, baseRef, ast); } else if (type === 'property') { ret = baseRef[id]; } else { ret = this.getPropIndex(property, baseRef); } return ret; }, /** * $foo.bar[1] index求值 * @private */ getPropIndex: function(property, baseRef) { var ast = property.id; var key; if (ast.type === 'references') { key = this.getReferences(ast); } else if (ast.type === 'integer') { key = ast.value; } else { key = ast.value; } return baseRef[key]; }, /** * $foo.bar()求值 */ getPropMethod: function(property, baseRef, ast) { var id = property.id; var ret = baseRef[id]; var args = []; utils.forEach(property.args, function(exp) { args.push(this.getLiteral(exp)); }, this); const payload = { property: id, params: args, context: baseRef }; var matched = this.customMethodHandlers.find(function(item) { return item && item.match(payload); }); if (matched) { debug('match custom method handler, uid %s', matched.uid); // run custom method handler, we can // add some native method which Java can do, for example // #set($foo = [1, 2]) $foo.size() ret = matched.resolve(payload); } else { if (ret && ret.call) { var that = this; if(typeof baseRef === 'object' && baseRef){ baseRef.eval = function() { return that.eval.apply(that, arguments); }; } try { ret = ret.apply(baseRef, args); } catch (e) { var pos = ast.pos || posUnknown; var text = Velocity.Helper.getRefText(ast); var err = ' on ' + text + ' at L/N ' + pos.first_line + ':' + pos.first_column; // e.name = ''; e.message += err; throw e; } } else { this._throw(ast, property, 'TypeError'); ret = undefined; } } return ret; }, _throw: function(ast, property, errorName) { if (this.config.env !== 'development') { return; } var text = Velocity.Helper.getRefText(ast); var pos = ast.pos || posUnknown; var propertyName = property.type === 'index' ? property.id.value : property.id; var errorMsg = 'get property ' + propertyName + ' of undefined'; if (errorName === 'TypeError') { errorMsg = propertyName + ' is not method'; } errorMsg += '\n at L/N ' + text + ' ' + pos.first_line + ':' + pos.first_column; var e = new Error(errorMsg); e.name = errorName || 'ReferenceError'; throw e; } }) }