RubyLouvre/avalon

View on GitHub
src/parser/index.js

Summary

Maintainability
A
1 hr
Test Coverage
import { avalon, msie, Cache } from '../seed/core'
import { clearString, stringPool, fill, rfill, dig } from '../vtree/clearString'

var keyMap = avalon.oneObject("break,case,catch,continue,debugger,default,delete,do,else,false," +
    "finally,for,function,if,in,instanceof,new,null,return,switch,this," +
    "throw,true,try,typeof,var,void,while,with," + /* 关键字*/
    "abstract,boolean,byte,char,class,const,double,enum,export,extends," +
    "final,float,goto,implements,import,int,interface,long,native," +
    "package,private,protected,public,short,static,super,synchronized," +
    "throws,transient,volatile,arguments")

export var skipMap = avalon.mix({
    Math: 1,
    Date: 1,
    $event: 1,
    window: 1,
    __vmodel__: 1,
    avalon: 1
}, keyMap)

var rvmKey = /(^|[^\w\u00c0-\uFFFF_])(@|##)(?=[$\w])/g
var ruselessSp = /\s*(\.|\|)\s*/g
var rshortCircuit = /\|\|/g
var brackets = /\(([^)]*)\)/
var rpipeline = /\|(?=\?\?)/
var rregexp = /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/g
var robjectProp = /\.[\w\.\$]+/g //对象的属性 el.xxx 中的xxx
var robjectKey = /(\{|\,)\s*([\$\w]+)\s*:/g //对象的键名与冒号 {xxx:1,yyy: 2}中的xxx, yyy
var rfilterName = /\|(\w+)/g
var rlocalVar = /[$a-zA-Z_][$a-zA-Z0-9_]*/g

var exprCache = new Cache(300)

function addScopeForLocal(str) {
    return str.replace(robjectProp, dig).
    replace(rlocalVar, function(el) {
        if (!skipMap[el]) {
            return "__vmodel__." + el
        }
        return el
    })
}

export function addScope(expr, type) {
    var cacheKey = expr + ':' + type
    var cache = exprCache.get(cacheKey)
    if (cache) {
        return cache.slice(0)
    }

    stringPool.map = {}
        //https://github.com/RubyLouvre/avalon/issues/1849
    var input = expr.replace(rregexp, function(a, b) {
            return b + dig(a.slice(b.length))
        }) //移除所有正则
    input = clearString(input) //移除所有字符串
    input = input.replace(rshortCircuit, dig). //移除所有短路运算符
    replace(ruselessSp, '$1'). //移除.|两端空白

    replace(robjectKey, function(_, a, b) { //移除所有键名
        return a + dig(b) + ':' //比如 ms-widget="[{is:'ms-address-wrap', $id:'address'}]"这样极端的情况 
    }).
    replace(rvmKey, '$1__vmodel__.'). //转换@与##为__vmodel__
    replace(rfilterName, function(a, b) { //移除所有过滤器的名字
        return '|' + dig(b)
    })
    input = addScopeForLocal(input) //在本地变量前添加__vmodel__

    var filters = input.split(rpipeline) //根据管道符切割表达式
    var body = filters.shift().replace(rfill, fill).trim()
    if (/\?\?\d/.test(body)) {
        body = body.replace(rfill, fill)
    }
    if (filters.length) {
        filters = filters.map(function(filter) {
            var bracketArgs = ''
            filter = filter.replace(brackets, function(a, b) {
                if (/\S/.test(b)) {
                    bracketArgs += ',' + b //还原字符串,正则,短路运算符
                }
                return ''
            })
            var arg = '[' + avalon.quote(filter.trim()) + bracketArgs + ']'
            return arg

        })
        filters = 'avalon.composeFilters(' + filters + ')(__value__)'
        filters = filters.replace(rfill, fill)
    } else {
        filters = ''
    }
    return exprCache.put(cacheKey, [body, filters])
}
var rhandleName = /^__vmodel__\.[$\w\.]+$/
var rfixIE678 = /__vmodel__\.([^(]+)\(([^)]*)\)/
export function makeHandle(body) {
    if (rhandleName.test(body)) {
        body = body + '($event)'
    }
    /* istanbul ignore if */
    if (msie < 9) {
        body = body.replace(rfixIE678, function(a, b, c) {
            return '__vmodel__.' + b + '.call(__vmodel__' + (/\S/.test(c) ? ',' + c : '') + ')'
        })
    }
    return body
}
export function createGetter(expr, type) {
    var arr = addScope(expr, type),
        body
    if (!arr[1]) {
        body = arr[0]
    } else {
        body = arr[1].replace(/__value__\)$/, arr[0] + ')')
    }
    try {
        return new Function('__vmodel__', 'return ' + body + ';')
            /* istanbul ignore next */
    } catch (e) {
        avalon.log('parse getter: [', expr, body, ']error')
        return avalon.noop
    }
}

/**
 * 生成表达式设值函数
 * @param  {String}  expr
 */
export function createSetter(expr, type) {
    var arr = addScope(expr, type)
    var body = 'try{ ' + arr[0] + ' = __value__}catch(e){avalon.log(e, "in on dir")}'
    try {
        return new Function('__vmodel__', '__value__', body + ';')
            /* istanbul ignore next */
    } catch (e) {
        avalon.log('parse setter: ', expr, ' error')
        return avalon.noop
    }
}