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  }