parser目錄下包含如下幾個(gè)文件,核心文件在于path.js侯繁。
-
directive.js:
parseDirective
-
expression.js:
parseExpression
-
path.js:
getPath, setPath, parsePath
-
template.js:
parseTemplate, cloneNode, parseTemplate
text.js:
parseText,
tokensToExp,
compileRegex
函數(shù)解讀:
- parseDirective: 判斷表達(dá)式中是否存在過(guò)濾器,如果存在提取出來(lái)
- parseExpression: 負(fù)責(zé)將表達(dá)式添加getter 和 setter方法
- makeGetterFn:將簡(jiǎn)單字符串表達(dá)式添加scope作用域并轉(zhuǎn)化為function返回
- compileGetter:將復(fù)雜字符串表達(dá)式進(jìn)行正則替換并在變量后添加scope作用域
例: status == "todo" 返回 scope.status == "todo" - compileSetter:將parse函數(shù)生成數(shù)組遍歷并將最后一個(gè)屬性作為最后的key
[path.js] 通過(guò)parse函數(shù)對(duì) a.b.c 進(jìn)行逐個(gè)字節(jié)掃描,最終獲得['a','b','c',raw:'a.b.c']數(shù)組
// actions
var APPEND = 0 // 拼接字符在keystr后
var PUSH = 1 // 將keystr添加到keys數(shù)組中
var INC_SUB_PATH_DEPTH = 2 // 拼接當(dāng)前字符在keystr后,并且深度+1
var PUSH_SUB_PATH = 3 // 如果深度大于0將狀態(tài)置回IN_SUB_PATH,相反將keystr添加到keys數(shù)組
// states
var BEFORE_PATH = 0 // 初始狀態(tài)
var IN_PATH = 1 // 遇到空格 和 ]
var BEFORE_IDENT = 2 // 遇到' . ' 或 空格時(shí)
var IN_IDENT = 3 // 遇到字符串?dāng)?shù)字時(shí)
var IN_SUB_PATH = 4 // 遇到 ' 或 " 或 [ 時(shí)
var IN_SINGLE_QUOTE = 5 // 遇到 '
var IN_DOUBLE_QUOTE = 6 // 遇到 "
var AFTER_PATH = 7 // 結(jié)束狀態(tài)
var ERROR = 8 // 報(bào)錯(cuò)
var pathStateMachine = [] // 狀態(tài) + 動(dòng)作 管理倉(cāng)庫(kù)
pathStateMachine[BEFORE_PATH] = {
'ws': [BEFORE_PATH],
'ident': [IN_IDENT, APPEND],
'[': [IN_SUB_PATH],
'eof': [AFTER_PATH]
}
pathStateMachine[IN_PATH] = {
'ws': [IN_PATH],
'.': [BEFORE_IDENT],
'[': [IN_SUB_PATH],
'eof': [AFTER_PATH]
}
pathStateMachine[BEFORE_IDENT] = {
'ws': [BEFORE_IDENT],
'ident': [IN_IDENT, APPEND]
}
pathStateMachine[IN_IDENT] = {
'ident': [IN_IDENT, APPEND],
'0': [IN_IDENT, APPEND],
'number': [IN_IDENT, APPEND],
'ws': [IN_PATH, PUSH],
'.': [BEFORE_IDENT, PUSH],
'[': [IN_SUB_PATH, PUSH],
'eof': [AFTER_PATH, PUSH]
}
pathStateMachine[IN_SUB_PATH] = {
"'": [IN_SINGLE_QUOTE, APPEND],
'"': [IN_DOUBLE_QUOTE, APPEND],
'[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
']': [IN_PATH, PUSH_SUB_PATH],
'eof': ERROR,
'else': [IN_SUB_PATH, APPEND]
}
pathStateMachine[IN_SINGLE_QUOTE] = {
"'": [IN_SUB_PATH, APPEND],
'eof': ERROR,
'else': [IN_SINGLE_QUOTE, APPEND]
}
pathStateMachine[IN_DOUBLE_QUOTE] = {
'"': [IN_SUB_PATH, APPEND],
'eof': ERROR,
'else': [IN_DOUBLE_QUOTE, APPEND]
}
/*
開(kāi)始狀態(tài)下當(dāng)遇到對(duì)應(yīng)字符會(huì)將狀態(tài)變化成對(duì)應(yīng)狀態(tài)并執(zhí)行對(duì)應(yīng)動(dòng)作
我們以 a["b"].c 為線索進(jìn)入parse函數(shù)并進(jìn)行逐個(gè)字節(jié)掃描
index=0時(shí):
char='a' mode=BEFORE_PATH pathStateMachine[BEFORE_PATH]['ident']=[IN_IDENT, APPEND] newchar="a",keys=[]
index=1時(shí) :
char='[' mode=IN_IDENT pathStateMachine[IN_IDENT]['[']=[IN_SUB_PATH, PUSH] newchar=undefined,keys=['a']
index=2時(shí) :
char='"' mode=IN_SUB_PATH pathStateMachine[IN_SUB_PATH]['"']=[IN_DOUBLE_QUOTE,APPEND] newchar='"',keys=['a']
index=3時(shí) :
char='b' mode=IN_DOUBLE_QUOTE pathStateMachine[IN_DOUBLE_QUOTE]['ident']= pathStateMachine[IN_DOUBLE_QUOTE]['else'] = [IN_DOUBLE_QUOTE,APPEND] newchar='"b',keys=['a']
index=4時(shí) :
char='"' mode=IN_DOUBLE_QUOTE pathStateMachine[IN_DOUBLE_QUOTE]['"']=[IN_SUB_PATH,APPEND] newchar='"b"',keys=['a']
index=5時(shí) :
char="]" mode=IN_SUB_PATH pathStateMachine[IN_SUB_PATH][']']=[IN_PATH,PUSH_SUB_PATH] newchar=undefined,keys=['a','b']
index=6時(shí) :
char="." mode=IN_PATH pathStateMachine[IN_PATH]['.']=[BEFORE_IDENT] newchar=undefined,keys=['a','b']
index=7時(shí) :
char="c" mode=BEFORE_IDENT pathStateMachine[BEFORE_IDENT]['indent']=[IN_IDENT,APPEND] newchar='c',keys=['a','b']
index=8時(shí) :
char=undefined mode=IN_IDENT pathStateMachine[IN_IDENT]['eof']=[AFTER_PATH,PUSH] newchar=undefined,keys=['a','b','c']
最終循環(huán)完成當(dāng)狀態(tài)變?yōu)锳FTER_PATH時(shí)贷腕,keys = ['a','b','c',raw:'a["b"].c']
*/
function parse (path) {
var keys = []
var index = -1
var mode = BEFORE_PATH
var subPathDepth = 0
var c, newChar, key, type, transition, action, typeMap
var actions = []
actions[PUSH] = function () {
if (key !== undefined) {
keys.push(key)
key = undefined
}
}
actions[APPEND] = function () {
if (key === undefined) {
key = newChar
} else {
key += newChar
}
}
actions[INC_SUB_PATH_DEPTH] = function () {
actions[APPEND]()
subPathDepth++
}
actions[PUSH_SUB_PATH] = function () {
if (subPathDepth > 0) {
subPathDepth--
mode = IN_SUB_PATH
actions[APPEND]()
} else {
subPathDepth = 0
key = formatSubPath(key)
if (key === false) {
return false
} else {
actions[PUSH]()
}
}
}
function maybeUnescapeQuote () {
var nextChar = path[index + 1]
if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
(mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
index++
newChar = '\\' + nextChar
actions[APPEND]()
return true
}
}
while (mode != null) {
index++
c = path[index]
if (c === '\\' && maybeUnescapeQuote()) {
continue
}
type = getPathCharType(c)
typeMap = pathStateMachine[mode]
transition = typeMap[type] || typeMap['else'] || ERROR
if (transition === ERROR) {
return // parse error
}
mode = transition[0]
action = actions[transition[1]]
if (action) {
newChar = transition[2]
newChar = newChar === undefined
? c
: newChar
if (action() === false) {
return
}
}
if (mode === AFTER_PATH) {
keys.raw = path
return keys
}
}
}