Evan You %!s(int64=12) %!d(string=hai) anos
pai
achega
be19525402
Modificáronse 2 ficheiros con 228 adicións e 4 borrados
  1. 8 4
      src/instance/bindings.js
  2. 220 0
      src/parse/path.js

+ 8 - 4
src/instance/bindings.js

@@ -29,11 +29,15 @@ exports._initBindings = function () {
     root.addChild('$parent', this.$parent._rootBinding)
     root.addChild('$root', this.$root._rootBinding)
   }
+  var self = this
+  var updateBindings = function (path) {
+    self._updateBindings(path)
+  }
   this._observer
-    .on('set', this._updateBindings)
-    .on('add', this._updateBindings)
-    .on('delete', this._updateBindings)
-    .on('mutate', this._updateBindings)
+    .on('set', updateBindings)
+    .on('add', updateBindings)
+    .on('delete', updateBindings)
+    .on('mutate', updateBindings)
 }
 
 /**

+ 220 - 0
src/parse/path.js

@@ -0,0 +1,220 @@
+/**
+ * Path-parsing algorithm scooped from Polymer/observe-js
+ */
+
+var pathStateMachine = {
+  'beforePath': {
+    'ws': ['beforePath'],
+    'ident': ['inIdent', 'append'],
+    '[': ['beforeElement'],
+    'eof': ['afterPath']
+  },
+
+  'inPath': {
+    'ws': ['inPath'],
+    '.': ['beforeIdent'],
+    '[': ['beforeElement'],
+    'eof': ['afterPath']
+  },
+
+  'beforeIdent': {
+    'ws': ['beforeIdent'],
+    'ident': ['inIdent', 'append']
+  },
+
+  'inIdent': {
+    'ident': ['inIdent', 'append'],
+    '0': ['inIdent', 'append'],
+    'number': ['inIdent', 'append'],
+    'ws': ['inPath', 'push'],
+    '.': ['beforeIdent', 'push'],
+    '[': ['beforeElement', 'push'],
+    'eof': ['afterPath', 'push']
+  },
+
+  'beforeElement': {
+    'ws': ['beforeElement'],
+    '0': ['afterZero', 'append'],
+    'number': ['inIndex', 'append'],
+    "'": ['inSingleQuote', 'append', ''],
+    '"': ['inDoubleQuote', 'append', '']
+  },
+
+  'afterZero': {
+    'ws': ['afterElement', 'push'],
+    ']': ['inPath', 'push']
+  },
+
+  'inIndex': {
+    '0': ['inIndex', 'append'],
+    'number': ['inIndex', 'append'],
+    'ws': ['afterElement'],
+    ']': ['inPath', 'push']
+  },
+
+  'inSingleQuote': {
+    "'": ['afterElement'],
+    'eof': ['error'],
+    'else': ['inSingleQuote', 'append']
+  },
+
+  'inDoubleQuote': {
+    '"': ['afterElement'],
+    'eof': ['error'],
+    'else': ['inDoubleQuote', 'append']
+  },
+
+  'afterElement': {
+    'ws': ['afterElement'],
+    ']': ['inPath', 'push']
+  }
+}
+
+function noop () {}
+
+function getPathCharType (char) {
+  if (char === undefined)
+    return 'eof'
+
+  var code = char.charCodeAt(0)
+
+  switch(code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+    case 0x30: // 0
+      return char
+
+    case 0x5F: // _
+    case 0x24: // $
+      return 'ident'
+
+    case 0x20: // Space
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  // a-z, A-Z
+  if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
+    return 'ident'
+
+  // 1-9
+  if (0x31 <= code && code <= 0x39)
+    return 'number'
+
+  return 'else'
+}
+
+/**
+ * Parse a string path into an array of segments
+ * Todo implement cache
+ *
+ * @param {String} path
+ * @return {Array|undefined}
+ */
+
+exports.parse = function (path) {
+  var keys = []
+  var index = -1
+  var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath'
+
+  var actions = {
+    push: function() {
+      if (key === undefined)
+        return
+
+      keys.push(key)
+      key = undefined
+    },
+
+    append: function() {
+      if (key === undefined)
+        key = newChar
+      else
+        key += newChar
+    }
+  }
+
+  function maybeUnescapeQuote() {
+    if (index >= path.length)
+      return
+
+    var nextChar = path[index + 1]
+    if ((mode == 'inSingleQuote' && nextChar == "'") ||
+        (mode == 'inDoubleQuote' && nextChar == '"')) {
+      index++
+      newChar = nextChar
+      actions.append()
+      return true
+    }
+  }
+
+  while (mode) {
+    index++
+    c = path[index]
+
+    if (c == '\\' && maybeUnescapeQuote(mode))
+      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]] || noop
+    newChar = transition[2] === undefined ? c : transition[2]
+    action()
+
+    if (mode === 'afterPath') {
+      return keys
+    }
+  }
+
+  return // parse error
+}
+
+/**
+ * Get from an object from a path
+ *
+ * @param {Object} obj
+ * @param {String} path
+ */
+
+exports.get = function (obj, path) {
+  
+}
+
+/**
+ * Set on an object from a path
+ *
+ * @param {Object} obj
+ * @param {String} path
+ * @param {*} val
+ */
+
+exports.set = function (obj, path, val) {
+  
+}
+
+/**
+ * Traverse an object along a path and trigger callback
+ *
+ * @param {Object} obj
+ * @param {String} path
+ * @param {Function} cb
+ */
+
+exports.traverse = function (obj, path, cb) {
+  
+}