let todo

function makeComputed (target, getter, sync) {
    let value
    const evaluate = () => {
        value = target::getter()
    }
    if (sync) {
        return function commputed () {
            if (arguments.length === 0) {
                return value
            }
            evaluate()
        }
    }
    let dirty = true
    return function commputed () {
        if (arguments.length === 0) {
            if (dirty) {
                evaluate()
                dirty = false
            }
            return value
        }
        dirty = true
    }
}

function watch (...expressions) {
    let deep = false
    let strict = false
    let sync = false
    return function toWatch (prototype, property, descriptor) {
        const isWatch = descriptor::hasOwnProperty('value')
        const lastArg = expressions[expressions.length - 1] || false
        if (typeof lastArg === 'boolean') {
            if (isWatch) {
                deep = lastArg
            } else {
                sync = lastArg
            }
            expressions.pop()
        } else if (typeof lastArg === 'object' && lastArg !== null) {
            deep = Boolean(lastArg.deep)
            strict = Boolean(lastArg.strict)
            sync = Boolean(lastArg.sync)
            expressions.pop()
        }

        let doWatch
        if (isWatch) {
            doWatch = function watch () {
                this.$watch(...expressions, {
                    callback: descriptor.value,
                    deep,
                    strict
                })
            }
        } else {
            doWatch = function commpute () {
                const {get: getter, set: setter} = descriptor
                const commputed = makeComputed(this, getter, sync)
                this.$watch(...expressions, {
                    callback: commputed,
                    deep,
                    strict
                })
                if (process.env.NODE_ENV === 'development') {
                    if (!this.$scope) {
                        throw new Error('Should inject $scope to Controller!')
                    }
                }
                const scope = this.$scope
                if (scope.hasOwnProperty(property)) {
                    return
                }
                Object.defineProperty(scope, property, {
                    get: commputed,
                    set: setter ? this::setter : undefined,
                    enumerable: true,
                    configurable: true
                })
            }
            descriptor.configurable = false
        }
        todo(prototype, doWatch)
    }
}

watch.install = function (ScopeController) {
    todo = ScopeController.$$todo
    function $watch (...args) {
        const options = args.pop()
        const expressions = args
        let callback, deep, strict
        if (typeof options === 'function') {
            callback = this::options
            deep = false
            strict = false
        } else {
            callback = this::options.callback
            deep = Boolean(options.deep)
            strict = Boolean(options.strict)
        }

        if (process.env.NODE_ENV === 'development') {
            if (!this.$scope) {
                throw new Error('Should inject $scope to Controller!')
            }
        }
        const scope = this.$scope
        if (expressions.length > 1) {
            return scope.$watchGroup(expressions, callback)
        }
        const [expression] = expressions
        if (deep) {
            return scope.$watchCollection(expression, callback)
        } else {
            return scope.$watch(expression, callback, strict)
        }
    }
    ScopeController.prototype.$watch = $watch
}


module.exports = watch

@@ -612,64 +612,37 @@
 let 
-deep = false%0A    let strict = false%0A    let sync = false
+immediate, strict, deep, sync
 %0A   
@@ -892,104 +892,78 @@
    i
-f (isWatch) %7B%0A                deep = lastArg%0A            %7D else %7B%0A                sync = lastArg
+mmediate = lastArg%0A            strict = false%0A            deep = false
 %0A   
@@ -963,33 +963,44 @@
 lse%0A            
-%7D
+sync = false
 %0A            exp
@@ -1088,36 +1088,41 @@
 ) %7B%0A            
-deep
+immediate
  = Boolean(lastA
@@ -1124,20 +1124,25 @@
 lastArg.
-deep
+immediate
 )%0A      
@@ -1172,32 +1172,73 @@
 lastArg.strict)%0A
+            deep = Boolean(lastArg.deep)%0A
             sync
@@ -1494,36 +1494,41 @@
                 
-deep
+immediate
 ,%0A              
@@ -1531,32 +1531,58 @@
           strict
+,%0A                    deep
 %0A               
@@ -1897,20 +1897,25 @@
         
-deep
+immediate
 ,%0A      
@@ -1930,24 +1930,50 @@
       strict
+,%0A                    deep
 %0A           
@@ -2906,20 +2906,25 @@
 ck, 
-deep
+immediate
 , strict
 %0A   
@@ -2919,16 +2919,22 @@
 , strict
+, deep
 %0A       
@@ -3012,36 +3012,41 @@
 ons%0A            
-deep
+immediate
  = false%0A       
@@ -3057,32 +3057,57 @@
  strict = false%0A
+            deep = false%0A
         %7D else %7B
@@ -3157,36 +3157,41 @@
 ack%0A            
-deep
+immediate
  = Boolean(optio
@@ -3193,20 +3193,25 @@
 options.
-deep
+immediate
 )%0A      
@@ -3241,32 +3241,395 @@
 options.strict)%0A
+            deep = Boolean(options.deep)%0A        %7D%0A%0A        if (!immediate) %7B%0A            const originCallback = callback%0A            let isFirst = true%0A            callback = function (...args) %7B%0A                if (isFirst) %7B%0A                    isFirst = false%0A                    return%0A                %7D%0A                originCallback(...args)%0A            %7D%0A
         %7D%0A%0A     

Support parameter `immediate` and set `immediate` with false defaultly in watch