Просмотр исходного кода

New ExpParser implementation

- extract all paths and replace them with correct reference
- in the process, create missing bindings on the owner vm's compiler
Evan You 12 лет назад
Родитель
Сommit
bc0fd377d5
2 измененных файлов с 44 добавлено и 58 удалено
  1. 6 17
      src/compiler.js
  2. 38 41
      src/exp-parser.js

+ 6 - 17
src/compiler.js

@@ -73,7 +73,7 @@ function Compiler (vm, options) {
     // and register child id on parent
     var childId = utils.attr(el, 'id')
     if (parent) {
-        vm.$parent = parent.vm
+        def(vm, '$parent', parent.vm)
         if (childId) {
             compiler.childId = childId
             parent.vm.$[childId] = vm
@@ -101,7 +101,7 @@ function Compiler (vm, options) {
     // which should be inenumerable but configurable
     if (compiler.repeat) {
         vm.$index = compiler.repeatIndex
-        vm.$collection = compiler.repeatCollection
+        def(vm, '$collection', compiler.repeatCollection)
         compiler.createBinding('$index')
     }
 
@@ -409,25 +409,14 @@ CompilerProto.createBinding = function (key, isExp, isFn) {
     if (isExp) {
         // a complex expression binding
         // we need to generate an anonymous computed property for it
-        var result = ExpParser.parse(key)
-        if (result.getter) {
+        var getter = ExpParser.parse(key, compiler)
+        if (getter) {
             log('  created expression binding: ' + key)
             binding.value = isFn
-                ? result.getter
-                : { $get: result.getter }
+                ? getter
+                : { $get: getter }
             compiler.markComputed(binding)
             compiler.exps.push(binding)
-            // need to create the bindings for keys
-            // that do not exist yet
-            if (result.paths) {
-                var i = result.paths.length, v
-                while (i--) {
-                    v = result.paths[i]
-                    if (!bindings[v]) {
-                        compiler.rootCompiler.createBinding(v)
-                    }
-                }
-            }
         }
     } else {
         log('  created binding: ' + key)

+ 38 - 41
src/exp-parser.js

@@ -1,4 +1,5 @@
-var utils = require('./utils')
+var utils = require('./utils'),
+    hasOwn = Object.prototype.hasOwnProperty
 
 // Variable extraction scooped from https://github.com/RubyLouvre/avalon
 
@@ -37,25 +38,45 @@ function getVariables (code) {
 }
 
 /**
- *  Based on top level variables, extract full keypaths accessed.
- *  We need full paths because we need to define them in the compiler's
- *  bindings, so that they emit 'get' events during dependency tracking.
+ *  Filter 
  */
-// function getPaths (code, vars) {
-//     var pathRE = new RegExp("\\b(" + vars.join('|') + ")[$\\w\\.]*\\b", 'g')
-//     return code.match(pathRE)
-// }
-
 function filterUnique (vars) {
     var hash = utils.hash(),
         i = vars.length,
-        key
+        key, res = []
     while (i--) {
         key = vars[i]
         if (hash[key]) continue
         hash[key] = 1
+        res.push(key)
     }
-    return Object.keys(hash)
+    return res
+}
+
+function getRel (path, compiler) {
+    var rel = '',
+        vm  = compiler.vm,
+        dot = path.indexOf('.'),
+        key = dot > -1
+            ? path.slice(0, dot)
+            : path
+    while (true) {
+        if (hasOwn.call(vm, key)) {
+            break
+        } else {
+            if (vm.$parent) {
+                vm = vm.$parent
+                rel += '$parent.'
+            } else {
+                break
+            }
+        }
+    }
+    compiler = vm.$compiler
+    if (!hasOwn.call(compiler.bindings, path)) {
+        compiler.createBinding(path)
+    }
+    return rel
 }
 
 /**
@@ -81,41 +102,17 @@ module.exports = {
      *  from an arbitrary expression, together with a list of paths to be
      *  created as bindings.
      */
-    parse: function (exp) {
+    parse: function (exp, compiler) {
         // extract variable names
         var vars = getVariables(exp)
         if (!vars.length) {
-            return {
-                getter: makeGetter('return ' + exp, exp)
-            }
+            return makeGetter('return ' + exp, exp)
         }
-        console.log(vars)
         vars = filterUnique(vars)
-        // var args = [],
-        //     v, i, keyPrefix,
-        //     l = vars.length,
-        //     hash = Object.create(null)
-        // for (i = 0; i < l; i++) {
-        //     v = vars[i]
-        //     // avoid duplicate keys
-        //     if (hash[v]) continue
-        //     hash[v] = v
-        //     // push assignment
-        //     keyPrefix = v.charAt(0)
-        //     args.push(v + (
-        //         (keyPrefix === '$' || keyPrefix === '_')
-        //             ? '=this.' + v
-        //             : '=this.$get("' + v + '")'
-        //         ))
-        // }
-        // args = 'var ' + args.join(',') + ';return ' + exp
         var pathRE = new RegExp("\\b(" + vars.join('|') + ")[$\\w\\.]*\\b", 'g'),
-            paths  = exp.match(pathRE),
-            body   = 'return ' + exp.replace(pathRE, 'this.$&')
-        console.log(paths, body)
-        return {
-            getter: makeGetter(body, exp),
-            paths: paths
-        }
+            body   = 'return ' + exp.replace(pathRE, function (path) {
+                return 'this.' + getRel(path, compiler) + path
+            })
+        return makeGetter(body, exp)
     }
 }