github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/parsers/text.js (about) 1 import Cache from '../cache' 2 import config from '../config' 3 import { parseDirective } from '../parsers/directive' 4 5 const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g 6 let cache, tagRE, htmlRE 7 8 /** 9 * Escape a string so it can be used in a RegExp 10 * constructor. 11 * 12 * @param {String} str 13 */ 14 15 function escapeRegex (str) { 16 return str.replace(regexEscapeRE, '\\$&') 17 } 18 19 export function compileRegex () { 20 var open = escapeRegex(config.delimiters[0]) 21 var close = escapeRegex(config.delimiters[1]) 22 var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]) 23 var unsafeClose = escapeRegex(config.unsafeDelimiters[1]) 24 tagRE = new RegExp( 25 unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + 26 open + '((?:.|\\n)+?)' + close, 27 'g' 28 ) 29 htmlRE = new RegExp( 30 '^' + unsafeOpen + '.*' + unsafeClose + '$' 31 ) 32 // reset cache 33 cache = new Cache(1000) 34 } 35 36 /** 37 * Parse a template text string into an array of tokens. 38 * 39 * @param {String} text 40 * @return {Array<Object> | null} 41 * - {String} type 42 * - {String} value 43 * - {Boolean} [html] 44 * - {Boolean} [oneTime] 45 */ 46 47 export function parseText (text) { 48 if (!cache) { 49 compileRegex() 50 } 51 var hit = cache.get(text) 52 if (hit) { 53 return hit 54 } 55 if (!tagRE.test(text)) { 56 return null 57 } 58 var tokens = [] 59 var lastIndex = tagRE.lastIndex = 0 60 var match, index, html, value, first, oneTime 61 /* eslint-disable no-cond-assign */ 62 while (match = tagRE.exec(text)) { 63 /* eslint-enable no-cond-assign */ 64 index = match.index 65 // push text token 66 if (index > lastIndex) { 67 tokens.push({ 68 value: text.slice(lastIndex, index) 69 }) 70 } 71 // tag token 72 html = htmlRE.test(match[0]) 73 value = html ? match[1] : match[2] 74 first = value.charCodeAt(0) 75 oneTime = first === 42 // * 76 value = oneTime 77 ? value.slice(1) 78 : value 79 tokens.push({ 80 tag: true, 81 value: value.trim(), 82 html: html, 83 oneTime: oneTime 84 }) 85 lastIndex = index + match[0].length 86 } 87 if (lastIndex < text.length) { 88 tokens.push({ 89 value: text.slice(lastIndex) 90 }) 91 } 92 cache.put(text, tokens) 93 return tokens 94 } 95 96 /** 97 * Format a list of tokens into an expression. 98 * e.g. tokens parsed from 'a {{b}} c' can be serialized 99 * into one single expression as '"a " + b + " c"'. 100 * 101 * @param {Array} tokens 102 * @param {Vue} [vm] 103 * @return {String} 104 */ 105 106 export function tokensToExp (tokens, vm) { 107 if (tokens.length > 1) { 108 return tokens.map(function (token) { 109 return formatToken(token, vm) 110 }).join('+') 111 } else { 112 return formatToken(tokens[0], vm, true) 113 } 114 } 115 116 /** 117 * Format a single token. 118 * 119 * @param {Object} token 120 * @param {Vue} [vm] 121 * @param {Boolean} [single] 122 * @return {String} 123 */ 124 125 function formatToken (token, vm, single) { 126 return token.tag 127 ? token.oneTime && vm 128 ? '"' + vm.$eval(token.value) + '"' 129 : inlineFilters(token.value, single) 130 : '"' + token.value + '"' 131 } 132 133 /** 134 * For an attribute with multiple interpolation tags, 135 * e.g. attr="some-{{thing | filter}}", in order to combine 136 * the whole thing into a single watchable expression, we 137 * have to inline those filters. This function does exactly 138 * that. This is a bit hacky but it avoids heavy changes 139 * to directive parser and watcher mechanism. 140 * 141 * @param {String} exp 142 * @param {Boolean} single 143 * @return {String} 144 */ 145 146 var filterRE = /[^|]\|[^|]/ 147 function inlineFilters (exp, single) { 148 if (!filterRE.test(exp)) { 149 return single 150 ? exp 151 : '(' + exp + ')' 152 } else { 153 var dir = parseDirective(exp) 154 if (!dir.filters) { 155 return '(' + exp + ')' 156 } else { 157 return 'this._applyFilters(' + 158 dir.expression + // value 159 ',null,' + // oldValue (null for read) 160 JSON.stringify(dir.filters) + // filter descriptors 161 ',false)' // write? 162 } 163 } 164 }