github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/vue-1.0.24/src/parsers/expression.js (about)

     1  import { warn } from '../util/index'
     2  import { parsePath, setPath } from './path'
     3  import Cache from '../cache'
     4  
     5  const expressionCache = new Cache(1000)
     6  
     7  const allowedKeywords =
     8    'Math,Date,this,true,false,null,undefined,Infinity,NaN,' +
     9    'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' +
    10    'encodeURIComponent,parseInt,parseFloat'
    11  const allowedKeywordsRE =
    12    new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)')
    13  
    14  // keywords that don't make sense inside expressions
    15  const improperKeywords =
    16    'break,case,class,catch,const,continue,debugger,default,' +
    17    'delete,do,else,export,extends,finally,for,function,if,' +
    18    'import,in,instanceof,let,return,super,switch,throw,try,' +
    19    'var,while,with,yield,enum,await,implements,package,' +
    20    'protected,static,interface,private,public'
    21  const improperKeywordsRE =
    22    new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)')
    23  
    24  const wsRE = /\s/g
    25  const newlineRE = /\n/g
    26  const saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g
    27  const restoreRE = /"(\d+)"/g
    28  const pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/
    29  const identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g
    30  const booleanLiteralRE = /^(?:true|false)$/
    31  
    32  /**
    33   * Save / Rewrite / Restore
    34   *
    35   * When rewriting paths found in an expression, it is
    36   * possible for the same letter sequences to be found in
    37   * strings and Object literal property keys. Therefore we
    38   * remove and store these parts in a temporary array, and
    39   * restore them after the path rewrite.
    40   */
    41  
    42  var saved = []
    43  
    44  /**
    45   * Save replacer
    46   *
    47   * The save regex can match two possible cases:
    48   * 1. An opening object literal
    49   * 2. A string
    50   * If matched as a plain string, we need to escape its
    51   * newlines, since the string needs to be preserved when
    52   * generating the function body.
    53   *
    54   * @param {String} str
    55   * @param {String} isString - str if matched as a string
    56   * @return {String} - placeholder with index
    57   */
    58  
    59  function save (str, isString) {
    60    var i = saved.length
    61    saved[i] = isString
    62      ? str.replace(newlineRE, '\\n')
    63      : str
    64    return '"' + i + '"'
    65  }
    66  
    67  /**
    68   * Path rewrite replacer
    69   *
    70   * @param {String} raw
    71   * @return {String}
    72   */
    73  
    74  function rewrite (raw) {
    75    var c = raw.charAt(0)
    76    var path = raw.slice(1)
    77    if (allowedKeywordsRE.test(path)) {
    78      return raw
    79    } else {
    80      path = path.indexOf('"') > -1
    81        ? path.replace(restoreRE, restore)
    82        : path
    83      return c + 'scope.' + path
    84    }
    85  }
    86  
    87  /**
    88   * Restore replacer
    89   *
    90   * @param {String} str
    91   * @param {String} i - matched save index
    92   * @return {String}
    93   */
    94  
    95  function restore (str, i) {
    96    return saved[i]
    97  }
    98  
    99  /**
   100   * Rewrite an expression, prefixing all path accessors with
   101   * `scope.` and generate getter/setter functions.
   102   *
   103   * @param {String} exp
   104   * @return {Function}
   105   */
   106  
   107  function compileGetter (exp) {
   108    if (improperKeywordsRE.test(exp)) {
   109      process.env.NODE_ENV !== 'production' && warn(
   110        'Avoid using reserved keywords in expression: ' + exp
   111      )
   112    }
   113    // reset state
   114    saved.length = 0
   115    // save strings and object literal keys
   116    var body = exp
   117      .replace(saveRE, save)
   118      .replace(wsRE, '')
   119    // rewrite all paths
   120    // pad 1 space here becaue the regex matches 1 extra char
   121    body = (' ' + body)
   122      .replace(identRE, rewrite)
   123      .replace(restoreRE, restore)
   124    return makeGetterFn(body)
   125  }
   126  
   127  /**
   128   * Build a getter function. Requires eval.
   129   *
   130   * We isolate the try/catch so it doesn't affect the
   131   * optimization of the parse function when it is not called.
   132   *
   133   * @param {String} body
   134   * @return {Function|undefined}
   135   */
   136  
   137  function makeGetterFn (body) {
   138    try {
   139      /* eslint-disable no-new-func */
   140      return new Function('scope', 'return ' + body + ';')
   141      /* eslint-enable no-new-func */
   142    } catch (e) {
   143      process.env.NODE_ENV !== 'production' && warn(
   144        'Invalid expression. ' +
   145        'Generated function body: ' + body
   146      )
   147    }
   148  }
   149  
   150  /**
   151   * Compile a setter function for the expression.
   152   *
   153   * @param {String} exp
   154   * @return {Function|undefined}
   155   */
   156  
   157  function compileSetter (exp) {
   158    var path = parsePath(exp)
   159    if (path) {
   160      return function (scope, val) {
   161        setPath(scope, path, val)
   162      }
   163    } else {
   164      process.env.NODE_ENV !== 'production' && warn(
   165        'Invalid setter expression: ' + exp
   166      )
   167    }
   168  }
   169  
   170  /**
   171   * Parse an expression into re-written getter/setters.
   172   *
   173   * @param {String} exp
   174   * @param {Boolean} needSet
   175   * @return {Function}
   176   */
   177  
   178  export function parseExpression (exp, needSet) {
   179    exp = exp.trim()
   180    // try cache
   181    var hit = expressionCache.get(exp)
   182    if (hit) {
   183      if (needSet && !hit.set) {
   184        hit.set = compileSetter(hit.exp)
   185      }
   186      return hit
   187    }
   188    var res = { exp: exp }
   189    res.get = isSimplePath(exp) && exp.indexOf('[') < 0
   190      // optimized super simple getter
   191      ? makeGetterFn('scope.' + exp)
   192      // dynamic getter
   193      : compileGetter(exp)
   194    if (needSet) {
   195      res.set = compileSetter(exp)
   196    }
   197    expressionCache.put(exp, res)
   198    return res
   199  }
   200  
   201  /**
   202   * Check if an expression is a simple path.
   203   *
   204   * @param {String} exp
   205   * @return {Boolean}
   206   */
   207  
   208  export function isSimplePath (exp) {
   209    return pathTestRE.test(exp) &&
   210      // don't treat true/false as paths
   211      !booleanLiteralRE.test(exp) &&
   212      // Math constants e.g. Math.PI, Math.E etc.
   213      exp.slice(0, 5) !== 'Math.'
   214  }