-import { EMPTY_OBJ } from './utils'
+import { EMPTY_OBJ, NOOP } from './utils'
import { MountedComponent } from './component'
import { ComponentWatchOptions, WatchOptions } from './componentOptions'
import { autorun, stop } from '@vue/observer'
const rawGetter =
typeof keyOrFn === 'string'
- ? () => proxy[keyOrFn]
+ ? parseDotPath(keyOrFn, proxy)
: () => keyOrFn.call(proxy)
+ if (__DEV__ && rawGetter === NOOP) {
+ console.warn(
+ `Failed watching expression: "${keyOrFn}". ` +
+ `Watch expressions can only be dot-delimited paths. ` +
+ `For more complex expressions, use $watch with a function instead.`
+ )
+ }
+
const getter = options.deep ? () => traverse(rawGetter()) : rawGetter
let oldValue: any
}
}
+const bailRE = /[^\w.$]/
+
+function parseDotPath(path: string, ctx: any): Function {
+ if (bailRE.test(path)) {
+ return NOOP
+ }
+ const segments = path.split('.')
+ if (segments.length === 1) {
+ return () => ctx[path]
+ } else {
+ return () => {
+ let obj = ctx
+ for (let i = 0; i < segments.length; i++) {
+ if (!obj) return
+ obj = obj[segments[i]]
+ }
+ return obj
+ }
+ }
+}
+
function traverse(value: any, seen: Set<any> = new Set()) {
if (value === null || typeof value !== 'object' || seen.has(value)) {
return