├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.en.md ├── README.md ├── bower.json ├── dev ├── index.html ├── index.js └── webpack.config.js ├── dist ├── smart-observe.js ├── smart-observe.js.map ├── smart-observe.min.js └── smart-observe.min.js.map ├── package.json ├── rollup.config.js ├── src ├── array.js ├── batcher.js ├── constants.js ├── dep.js ├── expression.js ├── index.js ├── observe.js ├── util.js └── watcher.js └── test └── test.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "babel-eslint", 4 | "extends": "standard", 5 | "rules": { 6 | "comma-dangle": [ 7 | "error", 8 | "only-multiline" 9 | ], 10 | "indent": [ 11 | "error", 12 | 2, 13 | { 14 | "SwitchCase": 1 15 | } 16 | ], 17 | "no-multiple-empty-lines": [ 18 | "error", 19 | { 20 | "max": 2 21 | } 22 | ], 23 | "operator-linebreak": [ 24 | "error", 25 | "before", 26 | { 27 | "overrides": { 28 | "=": "after" 29 | } 30 | } 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | npm-debug.log 5 | 6 | jsconfig.json 7 | .vscode 8 | 9 | dev 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "5" 5 | - "6" 6 | - "7" 7 | - "8" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 lon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | [中文](https://github.com/cnlon/smart-observe/blob/master/README.md) | English 2 | 3 | # smart-observe 4 | 5 | [![Build Status](https://travis-ci.org/cnlon/smart-observe.svg?branch=master)](https://travis-ci.org/cnlon/smart-observe) 6 | [![npm version](https://badge.fury.io/js/smart-observe.svg)](https://badge.fury.io/js/smart-observe) 7 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) 8 | 9 | 10 | **smart-observe** comes from [**Vue.js**](https://github.com/vuejs/vue) and is a small, efficient library for observing changes of javascript Object, Array and Class. 11 | 12 | ## Installation 13 | 14 | ``` bash 15 | npm install --save smart-observe 16 | ``` 17 | 18 | or 19 | 20 | ``` bash 21 | bower install --save smart-observe 22 | ``` 23 | 24 | ## Usage 25 | 26 | #### To watch expression. `observe.watch(target, expression, callback)` or `observe(target, expression, callback)` 27 | 28 | Try it on: 29 | [codepen](http://codepen.io/lon/pen/rrqLLk?editors=0010#0) 30 | [jsfiddle](https://jsfiddle.net/lon/x4n2yjLn/) 31 | 32 | ``` javascript 33 | const target = {a: 1} 34 | observe(target, 'a', function (newValue, oldValue) { 35 | console.log(newValue, oldValue) 36 | }) 37 | target.a = 3 38 | // 3 1 39 | ``` 40 | 41 | #### To add computed property. `observe.compute(target, name, getter)` 42 | 43 | Try it on: 44 | [codepen](http://codepen.io/lon/pen/dpgXLN?editors=0010#0) 45 | [jsfiddle](https://jsfiddle.net/lon/q402v3jd/) 46 | 47 | ``` javascript 48 | const target = {a: 1} 49 | observe.compute(target, 'b', function () { 50 | return this.a * 2 51 | }) 52 | console.log(target.b) 53 | // 2 54 | target.a = 3 55 | console.log(target.b) 56 | // 6 57 | ``` 58 | 59 | #### To watch expressions and computed properties. `observe.react(options)` 60 | 61 | Try it on: 62 | [codepen](http://codepen.io/lon/pen/zKmKqA?editors=0010#0) 63 | [jsfiddle](https://jsfiddle.net/lon/ufth8xpe/) 64 | 65 | ``` javascript 66 | const options = { 67 | data: { 68 | PI: Math.PI, 69 | radius: 1, 70 | }, 71 | computed: { 72 | 'area': function () { 73 | return this.PI * this.square(this.radius) // πr² 74 | }, 75 | }, 76 | watchers: { 77 | 'area': function (newValue, oldValue) { 78 | console.log(`area: ${newValue}`) 79 | }, 80 | }, 81 | methods: { 82 | square (num) { 83 | return num * num 84 | }, 85 | }, 86 | } 87 | const target = observe.react(options) 88 | target.radius = 3 89 | // area: 28.274333882308138 90 | ``` 91 | 92 | ## API 93 | 94 | #### properties 95 | 96 | | name | type | value | detail | 97 | | --- | --- | --- | --- | 98 | | `observe.deep` | `boolean` | The default is `false` | If `true`, `observe.watch(target, expression, callback)` will observe `target` deeply | 99 | | `observe.sync` | `boolean` | The default is `false` | If `true`, `observe.watch(target, expression, callback)` will invoke callback immediately when a property change is detected | 100 | | `observe.default` | `function` | Could only be one of `observe.react`, `observe.watch` and `observe.compute`. The default is `observe.watch` | Set actual method to `observe.default` for `observe(...)` | 101 | 102 | #### methods 103 | 104 | **`observe(...)`** 105 | 106 | - It's syntactic sugar of `observe.default`. See 'properties' for details 107 | 108 | **`observe.watch(target, expression, callback)`** 109 | 110 | - `target`: Any object 111 | - `expression`: `string` or `function` 112 | - `callback`: `function` 113 | - Returns `Watcher`. And calling `watcher.teardown()` could unwatch expression 114 | 115 | **`observe.compute(target, name, accessor, cache)`** 116 | 117 | - `target`: Any object 118 | - `name`: `string` 119 | - `accessor`: 120 | - `function`: It will be the `get` of accessor 121 | - `Object`: Contains: (at least `get` or `set`) 122 | - `get`: `function` 123 | - `set`: `function` 124 | - `cache`: `boolean`. Optional. The default is `true`. If `false`, the `get` will be evaluated whenever reading computed properties 125 | - `cache`: `boolean`. Same as `accessor.cache` 126 | 127 | **`observe.react(options, target)`** 128 | 129 | - `options`: `Object`. Contains: 130 | - `data`: It's the properties to add 131 | - `computed`: It's the computed properties to add 132 | - `watchers`: It's the watchers to watch properties or computed properties 133 | - `methods`: The methods to add. And these will bind to `target` 134 | - `target`: Any object. Optional. The default is empty object. It will be attached with the fields of `options` 135 | - returns `target` 136 | 137 | ## License 138 | 139 | [MIT](https://github.com/cnlon/smart-observe/blob/master/LICENSE) 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 中文 | [English](https://github.com/cnlon/smart-observe/blob/master/README.en.md) 2 | 3 | # smart-observe 4 | 5 | [![Build Status](https://travis-ci.org/cnlon/smart-observe.svg?branch=master)](https://travis-ci.org/cnlon/smart-observe) 6 | [![npm version](https://badge.fury.io/js/smart-observe.svg)](https://badge.fury.io/js/smart-observe) 7 | [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) 8 | 9 | **smart-observe** 来自 [**Vue.js**](https://github.com/vuejs/vue),是一个小巧、高效,用于监测 javascript 对象、数组、类 变化的库 10 | 11 | ## 安装 12 | 13 | ``` bash 14 | npm install --save smart-observe 15 | ``` 16 | 17 | 或 18 | 19 | ``` 20 | bower install --save smart-observe 21 | ``` 22 | 23 | ## 使用 24 | 25 | #### 监测属性 `observe.watch(target, expression, callback)` 或 `observe(target, expression, callback)` 26 | 27 | 试一试: 28 | [codepen](http://codepen.io/lon/pen/rrqLLk?editors=0010#0) 29 | [jsfiddle](https://jsfiddle.net/lon/x4n2yjLn/) 30 | 31 | ``` javascript 32 | const target = {a: 1} 33 | observe(target, 'a', function (newValue, oldValue) { 34 | console.log(newValue, oldValue) 35 | }) 36 | target.a = 3 37 | // 3 1 38 | ``` 39 | 40 | #### 添加计算属性 `observe.compute(target, name, getter)` 41 | 42 | 试一试: 43 | [codepen](http://codepen.io/lon/pen/dpgXLN?editors=0010#0) 44 | [jsfiddle](https://jsfiddle.net/lon/q402v3jd/) 45 | 46 | ``` javascript 47 | const target = {a: 1} 48 | observe.compute(target, 'b', function () { 49 | return this.a * 2 50 | }) 51 | console.log(target.b) 52 | // 2 53 | target.a = 3 54 | console.log(target.b) 55 | // 6 56 | ``` 57 | 58 | #### 监测属性并添加计算属性 `observe.react(options)` 59 | 60 | 试一试: 61 | [codepen](http://codepen.io/lon/pen/zKmKqA?editors=0010#0) 62 | [jsfiddle](https://jsfiddle.net/lon/ufth8xpe/) 63 | 64 | ``` javascript 65 | const options = { 66 | data: { 67 | PI: Math.PI, 68 | radius: 1, 69 | }, 70 | computed: { 71 | 'area': function () { 72 | return this.PI * this.square(this.radius) // πr² 73 | }, 74 | }, 75 | watchers: { 76 | 'area': function (newValue, oldValue) { 77 | console.log(`area: ${newValue}`) 78 | }, 79 | }, 80 | methods: { 81 | square (num) { 82 | return num * num 83 | }, 84 | }, 85 | } 86 | const target = observe.react(options) 87 | target.radius = 3 88 | // area: 28.274333882308138 89 | ``` 90 | 91 | ## API 92 | 93 | #### 属性 94 | 95 | | 名称 | 类型 | 值 | 说明 | 96 | | --- | --- | --- | --- | 97 | | `observe.deep` | `boolean` | 默认为 `false` | 如果为 `true`,`observe.watch(target, expression, callback)` 将会对 `target` 深度监测 | 98 | | `observe.sync` | `boolean` | 默认为 `false` | 如果为 `true`,`observe.watch(target, expression, callback)` 监测到属性变化时,立即调用回调函数 | 99 | | `observe.default` | `function` | 只能为 `observe.react`,`observe.watch` 或 `observe.compute`, 默认为 `observe.watch` | 设置 `observe(...)` 实际调用的方法,写起来简洁一些 | 100 | 101 | #### 方法 102 | 103 | **`observe(...)`** 104 | 105 | - 为方法 `observe.default` 的语法糖,`observe.default` 参见属性 106 | 107 | **`observe.watch(target, expression, callback)`** 108 | 109 | - `target`: 任意对象 110 | - `expression`: `string` 或 `function` 111 | - `callback`: `function` 112 | - 返回 `Watcher`,调用 `watcher.teardown()` 可以取消监测 113 | 114 | **`observe.compute(target, name, accessor, cache)`** 115 | 116 | - `target`: 任意对象 117 | - `name`: `string` 118 | - `accessor`: 119 | - `function`: 会作为 `getter`,等同传入 {get: accessor} 120 | - `Object`: 可以包含:(其中,至少包含 `get` 或 `set`) 121 | - `get`: `function` 122 | - `set`: `function` 123 | - `cache`: `boolean`,可选,默认为 `true`,如果设为 `false`,每次读取计算属性都要重新计算 124 | - `cache`: `boolean`,可选,默认为 `true`,仅当 `accessor` 为 `function` 时有效。 125 | 126 | **`observe.react(options, target)`** 127 | 128 | - `options`: `Object`,要配置的参数集合,可以包含: 129 | - `data`: 要附加的字段 130 | - `computed`: 要附加的计算属性 131 | - `watchers`: 要监测的属性和计算属性 132 | - `methods`: 要附加的方法,这些方法将会自动绑定 `target` 133 | - `target`: 任意对象,可选,默认为空对象,`options` 的参数将附加到此对象上 134 | - 返回 `target` 135 | 136 | ## License 137 | 138 | [MIT](https://github.com/cnlon/smart-observe/blob/master/LICENSE) 139 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smart-observe", 3 | "description": "smart-observe comes from Vue.js and is a small, efficient library for observing changes of javascript Object, Array and Class.", 4 | "main": "dist/smart-observe.js", 5 | "keywords": [ 6 | "observe", 7 | "observer", 8 | "watch", 9 | "watcher", 10 | "computed", 11 | "vue", 12 | "vue.js", 13 | "ob.js", 14 | "ob" 15 | ], 16 | "authors": [ 17 | "lon (http://lon.im)" 18 | ], 19 | "license": "MIT", 20 | "homepage": "https://github.com/cnlon/smart-observe", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components", 25 | "test", 26 | "dev" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dev/index.js: -------------------------------------------------------------------------------- 1 | import observe from 'smart-observe' 2 | 3 | window.onload = function () { 4 | const target = window.d = observe.react({ 5 | data: { 6 | PI: Math.PI, 7 | radius: 2, 8 | }, 9 | computed: { 10 | 'area': function () { 11 | return this.PI * this.square(this.radius) 12 | }, 13 | }, 14 | watchers: { 15 | 'area': function (newValue, oldValue) { 16 | console.log(newValue) 17 | }, 18 | }, 19 | methods: { 20 | square (num) { 21 | return num * num 22 | }, 23 | }, 24 | }) 25 | target.radius = 3 26 | console.dir(target) 27 | } 28 | -------------------------------------------------------------------------------- /dev/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const config = { 4 | entry: { 5 | app: './dev/index.js', 6 | }, 7 | output: { 8 | path: path.resolve(__dirname, './build'), 9 | filename: 'dev.js', 10 | }, 11 | module: { 12 | loaders: [ 13 | { 14 | test: /\.js$/, 15 | exclude: /node_modules/, 16 | loader: 'babel', 17 | }, 18 | ], 19 | }, 20 | babel: { 21 | presets: ['es2015'], 22 | plugins: ['transform-class-properties'], 23 | }, 24 | devtool: 'eval', 25 | resolve: { 26 | alias: { 27 | 'smart-observe': path.resolve(__dirname, '../src/index.js'), 28 | }, 29 | }, 30 | } 31 | 32 | module.exports = config 33 | -------------------------------------------------------------------------------- /dist/smart-observe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * smart-observe --- By lon 3 | * https://github.com/cnlon/smart-observe 4 | */ 5 | (function (global, factory) { 6 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 7 | typeof define === 'function' && define.amd ? define('observe', factory) : 8 | (global.observe = factory()); 9 | }(this, (function () { 'use strict'; 10 | 11 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { 12 | return typeof obj; 13 | } : function (obj) { 14 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 15 | }; 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | var classCallCheck = function (instance, Constructor) { 28 | if (!(instance instanceof Constructor)) { 29 | throw new TypeError("Cannot call a class as a function"); 30 | } 31 | }; 32 | 33 | var createClass = function () { 34 | function defineProperties(target, props) { 35 | for (var i = 0; i < props.length; i++) { 36 | var descriptor = props[i]; 37 | descriptor.enumerable = descriptor.enumerable || false; 38 | descriptor.configurable = true; 39 | if ("value" in descriptor) descriptor.writable = true; 40 | Object.defineProperty(target, descriptor.key, descriptor); 41 | } 42 | } 43 | 44 | return function (Constructor, protoProps, staticProps) { 45 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 46 | if (staticProps) defineProperties(Constructor, staticProps); 47 | return Constructor; 48 | }; 49 | }(); 50 | 51 | var uid = 0; 52 | 53 | /** 54 | * A dep is an observable that can have multiple 55 | * watcher subscribing to it. 56 | */ 57 | 58 | var Dep = function () { 59 | function Dep() { 60 | classCallCheck(this, Dep); 61 | 62 | this.id = uid++; 63 | this.subs = []; 64 | } 65 | 66 | /** 67 | * Add a subscriber. 68 | * 69 | * @param {Watcher} sub 70 | */ 71 | 72 | // the current target watcher being evaluated. 73 | // this is globally unique because there could be only one 74 | // watcher being evaluated at any time. 75 | 76 | 77 | createClass(Dep, [{ 78 | key: "addSub", 79 | value: function addSub(sub) { 80 | this.subs.push(sub); 81 | } 82 | 83 | /** 84 | * Remove a subscriber. 85 | * 86 | * @param {Watcher} sub 87 | */ 88 | 89 | }, { 90 | key: "removeSub", 91 | value: function removeSub(sub) { 92 | this.subs.$remove(sub); 93 | } 94 | 95 | /** 96 | * Add self as a dependency to the target watcher. 97 | */ 98 | 99 | }, { 100 | key: "depend", 101 | value: function depend() { 102 | Dep.target.addDep(this); 103 | } 104 | 105 | /** 106 | * Notify all subscribers of a new value. 107 | */ 108 | 109 | }, { 110 | key: "notify", 111 | value: function notify() { 112 | var subs = this.subs; 113 | for (var i = 0, l = subs.length; i < l; i++) { 114 | subs[i].update(); 115 | } 116 | } 117 | }]); 118 | return Dep; 119 | }(); 120 | 121 | Dep.target = null; 122 | 123 | var OBSERVE_NAME = '__s_o__'; 124 | var WATCHERS_PROPERTY_NAME = '__watchers__'; 125 | var DATA_PROPTERTY_NAME = '__data__'; 126 | 127 | var DEBUGGING = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'; 128 | 129 | /** 130 | * Define property with value. 131 | * 132 | * @param {Object} object 133 | * @param {String} property 134 | * @param {*} value 135 | * @param {Boolean} [enumerable] 136 | */ 137 | 138 | function defineValue(object, property, value, enumerable) { 139 | Object.defineProperty(object, property, { 140 | value: value, 141 | enumerable: !!enumerable, 142 | writable: true, 143 | configurable: true 144 | }); 145 | } 146 | 147 | /** 148 | * Define property with getter and setter. 149 | * 150 | * @param {Object} object 151 | * @param {String} property 152 | * @param {Function} getter 153 | * @param {Function} setter 154 | */ 155 | 156 | function defineAccessor(object, property, getter, setter) { 157 | Object.defineProperty(object, property, { 158 | get: getter, 159 | set: setter, 160 | enumerable: true, 161 | configurable: true 162 | }); 163 | } 164 | 165 | /** 166 | * Array type check. 167 | * 168 | * @return {Boolean} 169 | */ 170 | 171 | var isArray = Array.isArray; 172 | 173 | /** 174 | * Strict object type check. Only returns true 175 | * for plain JavaScript objects. 176 | * 177 | * @param {*} object 178 | * @return {Boolean} 179 | */ 180 | 181 | var toString = Object.prototype.toString; 182 | var OBJECT_STRING = '[object Object]'; 183 | function isPlainObject(object) { 184 | return toString.call(object) === OBJECT_STRING; 185 | } 186 | 187 | /** 188 | * Quick object check - this is primarily used to tell 189 | * Objects from primitive values when we know the value 190 | * is a JSON-compliant type. 191 | * 192 | * @param {*} object 193 | * @return {Boolean} 194 | */ 195 | 196 | function isObject(object) { 197 | return object !== null && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object'; 198 | } 199 | 200 | /** 201 | * Function type check 202 | * 203 | * @param {*} func 204 | * @param {Boolean} 205 | */ 206 | 207 | function isFunction(func) { 208 | return typeof func === 'function'; 209 | } 210 | 211 | /** 212 | * Iterate object 213 | * 214 | * @param {Object} object 215 | * @param {Function} callback 216 | */ 217 | 218 | function everyEntries(object, callback) { 219 | var keys = Object.keys(object); 220 | for (var i = 0, l = keys.length; i < l; i++) { 221 | callback(keys[i], object[keys[i]]); 222 | } 223 | } 224 | 225 | /** 226 | * noop is function which is nothing to do. 227 | */ 228 | 229 | function noop() {} 230 | 231 | /** 232 | * @param {String} string 233 | */ 234 | 235 | var warn = typeof DEBUGGING !== 'undefined' && DEBUGGING && typeof console !== 'undefined' && console && isFunction(console.warn) ? console.warn : noop; 236 | 237 | var _Set = void 0; 238 | if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) { 239 | // use native Set when available. 240 | _Set = Set; 241 | } else { 242 | // a non-standard Set polyfill that only works with primitive keys. 243 | _Set = function _Set() { 244 | this.set = Object.create(null); 245 | }; 246 | _Set.prototype.has = function (key) { 247 | return this.set[key] !== undefined; 248 | }; 249 | _Set.prototype.add = function (key) { 250 | this.set[key] = 1; 251 | }; 252 | _Set.prototype.clear = function () { 253 | this.set = Object.create(null); 254 | }; 255 | } 256 | 257 | var arrayPrototype = Array.prototype; 258 | var arrayMethods = Object.create(arrayPrototype); 259 | var arrayMutativeMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; 260 | 261 | /** 262 | * Augment an target Array with arrayMethods 263 | * 264 | * @param {Array} array 265 | */ 266 | 267 | function amend(array) { 268 | Object.setPrototypeOf(array, arrayMethods); 269 | } 270 | 271 | /** 272 | * Intercept mutating methods and emit events 273 | */ 274 | 275 | var _loop = function _loop(i, l) { 276 | var method = arrayMutativeMethods[i]; 277 | // cache original method 278 | var original = arrayPrototype[method]; 279 | defineValue(arrayMethods, method, function mutator() { 280 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 281 | args[_key] = arguments[_key]; 282 | } 283 | 284 | var result = original.apply(this, args); 285 | var observer = this[OBSERVE_NAME]; 286 | var inserted = void 0; 287 | switch (method) { 288 | case 'push': 289 | inserted = args; 290 | break; 291 | case 'unshift': 292 | inserted = args; 293 | break; 294 | case 'splice': 295 | inserted = args.slice(2); 296 | break; 297 | } 298 | if (inserted) observer.observeArray(inserted); 299 | observer.dep.notify(); // notify change 300 | return result; 301 | }); 302 | }; 303 | 304 | for (var i = 0, l = arrayMutativeMethods.length; i < l; i++) { 305 | _loop(i, l); 306 | } 307 | 308 | /** 309 | * Swap the element at the given index with a new value 310 | * and emits corresponding event. 311 | * 312 | * @param {Number} index 313 | * @param {*} value 314 | * @return {*} - replaced element 315 | */ 316 | 317 | function $set(index, value) { 318 | if (index >= this.length) { 319 | this.length = Number(index) + 1; 320 | } 321 | return this.splice(index, 1, value)[0]; 322 | } 323 | defineValue(arrayPrototype, '$set', $set); 324 | 325 | /** 326 | * Convenience method to remove the element at given index 327 | * or target element reference. 328 | * 329 | * @param {*} item 330 | * @return {*} - removed element 331 | */ 332 | 333 | function $remove(item) { 334 | if (!this.length) return; 335 | var index = this.indexOf(item); 336 | if (index > -1) { 337 | return this.splice(index, 1); 338 | } 339 | } 340 | defineValue(arrayPrototype, '$remove', $remove); 341 | 342 | /** 343 | * Observer class that are attached to each observed 344 | * object. Once attached, the observer converts target 345 | * object's property keys into getter/setters that 346 | * collect dependencies and dispatches updates. 347 | * 348 | * @class 349 | * @param {Array|Object} value 350 | */ 351 | 352 | var Observer = function () { 353 | function Observer(value) { 354 | classCallCheck(this, Observer); 355 | 356 | this.value = value; 357 | this.dep = new Dep(); 358 | defineValue(value, OBSERVE_NAME, this); 359 | if (isArray(value)) { 360 | amend(value); 361 | this.observeArray(value); 362 | } else { 363 | this.walk(value); 364 | } 365 | } 366 | 367 | /** 368 | * Walk through each property and convert them into 369 | * getter/setters. This method should only be called when 370 | * value type is Object. 371 | * 372 | * @param {Object} object 373 | */ 374 | 375 | createClass(Observer, [{ 376 | key: 'walk', 377 | value: function walk(object) { 378 | var _this = this; 379 | 380 | everyEntries(object, function (key, value) { 381 | return _this.convert(key, value); 382 | }); 383 | } 384 | 385 | /** 386 | * Observe a list of Array items. 387 | * 388 | * @param {Array} items 389 | */ 390 | 391 | }, { 392 | key: 'observeArray', 393 | value: function observeArray(items) { 394 | for (var i = 0, l = items.length; i < l; i++) { 395 | observe$1(items[i]); 396 | } 397 | } 398 | 399 | /** 400 | * Convert a property into getter/setter so we can emit 401 | * the events when the property is accessed/changed. 402 | * 403 | * @param {String} key 404 | * @param {*} value 405 | */ 406 | 407 | }, { 408 | key: 'convert', 409 | value: function convert(key, value) { 410 | defineReactive(this.value, key, value); 411 | } 412 | }]); 413 | return Observer; 414 | }(); 415 | 416 | /** 417 | * Attempt to create an observer instance for a value, 418 | * returns the new observer if successfully observed, 419 | * or the existing observer if the value already has one. 420 | * 421 | * @param {*} value 422 | * @return {Observer|undefined} 423 | */ 424 | 425 | function observe$1(value) { 426 | if (!value || (typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') return; 427 | var observer = void 0; 428 | if (Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME) && value[OBSERVE_NAME] instanceof Observer) { 429 | observer = value[OBSERVE_NAME]; 430 | } else if ((isArray(value) || isPlainObject(value)) && Object.isExtensible(value)) { 431 | observer = new Observer(value); 432 | } 433 | return observer; 434 | } 435 | 436 | /** 437 | * Define a reactive property on an Object. 438 | * 439 | * @param {Object} object 440 | * @param {String} key 441 | * @param {*} value 442 | */ 443 | 444 | function defineReactive(object, key, value) { 445 | var dep = new Dep(); 446 | 447 | var desc = Object.getOwnPropertyDescriptor(object, key); 448 | if (desc && desc.configurable === false) return; 449 | 450 | // cater for pre-defined getter/setters 451 | var getter = desc && desc.get; 452 | var setter = desc && desc.set; 453 | 454 | var childOb = observe$1(value); 455 | 456 | function reactiveGetter() { 457 | var currentValue = getter ? getter.call(object) : value; 458 | if (Dep.target) { 459 | dep.depend(); 460 | if (childOb) { 461 | childOb.dep.depend(); 462 | } 463 | if (isArray(currentValue)) { 464 | for (var i = 0, l = currentValue.length, e; i < l; i++) { 465 | e = currentValue[i]; 466 | e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend(); 467 | } 468 | } 469 | } 470 | return currentValue; 471 | } 472 | function reactiveSetter(newValue) { 473 | var oldValue = getter ? getter.call(object) : value; 474 | if (newValue === oldValue) return; 475 | if (setter) { 476 | setter.call(object, newValue); 477 | } else { 478 | value = newValue; 479 | } 480 | childOb = observe$1(newValue); 481 | dep.notify(); 482 | } 483 | defineAccessor(object, key, reactiveGetter, reactiveSetter); 484 | } 485 | 486 | /** 487 | * Build a getter function. Requires eval. 488 | * 489 | * We isolate the try/catch so it doesn't affect the 490 | * optimization of the parse function when it is not called. 491 | * 492 | * @param {String} body 493 | * @return {Function|undefined} 494 | */ 495 | 496 | function makeGetterFunction(body) { 497 | try { 498 | /* eslint-disable no-new-func */ 499 | return new Function('scope', 'return ' + body + ';'); 500 | /* eslint-enable no-new-func */ 501 | } catch (e) { 502 | warn('Invalid expression. Generated function body: ' + body); 503 | } 504 | } 505 | 506 | /** 507 | * Parse an expression to getter. 508 | * 509 | * @param {String} expression 510 | * @return {Function|undefined} 511 | */ 512 | 513 | function parse(expression) { 514 | expression = String.prototype.trim.call(expression); 515 | return makeGetterFunction('scope.' + expression); 516 | } 517 | 518 | var callbacks = []; 519 | var pending = false; 520 | function nextTickHandler() { 521 | pending = false; 522 | var callbackCopies = callbacks.slice(0); 523 | callbacks.length = 0; 524 | for (var i = 0; i < callbackCopies.length; i++) { 525 | callbackCopies[i](); 526 | } 527 | } 528 | 529 | var callNextTick; 530 | if ((typeof process === 'undefined' ? 'undefined' : _typeof(process)) === 'object' && process && typeof process.nextTick === 'function') { 531 | callNextTick = process.nextTick; 532 | } else if (typeof MutationObserver !== 'undefined') { 533 | var counter = 0; 534 | var textNode = document.createTextNode(counter); 535 | var observer = new MutationObserver(nextTickHandler); 536 | observer.observe(textNode, { 537 | characterData: true 538 | }); 539 | callNextTick = function callNextTick() { 540 | counter = counter === 0 ? 1 : 0; 541 | textNode.data = String(counter); 542 | }; 543 | } else { 544 | callNextTick = setTimeout; 545 | } 546 | 547 | var nextTick = function nextTick(callback, context) { 548 | var func = callback; 549 | if (context) { 550 | var args = []; 551 | var l = arguments.length; 552 | while (--l > 1) { 553 | args.unshift(arguments[l]); 554 | } 555 | func = function func() { 556 | callback.apply(context, args); 557 | }; 558 | } 559 | callbacks.push(func); 560 | if (pending) { 561 | return; 562 | } 563 | pending = true; 564 | callNextTick(nextTickHandler); 565 | }; 566 | 567 | var queue = []; 568 | var has = {}; 569 | var waiting = false; 570 | var queueIndex = void 0; 571 | 572 | /** 573 | * Reset the batcher's state. 574 | */ 575 | 576 | function resetBatcherState() { 577 | queue = []; 578 | has = {}; 579 | waiting = false; 580 | } 581 | 582 | /** 583 | * Flush queue and run the watchers. 584 | */ 585 | 586 | function flushBatcherQueue() { 587 | runBatcherQueue(queue); 588 | resetBatcherState(); 589 | } 590 | 591 | /** 592 | * Run the watchers in a single queue. 593 | * 594 | * @param {Array} queue 595 | */ 596 | 597 | function runBatcherQueue(queue) { 598 | // do not cache length because more watchers might be pushed 599 | // as we run existing watchers 600 | for (queueIndex = 0; queueIndex < queue.length; queueIndex++) { 601 | var watcher = queue[queueIndex]; 602 | var id = watcher.id; 603 | has[id] = null; 604 | watcher.run(); 605 | } 606 | } 607 | 608 | /** 609 | * Push a watcher into the watcher queue. 610 | * Jobs with duplicate IDs will be skipped unless it's 611 | * pushed when the queue is being flushed. 612 | * 613 | * @param {Watcher} watcher 614 | * properties: 615 | * - {Number} id 616 | * - {Function} run 617 | */ 618 | 619 | function batch(watcher) { 620 | var id = watcher.id; 621 | if (has[id] == null) { 622 | has[id] = queue.length; 623 | queue.push(watcher); 624 | // queue the flush 625 | if (!waiting) { 626 | waiting = true; 627 | nextTick(flushBatcherQueue); 628 | } 629 | } 630 | } 631 | 632 | var uid$1 = 0; 633 | 634 | var Watcher = function () { 635 | 636 | /** 637 | * A watcher parses an expression, collects dependencies, 638 | * and fires callback when the expression value changes. 639 | * 640 | * @param {Object} owner 641 | * @param {String|Function} getter 642 | * @param {Function} callback 643 | * @param {Object} options 644 | * - {Boolean} deep 645 | * - {Boolean} sync 646 | * - {Boolean} lazy 647 | * @constructor 648 | */ 649 | 650 | function Watcher(owner, getter, callback, options) { 651 | classCallCheck(this, Watcher); 652 | 653 | owner[WATCHERS_PROPERTY_NAME].push(this); 654 | this.owner = owner; 655 | this.getter = getter; 656 | this.callback = callback; 657 | this.options = options; 658 | // uid for batching 659 | this.id = ++uid$1; 660 | this.active = true; 661 | // for lazy watchers 662 | this.dirty = options.lazy; 663 | this.deps = []; 664 | this.newDeps = []; 665 | this.depIds = new _Set(); 666 | this.newDepIds = new _Set(); 667 | this.value = options.lazy ? undefined : this.get(); 668 | } 669 | 670 | /** 671 | * Evaluate the getter, and re-collect dependencies. 672 | */ 673 | 674 | createClass(Watcher, [{ 675 | key: 'get', 676 | value: function get$$1() { 677 | this.beforeGet(); 678 | var scope = this.owner; 679 | var value = this.getter.call(scope, scope); 680 | if (this.options.deep) { 681 | traverse(value); 682 | } 683 | this.afterGet(); 684 | return value; 685 | } 686 | 687 | /** 688 | * Prepare for dependency collection. 689 | */ 690 | 691 | }, { 692 | key: 'beforeGet', 693 | value: function beforeGet() { 694 | Dep.target = this; 695 | } 696 | 697 | /** 698 | * Add a dependency to this directive. 699 | * 700 | * @param {Dep} dep 701 | */ 702 | 703 | }, { 704 | key: 'addDep', 705 | value: function addDep(dep) { 706 | var id = dep.id; 707 | if (!this.newDepIds.has(id)) { 708 | this.newDepIds.add(id); 709 | this.newDeps.push(dep); 710 | if (!this.depIds.has(id)) { 711 | dep.addSub(this); 712 | } 713 | } 714 | } 715 | 716 | /** 717 | * Clean up for dependency collection. 718 | */ 719 | 720 | }, { 721 | key: 'afterGet', 722 | value: function afterGet() { 723 | Dep.target = null; 724 | var i = this.deps.length; 725 | while (i--) { 726 | var dep = this.deps[i]; 727 | if (!this.newDepIds.has(dep.id)) { 728 | dep.removeSub(this); 729 | } 730 | } 731 | var tmp = this.depIds; 732 | this.depIds = this.newDepIds; 733 | this.newDepIds = tmp; 734 | this.newDepIds.clear(); 735 | tmp = this.deps; 736 | this.deps = this.newDeps; 737 | this.newDeps = tmp; 738 | this.newDeps.length = 0; 739 | } 740 | 741 | /** 742 | * Will be called when a dependency changes. 743 | */ 744 | 745 | }, { 746 | key: 'update', 747 | value: function update() { 748 | if (this.options.lazy) { 749 | this.dirty = true; 750 | } else if (this.options.sync) { 751 | this.run(); 752 | } else { 753 | batch(this); 754 | } 755 | } 756 | 757 | /** 758 | * Will be called by the batcher. 759 | */ 760 | 761 | }, { 762 | key: 'run', 763 | value: function run() { 764 | if (this.active) { 765 | var value = this.get(); 766 | if (value !== this.value 767 | // Deep watchers and watchers on Object/Arrays should fire even when 768 | // the value is the same, because the value may have mutated; 769 | || isObject(value) || this.options.deep) { 770 | var oldValue = this.value; 771 | this.value = value; 772 | this.callback.call(this.owner, value, oldValue); 773 | } 774 | } 775 | } 776 | 777 | /** 778 | * Evaluate the value of the watcher. 779 | * This only gets called for lazy watchers. 780 | */ 781 | 782 | }, { 783 | key: 'evaluate', 784 | value: function evaluate() { 785 | // avoid overwriting another watcher that is being collected. 786 | var current = Dep.target; 787 | this.value = this.get(); 788 | this.dirty = false; 789 | Dep.target = current; 790 | } 791 | 792 | /** 793 | * Depend on all deps collected by this watcher. 794 | */ 795 | 796 | }, { 797 | key: 'depend', 798 | value: function depend() { 799 | var i = this.deps.length; 800 | while (i--) { 801 | this.deps[i].depend(); 802 | } 803 | } 804 | 805 | /** 806 | * Remove self from all dependencies' subcriber list. 807 | */ 808 | 809 | }, { 810 | key: 'teardown', 811 | value: function teardown() { 812 | if (this.active) { 813 | var i = this.deps.length; 814 | while (i--) { 815 | this.deps[i].removeSub(this); 816 | } 817 | this.active = false; 818 | this.owner = this.callback = this.value = null; 819 | } 820 | } 821 | }]); 822 | return Watcher; 823 | }(); 824 | 825 | /** 826 | * Recrusively traverse an object to evoke all converted 827 | * getters, so that every nested property inside the object 828 | * is collected as a "deep" dependency. 829 | * 830 | * @param {*} value 831 | */ 832 | 833 | function traverse(value) { 834 | var i = void 0, 835 | keys = void 0; 836 | if (isArray(value)) { 837 | i = value.length; 838 | while (i--) { 839 | traverse(value[i]); 840 | } 841 | } else if (isObject(value)) { 842 | keys = Object.keys(value); 843 | i = keys.length; 844 | while (i--) { 845 | traverse(value[keys[i]]); 846 | } 847 | } 848 | } 849 | 850 | /** 851 | * Create an watcher instance, returns the new watcher. 852 | * 853 | * @param {Object} owner 854 | * @param {String|Function} expressionOrFunction 855 | * @param {Function} callback 856 | * @param {Object} options 857 | * - {Boolean} deep 858 | * - {Boolean} sync 859 | * - {Boolean} lazy 860 | * @return {Watcher} 861 | */ 862 | 863 | function watch$1(owner, expressionOrFunction, callback, options) { 864 | // parse expression for getter 865 | var getter = isFunction(expressionOrFunction) ? expressionOrFunction : parse(expressionOrFunction); 866 | return new Watcher(owner, getter, callback, options); 867 | } 868 | 869 | /** 870 | * Make a computed getter, which can collect dependencies. 871 | * 872 | * @param {Object} owner 873 | * @param {Function} getter 874 | */ 875 | 876 | function makeComputed(owner, getter) { 877 | var watcher = new Watcher(owner, getter, null, { 878 | deep: observe$$1.deep, 879 | lazy: true, 880 | sync: observe$$1.sync 881 | }); 882 | return function computedGetter() { 883 | if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) { 884 | watcher.options.lazy = false; 885 | watcher.callback = function () { 886 | var deps = watcher.deps; 887 | for (var i = 0, l = deps.length; i < l; i++) { 888 | deps[i].notify(); 889 | } 890 | }; 891 | } 892 | if (watcher.dirty) { 893 | watcher.evaluate(); 894 | } 895 | if (Dep.target) { 896 | watcher.depend(); 897 | } 898 | return watcher.value; 899 | }; 900 | } 901 | 902 | Object.defineProperties(observe$$1, { 903 | 'react': { value: react }, 904 | 'compute': { value: compute }, 905 | 'watch': { value: watch$$1 }, 906 | 'default': { value: watch$$1, writable: true }, // Only could be react, compute or watch 907 | 'deep': { value: false, writable: true }, 908 | 'lazy': { value: false, writable: true }, 909 | 'sync': { value: false, writable: true } 910 | }); 911 | 912 | /** 913 | * observe 914 | * 915 | * @public 916 | * @param {Object} target 917 | * @param {*} [expression] 918 | * @param {*} [func] 919 | * @param {*} [options] 920 | * @return {Function} observe 921 | */ 922 | 923 | function observe$$1(target, expression, func, options) { 924 | ensure(target); 925 | return observe$$1.default(target, expression, func, options); 926 | } 927 | 928 | /** 929 | * React options 930 | * 931 | * @param {Object} options 932 | * @param {Object} [target] 933 | * @return {Function} observe 934 | */ 935 | 936 | function react(options, target) { 937 | if (target) { 938 | ensure(target); 939 | } else { 940 | target = {}; 941 | init(target); 942 | } 943 | options.methods && carryMethods(target, options.methods); 944 | options.data && reactProperties(target, options.data); 945 | options.computed && computeProperties(target, options.computed); 946 | options.watchers && watchProperties(target, options.watchers); 947 | return target; 948 | } 949 | 950 | /** 951 | * Compute property 952 | * 953 | * @param {Object} target 954 | * @param {String} name 955 | * @param {Function|Object} getterOrAccessor 956 | * - Function getter 957 | * - Object accessor 958 | * - Function [get] - getter 959 | * - Function [set] - setter 960 | * - Boolean [cache] 961 | * @param {Boolean} [cache] 962 | */ 963 | 964 | function compute(target, name, getterOrAccessor, cache) { 965 | ensure(target); 966 | var getter = void 0, 967 | setter = void 0; 968 | if (isFunction(getterOrAccessor)) { 969 | getter = cache !== false ? makeComputed(target, getterOrAccessor) : getterOrAccessor.bind(this); 970 | setter = noop; 971 | } else { 972 | getter = getterOrAccessor.get ? getterOrAccessor.cache !== false || cache !== false ? makeComputed(target, getterOrAccessor.get) : getterOrAccessor.get.bind(this) : noop; 973 | setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop; 974 | } 975 | defineAccessor(target, name, getter, setter); 976 | } 977 | 978 | /** 979 | * Watch property 980 | * 981 | * @param {Object} target 982 | * @param {String|Function} expressionOrFunction 983 | * @param {Function} callback 984 | * @param {Object} [options] 985 | * - {Boolean} deep 986 | * - {Boolean} sync 987 | * - {Boolean} lazy 988 | * @return {Watcher} 989 | */ 990 | 991 | function watch$$1(target, expressionOrFunction, callback) { 992 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : observe$$1; 993 | 994 | ensure(target); 995 | return watch$1(target, expressionOrFunction, callback, options); 996 | } 997 | 998 | /** 999 | * @param {Object} target 1000 | */ 1001 | 1002 | function init(target) { 1003 | defineValue(target, WATCHERS_PROPERTY_NAME, [], false); 1004 | defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false); 1005 | observe$1(target[DATA_PROPTERTY_NAME]); 1006 | reactSelfProperties(target); 1007 | } 1008 | 1009 | function ensure(target) { 1010 | if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) { 1011 | init(target); 1012 | } 1013 | } 1014 | 1015 | /** 1016 | * @param {Object} target 1017 | * @param {Object} methods 1018 | */ 1019 | 1020 | function carryMethods(target, methods) { 1021 | everyEntries(methods, function (name, method) { 1022 | target[name] = method.bind(target); 1023 | }); 1024 | } 1025 | 1026 | /** 1027 | * @param {Object} target 1028 | * @param {String} key 1029 | * @param {*} value 1030 | */ 1031 | 1032 | function reactProperty(target, key, value) { 1033 | target[DATA_PROPTERTY_NAME][key] = value; 1034 | defineReactive(target[DATA_PROPTERTY_NAME], key, value); 1035 | proxy(target, key); 1036 | } 1037 | 1038 | /** 1039 | * @param {Object} target 1040 | * @param {Object} properties 1041 | */ 1042 | 1043 | function reactProperties(target, properties) { 1044 | everyEntries(properties, function (key, value) { 1045 | return reactProperty(target, key, value); 1046 | }); 1047 | } 1048 | 1049 | /** 1050 | * @param {Object} target 1051 | */ 1052 | 1053 | function reactSelfProperties(target) { 1054 | everyEntries(target, function (key, value) { 1055 | !isFunction(value) && reactProperty(target, key, value); 1056 | }); 1057 | } 1058 | 1059 | /** 1060 | * @param {Object} target 1061 | * @param {Object} properties 1062 | */ 1063 | 1064 | function computeProperties(target, properties) { 1065 | everyEntries(properties, function (key, value) { 1066 | return compute(target, key, value); 1067 | }); 1068 | } 1069 | 1070 | /** 1071 | * @param {Object} target 1072 | * @param {Object} properties 1073 | */ 1074 | 1075 | function watchProperties(target, properties) { 1076 | everyEntries(properties, function (expression, functionOrOption) { 1077 | if (isFunction(functionOrOption)) { 1078 | watch$$1(target, expression, functionOrOption); 1079 | } else { 1080 | watch$$1(target, expression, functionOrOption.watcher, functionOrOption); 1081 | } 1082 | }); 1083 | } 1084 | 1085 | /** 1086 | * @param {Object} target 1087 | * @param {String} key 1088 | */ 1089 | 1090 | function proxy(target, key) { 1091 | function getter() { 1092 | return target[DATA_PROPTERTY_NAME][key]; 1093 | } 1094 | function setter(value) { 1095 | target[DATA_PROPTERTY_NAME][key] = value; 1096 | } 1097 | defineAccessor(target, key, getter, setter); 1098 | } 1099 | 1100 | return observe$$1; 1101 | 1102 | }))); 1103 | //# sourceMappingURL=smart-observe.js.map 1104 | -------------------------------------------------------------------------------- /dist/smart-observe.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"smart-observe.js","sources":["../src/dep.js","../src/constants.js","../src/util.js","../src/array.js","../src/observe.js","../src/expression.js","../node_modules/smart-next-tick/nextTick.js","../src/batcher.js","../src/watcher.js","../src/index.js"],"sourcesContent":["let uid = 0\n\n/**\n * A dep is an observable that can have multiple\n * watcher subscribing to it.\n */\n\nexport default class Dep {\n // the current target watcher being evaluated.\n // this is globally unique because there could be only one\n // watcher being evaluated at any time.\n static target = null\n\n constructor () {\n this.id = uid++\n this.subs = []\n }\n\n /**\n * Add a subscriber.\n *\n * @param {Watcher} sub\n */\n\n addSub (sub) {\n this.subs.push(sub)\n }\n\n /**\n * Remove a subscriber.\n *\n * @param {Watcher} sub\n */\n\n removeSub (sub) {\n this.subs.$remove(sub)\n }\n\n /**\n * Add self as a dependency to the target watcher.\n */\n\n depend () {\n Dep.target.addDep(this)\n }\n\n /**\n * Notify all subscribers of a new value.\n */\n\n notify () {\n const subs = this.subs\n for (let i = 0, l = subs.length; i < l; i++) {\n subs[i].update()\n }\n }\n}\n","export const OBSERVE_NAME = '__s_o__'\nexport const WATCHERS_PROPERTY_NAME = '__watchers__'\nexport const DATA_PROPTERTY_NAME = '__data__'\n\nexport const DEBUGGING = typeof process !== 'undefined'\n && process.env.NODE_ENV !== 'production'\n","import {DEBUGGING} from './constants'\n\n/**\n * Define property with value.\n *\n * @param {Object} object\n * @param {String} property\n * @param {*} value\n * @param {Boolean} [enumerable]\n */\n\nexport function defineValue (object, property, value, enumerable) {\n Object.defineProperty(object, property, {\n value,\n enumerable: !!enumerable,\n writable: true,\n configurable: true,\n })\n}\n\n/**\n * Define property with getter and setter.\n *\n * @param {Object} object\n * @param {String} property\n * @param {Function} getter\n * @param {Function} setter\n */\n\nexport function defineAccessor (object, property, getter, setter) {\n Object.defineProperty(object, property, {\n get: getter,\n set: setter,\n enumerable: true,\n configurable: true,\n })\n}\n\n/**\n * Array type check.\n *\n * @return {Boolean}\n */\n\nexport const isArray = Array.isArray\n\n/**\n * Strict object type check. Only returns true\n * for plain JavaScript objects.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nconst toString = Object.prototype.toString\nconst OBJECT_STRING = '[object Object]'\nexport function isPlainObject (object) {\n return toString.call(object) === OBJECT_STRING\n}\n\n/**\n * Quick object check - this is primarily used to tell\n * Objects from primitive values when we know the value\n * is a JSON-compliant type.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nexport function isObject (object) {\n return object !== null && typeof object === 'object'\n}\n\n/**\n * Function type check\n *\n * @param {*} func\n * @param {Boolean}\n */\n\nexport function isFunction (func) {\n return typeof func === 'function'\n}\n\n/**\n * Iterate object\n *\n * @param {Object} object\n * @param {Function} callback\n */\n\nexport function everyEntries (object, callback) {\n const keys = Object.keys(object)\n for (let i = 0, l = keys.length; i < l; i++) {\n callback(keys[i], object[keys[i]])\n }\n}\n\n/**\n * noop is function which is nothing to do.\n */\n\nexport function noop () {}\n\n/**\n * @param {String} string\n */\n\nexport const warn = typeof DEBUGGING !== 'undefined' && DEBUGGING\n && typeof console !== 'undefined' && console\n && isFunction(console.warn)\n ? console.warn\n : noop\n\nexport let _Set\nif (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {\n // use native Set when available.\n _Set = Set\n} else {\n // a non-standard Set polyfill that only works with primitive keys.\n _Set = function () {\n this.set = Object.create(null)\n }\n _Set.prototype.has = function (key) {\n return this.set[key] !== undefined\n }\n _Set.prototype.add = function (key) {\n this.set[key] = 1\n }\n _Set.prototype.clear = function () {\n this.set = Object.create(null)\n }\n}\n","import {defineValue} from './util'\nimport {OBSERVE_NAME} from './constants'\n\nconst arrayPrototype = Array.prototype\nconst arrayMethods = Object.create(arrayPrototype)\nconst arrayMutativeMethods = [\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n]\n\n/**\n * Augment an target Array with arrayMethods\n *\n * @param {Array} array\n */\n\nexport default function amend (array) {\n Object.setPrototypeOf(array, arrayMethods)\n}\n\n/**\n * Intercept mutating methods and emit events\n */\n\nfor (let i = 0, l = arrayMutativeMethods.length; i < l; i++) {\n const method = arrayMutativeMethods[i]\n // cache original method\n const original = arrayPrototype[method]\n defineValue(arrayMethods, method, function mutator (...args) {\n const result = original.apply(this, args)\n const observer = this[OBSERVE_NAME]\n let inserted\n switch (method) {\n case 'push':\n inserted = args\n break\n case 'unshift':\n inserted = args\n break\n case 'splice':\n inserted = args.slice(2)\n break\n }\n if (inserted) observer.observeArray(inserted)\n observer.dep.notify() // notify change\n return result\n })\n}\n\n/**\n * Swap the element at the given index with a new value\n * and emits corresponding event.\n *\n * @param {Number} index\n * @param {*} value\n * @return {*} - replaced element\n */\n\nfunction $set (index, value) {\n if (index >= this.length) {\n this.length = Number(index) + 1\n }\n return this.splice(index, 1, value)[0]\n}\ndefineValue(arrayPrototype, '$set', $set)\n\n/**\n * Convenience method to remove the element at given index\n * or target element reference.\n *\n * @param {*} item\n * @return {*} - removed element\n */\n\nfunction $remove (item) {\n if (!this.length) return\n const index = this.indexOf(item)\n if (index > -1) {\n return this.splice(index, 1)\n }\n}\ndefineValue(arrayPrototype, '$remove', $remove)\n","import Dep from './dep'\nimport amendArray from './array'\nimport {\n defineValue,\n defineAccessor,\n isArray,\n isPlainObject,\n everyEntries,\n} from './util'\nimport {OBSERVE_NAME} from './constants'\n\n/**\n * Observer class that are attached to each observed\n * object. Once attached, the observer converts target\n * object's property keys into getter/setters that\n * collect dependencies and dispatches updates.\n *\n * @class\n * @param {Array|Object} value\n */\n\nclass Observer {\n constructor (value) {\n this.value = value\n this.dep = new Dep()\n defineValue(value, OBSERVE_NAME, this)\n if (isArray(value)) {\n amendArray(value)\n this.observeArray(value)\n } else {\n this.walk(value)\n }\n }\n\n /**\n * Walk through each property and convert them into\n * getter/setters. This method should only be called when\n * value type is Object.\n *\n * @param {Object} object\n */\n\n walk (object) {\n everyEntries(object, (key, value) => this.convert(key, value))\n }\n\n /**\n * Observe a list of Array items.\n *\n * @param {Array} items\n */\n\n observeArray (items) {\n for (let i = 0, l = items.length; i < l; i++) {\n observe(items[i])\n }\n }\n\n /**\n * Convert a property into getter/setter so we can emit\n * the events when the property is accessed/changed.\n *\n * @param {String} key\n * @param {*} value\n */\n\n convert (key, value) {\n defineReactive(this.value, key, value)\n }\n}\n\n/**\n * Attempt to create an observer instance for a value,\n * returns the new observer if successfully observed,\n * or the existing observer if the value already has one.\n *\n * @param {*} value\n * @return {Observer|undefined}\n */\n\nexport function observe (value) {\n if (!value || typeof value !== 'object') return\n let observer\n if (\n Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME)\n && value[OBSERVE_NAME] instanceof Observer\n ) {\n observer = value[OBSERVE_NAME]\n } else if (\n (isArray(value) || isPlainObject(value))\n && Object.isExtensible(value)\n ) {\n observer = new Observer(value)\n }\n return observer\n}\n\n/**\n * Define a reactive property on an Object.\n *\n * @param {Object} object\n * @param {String} key\n * @param {*} value\n */\n\nexport function defineReactive (object, key, value) {\n const dep = new Dep()\n\n const desc = Object.getOwnPropertyDescriptor(object, key)\n if (desc && desc.configurable === false) return\n\n // cater for pre-defined getter/setters\n const getter = desc && desc.get\n const setter = desc && desc.set\n\n let childOb = observe(value)\n\n function reactiveGetter () {\n const currentValue = getter ? getter.call(object) : value\n if (Dep.target) {\n dep.depend()\n if (childOb) {\n childOb.dep.depend()\n }\n if (isArray(currentValue)) {\n for (let i = 0, l = currentValue.length, e; i < l; i++) {\n e = currentValue[i]\n e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend()\n }\n }\n }\n return currentValue\n }\n function reactiveSetter (newValue) {\n const oldValue = getter ? getter.call(object) : value\n if (newValue === oldValue) return\n if (setter) {\n setter.call(object, newValue)\n } else {\n value = newValue\n }\n childOb = observe(newValue)\n dep.notify()\n }\n defineAccessor(object, key, reactiveGetter, reactiveSetter)\n}\n","import {warn} from './util'\n\n/**\n * Build a getter function. Requires eval.\n *\n * We isolate the try/catch so it doesn't affect the\n * optimization of the parse function when it is not called.\n *\n * @param {String} body\n * @return {Function|undefined}\n */\n\nfunction makeGetterFunction (body) {\n try {\n /* eslint-disable no-new-func */\n return new Function('scope', `return ${body};`)\n /* eslint-enable no-new-func */\n } catch (e) {\n warn('Invalid expression. Generated function body: ' + body)\n }\n}\n\n/**\n * Parse an expression to getter.\n *\n * @param {String} expression\n * @return {Function|undefined}\n */\n\nexport default function parse (expression) {\n expression = String.prototype.trim.call(expression)\n return makeGetterFunction('scope.' + expression)\n}\n","var callbacks = []\nvar pending = false\nfunction nextTickHandler () {\n pending = false\n var callbackCopies = callbacks.slice(0)\n callbacks.length = 0\n for (var i = 0; i < callbackCopies.length; i++) {\n callbackCopies[i]()\n }\n}\n\nvar callNextTick\nif (typeof process === 'object'\n && process\n && typeof process.nextTick === 'function'\n) {\n callNextTick = process.nextTick\n} else if (typeof MutationObserver !== 'undefined') {\n var counter = 0\n var textNode = document.createTextNode(counter)\n var observer = new MutationObserver(nextTickHandler)\n observer.observe(textNode, {\n characterData: true\n })\n callNextTick = function () {\n counter = counter === 0 ? 1 : 0\n textNode.data = String(counter)\n }\n} else {\n callNextTick = setTimeout\n}\n\n\nmodule.exports = function nextTick (callback, context) {\n var func = callback\n if (context) {\n var args = []\n var l = arguments.length\n while (--l > 1) {\n args.unshift(arguments[l])\n }\n func = function () {\n callback.apply(context, args)\n }\n }\n callbacks.push(func)\n if (pending) {\n return\n }\n pending = true\n callNextTick(nextTickHandler)\n}\n","import nextTick from 'smart-next-tick'\n\nlet queue = []\nlet has = {}\nlet waiting = false\nlet queueIndex\n\n/**\n * Reset the batcher's state.\n */\n\nfunction resetBatcherState () {\n queue = []\n has = {}\n waiting = false\n}\n\n/**\n * Flush queue and run the watchers.\n */\n\nfunction flushBatcherQueue () {\n runBatcherQueue(queue)\n resetBatcherState()\n}\n\n/**\n * Run the watchers in a single queue.\n *\n * @param {Array} queue\n */\n\nfunction runBatcherQueue (queue) {\n // do not cache length because more watchers might be pushed\n // as we run existing watchers\n for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {\n const watcher = queue[queueIndex]\n const id = watcher.id\n has[id] = null\n watcher.run()\n }\n}\n\n/**\n * Push a watcher into the watcher queue.\n * Jobs with duplicate IDs will be skipped unless it's\n * pushed when the queue is being flushed.\n *\n * @param {Watcher} watcher\n * properties:\n * - {Number} id\n * - {Function} run\n */\n\nexport default function batch (watcher) {\n const id = watcher.id\n if (has[id] == null) {\n has[id] = queue.length\n queue.push(watcher)\n // queue the flush\n if (!waiting) {\n waiting = true\n nextTick(flushBatcherQueue)\n }\n }\n}\n","import observe from './index'\nimport Dep from './dep'\nimport parseExpression from './expression'\nimport batch from './batcher'\nimport {\n isArray,\n isObject,\n isFunction,\n _Set as Set,\n} from './util'\nimport {WATCHERS_PROPERTY_NAME} from './constants'\n\nlet uid = 0\n\nclass Watcher {\n\n /**\n * A watcher parses an expression, collects dependencies,\n * and fires callback when the expression value changes.\n *\n * @param {Object} owner\n * @param {String|Function} getter\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @constructor\n */\n\n constructor (owner, getter, callback, options) {\n owner[WATCHERS_PROPERTY_NAME].push(this)\n this.owner = owner\n this.getter = getter\n this.callback = callback\n this.options = options\n // uid for batching\n this.id = ++uid\n this.active = true\n // for lazy watchers\n this.dirty = options.lazy\n this.deps = []\n this.newDeps = []\n this.depIds = new Set()\n this.newDepIds = new Set()\n this.value = options.lazy\n ? undefined\n : this.get()\n }\n\n /**\n * Evaluate the getter, and re-collect dependencies.\n */\n\n get () {\n this.beforeGet()\n const scope = this.owner\n const value = this.getter.call(scope, scope)\n if (this.options.deep) {\n traverse(value)\n }\n this.afterGet()\n return value\n }\n\n /**\n * Prepare for dependency collection.\n */\n\n beforeGet () {\n Dep.target = this\n }\n\n /**\n * Add a dependency to this directive.\n *\n * @param {Dep} dep\n */\n\n addDep (dep) {\n const id = dep.id\n if (!this.newDepIds.has(id)) {\n this.newDepIds.add(id)\n this.newDeps.push(dep)\n if (!this.depIds.has(id)) {\n dep.addSub(this)\n }\n }\n }\n\n /**\n * Clean up for dependency collection.\n */\n\n afterGet () {\n Dep.target = null\n let i = this.deps.length\n while (i--) {\n const dep = this.deps[i]\n if (!this.newDepIds.has(dep.id)) {\n dep.removeSub(this)\n }\n }\n let tmp = this.depIds\n this.depIds = this.newDepIds\n this.newDepIds = tmp\n this.newDepIds.clear()\n tmp = this.deps\n this.deps = this.newDeps\n this.newDeps = tmp\n this.newDeps.length = 0\n }\n\n /**\n * Will be called when a dependency changes.\n */\n\n update () {\n if (this.options.lazy) {\n this.dirty = true\n } else if (this.options.sync) {\n this.run()\n } else {\n batch(this)\n }\n }\n\n /**\n * Will be called by the batcher.\n */\n\n run () {\n if (this.active) {\n const value = this.get()\n if (\n value !== this.value\n // Deep watchers and watchers on Object/Arrays should fire even when\n // the value is the same, because the value may have mutated;\n || ((isObject(value) || this.options.deep))\n ) {\n const oldValue = this.value\n this.value = value\n this.callback.call(this.owner, value, oldValue)\n }\n }\n }\n\n /**\n * Evaluate the value of the watcher.\n * This only gets called for lazy watchers.\n */\n\n evaluate () {\n // avoid overwriting another watcher that is being collected.\n const current = Dep.target\n this.value = this.get()\n this.dirty = false\n Dep.target = current\n }\n\n /**\n * Depend on all deps collected by this watcher.\n */\n\n depend () {\n let i = this.deps.length\n while (i--) {\n this.deps[i].depend()\n }\n }\n\n /**\n * Remove self from all dependencies' subcriber list.\n */\n\n teardown () {\n if (this.active) {\n let i = this.deps.length\n while (i--) {\n this.deps[i].removeSub(this)\n }\n this.active = false\n this.owner = this.callback = this.value = null\n }\n }\n}\n\n/**\n * Recrusively traverse an object to evoke all converted\n * getters, so that every nested property inside the object\n * is collected as a \"deep\" dependency.\n *\n * @param {*} value\n */\n\nfunction traverse (value) {\n let i, keys\n if (isArray(value)) {\n i = value.length\n while (i--) traverse(value[i])\n } else if (isObject(value)) {\n keys = Object.keys(value)\n i = keys.length\n while (i--) traverse(value[keys[i]])\n }\n}\n\n/**\n * Create an watcher instance, returns the new watcher.\n *\n * @param {Object} owner\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nexport function watch (owner, expressionOrFunction, callback, options) {\n // parse expression for getter\n const getter = isFunction(expressionOrFunction)\n ? expressionOrFunction\n : parseExpression(expressionOrFunction)\n return new Watcher(owner, getter, callback, options)\n}\n\n/**\n * Make a computed getter, which can collect dependencies.\n *\n * @param {Object} owner\n * @param {Function} getter\n */\n\nexport function makeComputed (owner, getter) {\n const watcher = new Watcher(owner, getter, null, {\n deep: observe.deep,\n lazy: true,\n sync: observe.sync,\n })\n return function computedGetter () {\n if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {\n watcher.options.lazy = false\n watcher.callback = function () {\n const deps = watcher.deps\n for (let i = 0, l = deps.length; i < l; i++) {\n deps[i].notify()\n }\n }\n }\n if (watcher.dirty) {\n watcher.evaluate()\n }\n if (Dep.target) {\n watcher.depend()\n }\n return watcher.value\n }\n}\n","import {\n observe as doObserve,\n defineReactive,\n} from './observe'\nimport {\n watch as doWatch,\n makeComputed,\n} from './watcher'\nimport {\n defineValue,\n defineAccessor,\n noop,\n isFunction,\n everyEntries,\n} from './util'\nimport {\n WATCHERS_PROPERTY_NAME,\n DATA_PROPTERTY_NAME,\n} from './constants'\n\nObject.defineProperties(observe, {\n 'react': {value: react},\n 'compute': {value: compute},\n 'watch': {value: watch},\n 'default': {value: watch, writable: true}, // Only could be react, compute or watch\n 'deep': {value: false, writable: true},\n 'lazy': {value: false, writable: true},\n 'sync': {value: false, writable: true},\n})\n\n/**\n * observe\n *\n * @public\n * @param {Object} target\n * @param {*} [expression]\n * @param {*} [func]\n * @param {*} [options]\n * @return {Function} observe\n */\n\nexport default function observe (target, expression, func, options) {\n ensure(target)\n return observe.default(target, expression, func, options)\n}\n\n/**\n * React options\n *\n * @param {Object} options\n * @param {Object} [target]\n * @return {Function} observe\n */\n\nfunction react (options, target) {\n if (target) {\n ensure(target)\n } else {\n target = {}\n init(target)\n }\n options.methods && carryMethods(target, options.methods)\n options.data && reactProperties(target, options.data)\n options.computed && computeProperties(target, options.computed)\n options.watchers && watchProperties(target, options.watchers)\n return target\n}\n\n/**\n * Compute property\n *\n * @param {Object} target\n * @param {String} name\n * @param {Function|Object} getterOrAccessor\n * - Function getter\n * - Object accessor\n * - Function [get] - getter\n * - Function [set] - setter\n * - Boolean [cache]\n * @param {Boolean} [cache]\n */\n\nfunction compute (target, name, getterOrAccessor, cache) {\n ensure(target)\n let getter, setter\n if (isFunction(getterOrAccessor)) {\n getter = cache !== false\n ? makeComputed(target, getterOrAccessor)\n : getterOrAccessor.bind(this)\n setter = noop\n } else {\n getter = getterOrAccessor.get\n ? getterOrAccessor.cache !== false || cache !== false\n ? makeComputed(target, getterOrAccessor.get)\n : getterOrAccessor.get.bind(this)\n : noop\n setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop\n }\n defineAccessor(target, name, getter, setter)\n}\n\n/**\n * Watch property\n *\n * @param {Object} target\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} [options]\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nfunction watch (target, expressionOrFunction, callback, options = observe) {\n ensure(target)\n return doWatch(target, expressionOrFunction, callback, options)\n}\n\n/**\n * @param {Object} target\n */\n\nfunction init (target) {\n defineValue(target, WATCHERS_PROPERTY_NAME, [], false)\n defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false)\n doObserve(target[DATA_PROPTERTY_NAME])\n reactSelfProperties(target)\n}\n\nfunction ensure (target) {\n if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {\n init(target)\n }\n}\n\n/**\n * @param {Object} target\n * @param {Object} methods\n */\n\nfunction carryMethods (target, methods) {\n everyEntries(methods, (name, method) => {\n target[name] = method.bind(target)\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n * @param {*} value\n */\n\nfunction reactProperty (target, key, value) {\n target[DATA_PROPTERTY_NAME][key] = value\n defineReactive(target[DATA_PROPTERTY_NAME], key, value)\n proxy(target, key)\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction reactProperties (target, properties) {\n everyEntries(properties, (key, value) => reactProperty(target, key, value))\n}\n\n/**\n * @param {Object} target\n */\n\nfunction reactSelfProperties (target) {\n everyEntries(target, (key, value) => {\n !isFunction(value) && reactProperty(target, key, value)\n })\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction computeProperties (target, properties) {\n everyEntries(properties, (key, value) => compute(target, key, value))\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction watchProperties (target, properties) {\n everyEntries(properties, (expression, functionOrOption) => {\n if (isFunction(functionOrOption)) {\n watch(target, expression, functionOrOption)\n } else {\n watch(target, expression, functionOrOption.watcher, functionOrOption)\n }\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n */\n\nfunction proxy (target, key) {\n function getter () {\n return target[DATA_PROPTERTY_NAME][key]\n }\n function setter (value) {\n target[DATA_PROPTERTY_NAME][key] = value\n }\n defineAccessor(target, key, getter, setter)\n}\n"],"names":["uid","Dep","id","subs","sub","push","$remove","target","addDep","i","l","length","update","OBSERVE_NAME","WATCHERS_PROPERTY_NAME","DATA_PROPTERTY_NAME","DEBUGGING","process","env","NODE_ENV","defineValue","object","property","value","enumerable","defineProperty","defineAccessor","getter","setter","isArray","Array","toString","Object","prototype","OBJECT_STRING","isPlainObject","call","isObject","isFunction","func","everyEntries","callback","keys","noop","warn","console","_Set","Set","match","set","create","has","key","undefined","add","clear","arrayPrototype","arrayMethods","arrayMutativeMethods","amend","array","setPrototypeOf","method","original","mutator","args","result","apply","observer","inserted","slice","observeArray","dep","notify","$set","index","Number","splice","item","indexOf","Observer","walk","convert","items","observe","hasOwnProperty","isExtensible","defineReactive","desc","getOwnPropertyDescriptor","configurable","get","childOb","reactiveGetter","currentValue","depend","e","reactiveSetter","newValue","oldValue","makeGetterFunction","body","Function","parse","expression","String","trim","callbacks","pending","nextTickHandler","callbackCopies","callNextTick","nextTick","MutationObserver","counter","textNode","document","createTextNode","data","setTimeout","context","arguments","unshift","queue","waiting","queueIndex","resetBatcherState","flushBatcherQueue","runBatcherQueue","watcher","run","batch","Watcher","owner","options","active","dirty","lazy","deps","newDeps","depIds","newDepIds","beforeGet","scope","deep","afterGet","addSub","removeSub","tmp","sync","current","traverse","watch","expressionOrFunction","parseExpression","makeComputed","computedGetter","evaluate","defineProperties","react","compute","writable","default","methods","carryMethods","reactProperties","computed","computeProperties","watchers","watchProperties","name","getterOrAccessor","cache","bind","doWatch","init","ensure","reactProperty","properties","reactSelfProperties","functionOrOption","proxy"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAIA,MAAM,CAAV;;;;;;;IAOqBC;iBAMJ;;;SACRC,EAAL,GAAUF,KAAV;SACKG,IAAL,GAAY,EAAZ;;;;;;;;;;;;;;;;2BASMC,KAAK;WACND,IAAL,CAAUE,IAAV,CAAeD,GAAf;;;;;;;;;;;8BASSA,KAAK;WACTD,IAAL,CAAUG,OAAV,CAAkBF,GAAlB;;;;;;;;;6BAOQ;UACJG,MAAJ,CAAWC,MAAX,CAAkB,IAAlB;;;;;;;;;6BAOQ;UACFL,OAAO,KAAKA,IAAlB;WACK,IAAIM,IAAI,CAAR,EAAWC,IAAIP,KAAKQ,MAAzB,EAAiCF,IAAIC,CAArC,EAAwCD,GAAxC,EAA6C;aACtCA,CAAL,EAAQG,MAAR;;;;;;;AA9CeX,IAIZM,SAAS;;ACXX,IAAMM,eAAe,SAArB;AACP,AAAO,IAAMC,yBAAyB,cAA/B;AACP,AAAO,IAAMC,sBAAsB,UAA5B;;AAEP,AAAO,IAAMC,YAAY,OAAOC,OAAP,KAAmB,WAAnB,IACpBA,QAAQC,GAAR,CAAYC,QAAZ,KAAyB,YADvB;;ACFP;;;;;;;;;AASA,AAAO,SAASC,WAAT,CAAsBC,MAAtB,EAA8BC,QAA9B,EAAwCC,KAAxC,EAA+CC,UAA/C,EAA2D;SACzDC,cAAP,CAAsBJ,MAAtB,EAA8BC,QAA9B,EAAwC;gBAAA;gBAE1B,CAAC,CAACE,UAFwB;cAG5B,IAH4B;kBAIxB;GAJhB;;;;;;;;;;;;AAiBF,AAAO,SAASE,cAAT,CAAyBL,MAAzB,EAAiCC,QAAjC,EAA2CK,MAA3C,EAAmDC,MAAnD,EAA2D;SACzDH,cAAP,CAAsBJ,MAAtB,EAA8BC,QAA9B,EAAwC;SACjCK,MADiC;SAEjCC,MAFiC;gBAG1B,IAH0B;kBAIxB;GAJhB;;;;;;;;;AAcF,AAAO,IAAMC,UAAUC,MAAMD,OAAtB;;;;;;;;;;AAUP,IAAME,WAAWC,OAAOC,SAAP,CAAiBF,QAAlC;AACA,IAAMG,gBAAgB,iBAAtB;AACA,AAAO,SAASC,aAAT,CAAwBd,MAAxB,EAAgC;SAC9BU,SAASK,IAAT,CAAcf,MAAd,MAA0Ba,aAAjC;;;;;;;;;;;;AAYF,AAAO,SAASG,QAAT,CAAmBhB,MAAnB,EAA2B;SACzBA,WAAW,IAAX,IAAmB,QAAOA,MAAP,yCAAOA,MAAP,OAAkB,QAA5C;;;;;;;;;;AAUF,AAAO,SAASiB,UAAT,CAAqBC,IAArB,EAA2B;SACzB,OAAOA,IAAP,KAAgB,UAAvB;;;;;;;;;;AAUF,AAAO,SAASC,YAAT,CAAuBnB,MAAvB,EAA+BoB,QAA/B,EAAyC;MACxCC,OAAOV,OAAOU,IAAP,CAAYrB,MAAZ,CAAb;OACK,IAAIZ,IAAI,CAAR,EAAWC,IAAIgC,KAAK/B,MAAzB,EAAiCF,IAAIC,CAArC,EAAwCD,GAAxC,EAA6C;aAClCiC,KAAKjC,CAAL,CAAT,EAAkBY,OAAOqB,KAAKjC,CAAL,CAAP,CAAlB;;;;;;;;AAQJ,AAAO,SAASkC,IAAT,GAAiB;;;;;;AAMxB,AAAO,IAAMC,OAAO,OAAO5B,SAAP,KAAqB,WAArB,IAAoCA,SAApC,IACf,OAAO6B,OAAP,KAAmB,WADJ,IACmBA,OADnB,IAEfP,WAAWO,QAAQD,IAAnB,CAFe,GAGdC,QAAQD,IAHM,GAIdD,IAJC;;AAMP,AAAO,IAAIG,aAAJ;AACP,IAAI,OAAOC,GAAP,KAAe,WAAf,IAA8BA,IAAIhB,QAAJ,GAAeiB,KAAf,CAAqB,aAArB,CAAlC,EAAuE;;SAE9DD,GAAP;CAFF,MAGO;;SAEE,gBAAY;SACZE,GAAL,GAAWjB,OAAOkB,MAAP,CAAc,IAAd,CAAX;GADF;OAGKjB,SAAL,CAAekB,GAAf,GAAqB,UAAUC,GAAV,EAAe;WAC3B,KAAKH,GAAL,CAASG,GAAT,MAAkBC,SAAzB;GADF;OAGKpB,SAAL,CAAeqB,GAAf,GAAqB,UAAUF,GAAV,EAAe;SAC7BH,GAAL,CAASG,GAAT,IAAgB,CAAhB;GADF;OAGKnB,SAAL,CAAesB,KAAf,GAAuB,YAAY;SAC5BN,GAAL,GAAWjB,OAAOkB,MAAP,CAAc,IAAd,CAAX;GADF;;;AC9HF,IAAMM,iBAAiB1B,MAAMG,SAA7B;AACA,IAAMwB,eAAezB,OAAOkB,MAAP,CAAcM,cAAd,CAArB;AACA,IAAME,uBAAuB,CAC3B,MAD2B,EAE3B,KAF2B,EAG3B,OAH2B,EAI3B,SAJ2B,EAK3B,QAL2B,EAM3B,MAN2B,EAO3B,SAP2B,CAA7B;;;;;;;;AAgBA,AAAe,SAASC,KAAT,CAAgBC,KAAhB,EAAuB;SAC7BC,cAAP,CAAsBD,KAAtB,EAA6BH,YAA7B;;;;;;;2BAOOhD,GAAOC;MACRoD,SAASJ,qBAAqBjD,CAArB,CAAf;;MAEMsD,WAAWP,eAAeM,MAAf,CAAjB;cACYL,YAAZ,EAA0BK,MAA1B,EAAkC,SAASE,OAAT,GAA2B;sCAANC,IAAM;UAAA;;;QACrDC,SAASH,SAASI,KAAT,CAAe,IAAf,EAAqBF,IAArB,CAAf;QACMG,WAAW,KAAKvD,YAAL,CAAjB;QACIwD,iBAAJ;YACQP,MAAR;WACO,MAAL;mBACaG,IAAX;;WAEG,SAAL;mBACaA,IAAX;;WAEG,QAAL;mBACaA,KAAKK,KAAL,CAAW,CAAX,CAAX;;;QAGAD,QAAJ,EAAcD,SAASG,YAAT,CAAsBF,QAAtB;aACLG,GAAT,CAAaC,MAAb,GAhB2D;WAiBpDP,MAAP;GAjBF;;;AAJF,KAAK,IAAIzD,IAAI,CAAR,EAAWC,IAAIgD,qBAAqB/C,MAAzC,EAAiDF,IAAIC,CAArD,EAAwDD,GAAxD,EAA6D;QAApDA,CAAoD,EAA7CC,CAA6C;;;;;;;;;;;;AAkC7D,SAASgE,IAAT,CAAeC,KAAf,EAAsBpD,KAAtB,EAA6B;MACvBoD,SAAS,KAAKhE,MAAlB,EAA0B;SACnBA,MAAL,GAAciE,OAAOD,KAAP,IAAgB,CAA9B;;SAEK,KAAKE,MAAL,CAAYF,KAAZ,EAAmB,CAAnB,EAAsBpD,KAAtB,EAA6B,CAA7B,CAAP;;AAEFH,YAAYoC,cAAZ,EAA4B,MAA5B,EAAoCkB,IAApC;;;;;;;;;;AAUA,SAASpE,OAAT,CAAkBwE,IAAlB,EAAwB;MAClB,CAAC,KAAKnE,MAAV,EAAkB;MACZgE,QAAQ,KAAKI,OAAL,CAAaD,IAAb,CAAd;MACIH,QAAQ,CAAC,CAAb,EAAgB;WACP,KAAKE,MAAL,CAAYF,KAAZ,EAAmB,CAAnB,CAAP;;;AAGJvD,YAAYoC,cAAZ,EAA4B,SAA5B,EAAuClD,OAAvC;;AC3EA;;;;;;;;;;IAUM0E;oBACSzD,KAAb,EAAoB;;;SACbA,KAAL,GAAaA,KAAb;SACKiD,GAAL,GAAW,IAAIvE,GAAJ,EAAX;gBACYsB,KAAZ,EAAmBV,YAAnB,EAAiC,IAAjC;QACIgB,QAAQN,KAAR,CAAJ,EAAoB;YACPA,KAAX;WACKgD,YAAL,CAAkBhD,KAAlB;KAFF,MAGO;WACA0D,IAAL,CAAU1D,KAAV;;;;;;;;;;;;;;yBAYEF,QAAQ;;;mBACCA,MAAb,EAAqB,UAAC+B,GAAD,EAAM7B,KAAN;eAAgB,MAAK2D,OAAL,CAAa9B,GAAb,EAAkB7B,KAAlB,CAAhB;OAArB;;;;;;;;;;;iCASY4D,OAAO;WACd,IAAI1E,IAAI,CAAR,EAAWC,IAAIyE,MAAMxE,MAA1B,EAAkCF,IAAIC,CAAtC,EAAyCD,GAAzC,EAA8C;kBACpC0E,MAAM1E,CAAN,CAAR;;;;;;;;;;;;;;4BAYK2C,KAAK7B,OAAO;qBACJ,KAAKA,KAApB,EAA2B6B,GAA3B,EAAgC7B,KAAhC;;;;;;;;;;;;;;;AAaJ,AAAO,SAAS6D,SAAT,CAAkB7D,KAAlB,EAAyB;MAC1B,CAACA,KAAD,IAAU,QAAOA,KAAP,yCAAOA,KAAP,OAAiB,QAA/B,EAAyC;MACrC6C,iBAAJ;MAEEpC,OAAOC,SAAP,CAAiBoD,cAAjB,CAAgCjD,IAAhC,CAAqCb,KAArC,EAA4CV,YAA5C,KACGU,MAAMV,YAAN,aAA+BmE,QAFpC,EAGE;eACWzD,MAAMV,YAAN,CAAX;GAJF,MAKO,IACL,CAACgB,QAAQN,KAAR,KAAkBY,cAAcZ,KAAd,CAAnB,KACGS,OAAOsD,YAAP,CAAoB/D,KAApB,CAFE,EAGL;eACW,IAAIyD,QAAJ,CAAazD,KAAb,CAAX;;SAEK6C,QAAP;;;;;;;;;;;AAWF,AAAO,SAASmB,cAAT,CAAyBlE,MAAzB,EAAiC+B,GAAjC,EAAsC7B,KAAtC,EAA6C;MAC5CiD,MAAM,IAAIvE,GAAJ,EAAZ;;MAEMuF,OAAOxD,OAAOyD,wBAAP,CAAgCpE,MAAhC,EAAwC+B,GAAxC,CAAb;MACIoC,QAAQA,KAAKE,YAAL,KAAsB,KAAlC,EAAyC;;;MAGnC/D,SAAS6D,QAAQA,KAAKG,GAA5B;MACM/D,SAAS4D,QAAQA,KAAKvC,GAA5B;;MAEI2C,UAAUR,UAAQ7D,KAAR,CAAd;;WAESsE,cAAT,GAA2B;QACnBC,eAAenE,SAASA,OAAOS,IAAP,CAAYf,MAAZ,CAAT,GAA+BE,KAApD;QACItB,IAAIM,MAAR,EAAgB;UACVwF,MAAJ;UACIH,OAAJ,EAAa;gBACHpB,GAAR,CAAYuB,MAAZ;;UAEElE,QAAQiE,YAAR,CAAJ,EAA2B;aACpB,IAAIrF,IAAI,CAAR,EAAWC,IAAIoF,aAAanF,MAA5B,EAAoCqF,CAAzC,EAA4CvF,IAAIC,CAAhD,EAAmDD,GAAnD,EAAwD;cAClDqF,aAAarF,CAAb,CAAJ;eACKuF,EAAEnF,YAAF,CAAL,IAAwBmF,EAAEnF,YAAF,EAAgB2D,GAAhB,CAAoBuB,MAApB,EAAxB;;;;WAICD,YAAP;;WAEOG,cAAT,CAAyBC,QAAzB,EAAmC;QAC3BC,WAAWxE,SAASA,OAAOS,IAAP,CAAYf,MAAZ,CAAT,GAA+BE,KAAhD;QACI2E,aAAaC,QAAjB,EAA2B;QACvBvE,MAAJ,EAAY;aACHQ,IAAP,CAAYf,MAAZ,EAAoB6E,QAApB;KADF,MAEO;cACGA,QAAR;;cAEQd,UAAQc,QAAR,CAAV;QACIzB,MAAJ;;iBAEapD,MAAf,EAAuB+B,GAAvB,EAA4ByC,cAA5B,EAA4CI,cAA5C;;;AC9IF;;;;;;;;;;AAUA,SAASG,kBAAT,CAA6BC,IAA7B,EAAmC;MAC7B;;WAEK,IAAIC,QAAJ,CAAa,OAAb,cAAgCD,IAAhC,OAAP;;GAFF,CAIE,OAAOL,CAAP,EAAU;SACL,kDAAkDK,IAAvD;;;;;;;;;;;AAWJ,AAAe,SAASE,KAAT,CAAgBC,UAAhB,EAA4B;eAC5BC,OAAOxE,SAAP,CAAiByE,IAAjB,CAAsBtE,IAAtB,CAA2BoE,UAA3B,CAAb;SACOJ,mBAAmB,WAAWI,UAA9B,CAAP;;;AC/BF,IAAIG,YAAY,EAAhB;AACA,IAAIC,UAAU,KAAd;AACA,SAASC,eAAT,GAA4B;cACd,KAAV;QACIC,iBAAiBH,UAAUrC,KAAV,CAAgB,CAAhB,CAArB;cACU3D,MAAV,GAAmB,CAAnB;SACK,IAAIF,IAAI,CAAb,EAAgBA,IAAIqG,eAAenG,MAAnC,EAA2CF,GAA3C,EAAgD;uBAC7BA,CAAf;;;;AAIR,IAAIsG,YAAJ;AACA,IAAI,QAAO9F,OAAP,yCAAOA,OAAP,OAAmB,QAAnB,IACGA,OADH,IAEG,OAAOA,QAAQ+F,QAAf,KAA4B,UAFnC,EAGE;mBACiB/F,QAAQ+F,QAAvB;CAJJ,MAKO,IAAI,OAAOC,gBAAP,KAA4B,WAAhC,EAA6C;QAC5CC,UAAU,CAAd;QACIC,WAAWC,SAASC,cAAT,CAAwBH,OAAxB,CAAf;QACI9C,WAAW,IAAI6C,gBAAJ,CAAqBJ,eAArB,CAAf;aACSzB,OAAT,CAAiB+B,QAAjB,EAA2B;uBACR;KADnB;mBAGe,wBAAY;kBACbD,YAAY,CAAZ,GAAgB,CAAhB,GAAoB,CAA9B;iBACSI,IAAT,GAAgBb,OAAOS,OAAP,CAAhB;KAFJ;CAPG,MAWA;mBACYK,UAAf;;;AAIJ,eAAiB,SAASP,QAAT,CAAmBvE,QAAnB,EAA6B+E,OAA7B,EAAsC;QAC/CjF,OAAOE,QAAX;QACI+E,OAAJ,EAAa;YACLvD,OAAO,EAAX;YACIvD,IAAI+G,UAAU9G,MAAlB;eACO,EAAED,CAAF,GAAM,CAAb,EAAgB;iBACPgH,OAAL,CAAaD,UAAU/G,CAAV,CAAb;;eAEG,gBAAY;qBACNyD,KAAT,CAAeqD,OAAf,EAAwBvD,IAAxB;SADJ;;cAIM5D,IAAV,CAAekC,IAAf;QACIqE,OAAJ,EAAa;;;cAGH,IAAV;iBACaC,eAAb;CAjBJ;;AC/BA,IAAIc,QAAQ,EAAZ;AACA,IAAIxE,MAAM,EAAV;AACA,IAAIyE,UAAU,KAAd;AACA,IAAIC,mBAAJ;;;;;;AAMA,SAASC,iBAAT,GAA8B;UACpB,EAAR;QACM,EAAN;YACU,KAAV;;;;;;;AAOF,SAASC,iBAAT,GAA8B;kBACZJ,KAAhB;;;;;;;;;;AAUF,SAASK,eAAT,CAA0BL,KAA1B,EAAiC;;;OAG1BE,aAAa,CAAlB,EAAqBA,aAAaF,MAAMhH,MAAxC,EAAgDkH,YAAhD,EAA8D;QACtDI,UAAUN,MAAME,UAAN,CAAhB;QACM3H,KAAK+H,QAAQ/H,EAAnB;QACIA,EAAJ,IAAU,IAAV;YACQgI,GAAR;;;;;;;;;;;;;;;AAeJ,AAAe,SAASC,KAAT,CAAgBF,OAAhB,EAAyB;MAChC/H,KAAK+H,QAAQ/H,EAAnB;MACIiD,IAAIjD,EAAJ,KAAW,IAAf,EAAqB;QACfA,EAAJ,IAAUyH,MAAMhH,MAAhB;UACMN,IAAN,CAAW4H,OAAX;;QAEI,CAACL,OAAL,EAAc;gBACF,IAAV;eACSG,iBAAT;;;;;AClDN,IAAI/H,QAAM,CAAV;;IAEMoI;;;;;;;;;;;;;;;;mBAgBSC,KAAb,EAAoB1G,MAApB,EAA4Bc,QAA5B,EAAsC6F,OAAtC,EAA+C;;;UACvCxH,sBAAN,EAA8BT,IAA9B,CAAmC,IAAnC;SACKgI,KAAL,GAAaA,KAAb;SACK1G,MAAL,GAAcA,MAAd;SACKc,QAAL,GAAgBA,QAAhB;SACK6F,OAAL,GAAeA,OAAf;;SAEKpI,EAAL,GAAU,EAAEF,KAAZ;SACKuI,MAAL,GAAc,IAAd;;SAEKC,KAAL,GAAaF,QAAQG,IAArB;SACKC,IAAL,GAAY,EAAZ;SACKC,OAAL,GAAe,EAAf;SACKC,MAAL,GAAc,IAAI7F,IAAJ,EAAd;SACK8F,SAAL,GAAiB,IAAI9F,IAAJ,EAAjB;SACKxB,KAAL,GAAa+G,QAAQG,IAAR,GACTpF,SADS,GAET,KAAKsC,GAAL,EAFJ;;;;;;;;;6BASK;WACAmD,SAAL;UACMC,QAAQ,KAAKV,KAAnB;UACM9G,QAAQ,KAAKI,MAAL,CAAYS,IAAZ,CAAiB2G,KAAjB,EAAwBA,KAAxB,CAAd;UACI,KAAKT,OAAL,CAAaU,IAAjB,EAAuB;iBACZzH,KAAT;;WAEG0H,QAAL;aACO1H,KAAP;;;;;;;;;gCAOW;UACPhB,MAAJ,GAAa,IAAb;;;;;;;;;;;2BASMiE,KAAK;UACLtE,KAAKsE,IAAItE,EAAf;UACI,CAAC,KAAK2I,SAAL,CAAe1F,GAAf,CAAmBjD,EAAnB,CAAL,EAA6B;aACtB2I,SAAL,CAAevF,GAAf,CAAmBpD,EAAnB;aACKyI,OAAL,CAAatI,IAAb,CAAkBmE,GAAlB;YACI,CAAC,KAAKoE,MAAL,CAAYzF,GAAZ,CAAgBjD,EAAhB,CAAL,EAA0B;cACpBgJ,MAAJ,CAAW,IAAX;;;;;;;;;;;+BASM;UACN3I,MAAJ,GAAa,IAAb;UACIE,IAAI,KAAKiI,IAAL,CAAU/H,MAAlB;aACOF,GAAP,EAAY;YACJ+D,MAAM,KAAKkE,IAAL,CAAUjI,CAAV,CAAZ;YACI,CAAC,KAAKoI,SAAL,CAAe1F,GAAf,CAAmBqB,IAAItE,EAAvB,CAAL,EAAiC;cAC3BiJ,SAAJ,CAAc,IAAd;;;UAGAC,MAAM,KAAKR,MAAf;WACKA,MAAL,GAAc,KAAKC,SAAnB;WACKA,SAAL,GAAiBO,GAAjB;WACKP,SAAL,CAAetF,KAAf;YACM,KAAKmF,IAAX;WACKA,IAAL,GAAY,KAAKC,OAAjB;WACKA,OAAL,GAAeS,GAAf;WACKT,OAAL,CAAahI,MAAb,GAAsB,CAAtB;;;;;;;;;6BAOQ;UACJ,KAAK2H,OAAL,CAAaG,IAAjB,EAAuB;aAChBD,KAAL,GAAa,IAAb;OADF,MAEO,IAAI,KAAKF,OAAL,CAAae,IAAjB,EAAuB;aACvBnB,GAAL;OADK,MAEA;cACC,IAAN;;;;;;;;;;0BAQG;UACD,KAAKK,MAAT,EAAiB;YACThH,QAAQ,KAAKoE,GAAL,EAAd;YAEEpE,UAAU,KAAKA;;;WAGVc,SAASd,KAAT,KAAmB,KAAK+G,OAAL,CAAaU,IAJvC,EAKE;cACM7C,WAAW,KAAK5E,KAAtB;eACKA,KAAL,GAAaA,KAAb;eACKkB,QAAL,CAAcL,IAAd,CAAmB,KAAKiG,KAAxB,EAA+B9G,KAA/B,EAAsC4E,QAAtC;;;;;;;;;;;;+BAUM;;UAEJmD,UAAUrJ,IAAIM,MAApB;WACKgB,KAAL,GAAa,KAAKoE,GAAL,EAAb;WACK6C,KAAL,GAAa,KAAb;UACIjI,MAAJ,GAAa+I,OAAb;;;;;;;;;6BAOQ;UACJ7I,IAAI,KAAKiI,IAAL,CAAU/H,MAAlB;aACOF,GAAP,EAAY;aACLiI,IAAL,CAAUjI,CAAV,EAAasF,MAAb;;;;;;;;;;+BAQQ;UACN,KAAKwC,MAAT,EAAiB;YACX9H,IAAI,KAAKiI,IAAL,CAAU/H,MAAlB;eACOF,GAAP,EAAY;eACLiI,IAAL,CAAUjI,CAAV,EAAa0I,SAAb,CAAuB,IAAvB;;aAEGZ,MAAL,GAAc,KAAd;aACKF,KAAL,GAAa,KAAK5F,QAAL,GAAgB,KAAKlB,KAAL,GAAa,IAA1C;;;;;;;;;;;;;;;AAaN,SAASgI,QAAT,CAAmBhI,KAAnB,EAA0B;MACpBd,UAAJ;MAAOiC,aAAP;MACIb,QAAQN,KAAR,CAAJ,EAAoB;QACdA,MAAMZ,MAAV;WACOF,GAAP;eAAqBc,MAAMd,CAAN,CAAT;;GAFd,MAGO,IAAI4B,SAASd,KAAT,CAAJ,EAAqB;WACnBS,OAAOU,IAAP,CAAYnB,KAAZ,CAAP;QACImB,KAAK/B,MAAT;WACOF,GAAP;eAAqBc,MAAMmB,KAAKjC,CAAL,CAAN,CAAT;;;;;;;;;;;;;;;;;;AAiBhB,AAAO,SAAS+I,OAAT,CAAgBnB,KAAhB,EAAuBoB,oBAAvB,EAA6ChH,QAA7C,EAAuD6F,OAAvD,EAAgE;;MAE/D3G,SAASW,WAAWmH,oBAAX,IACAA,oBADA,GAEAC,MAAgBD,oBAAhB,CAFf;SAGO,IAAIrB,OAAJ,CAAYC,KAAZ,EAAmB1G,MAAnB,EAA2Bc,QAA3B,EAAqC6F,OAArC,CAAP;;;;;;;;;;AAUF,AAAO,SAASqB,YAAT,CAAuBtB,KAAvB,EAA8B1G,MAA9B,EAAsC;MACrCsG,UAAU,IAAIG,OAAJ,CAAYC,KAAZ,EAAmB1G,MAAnB,EAA2B,IAA3B,EAAiC;UACzCyD,WAAQ4D,IADiC;UAEzC,IAFyC;UAGzC5D,WAAQiE;GAHA,CAAhB;SAKO,SAASO,cAAT,GAA2B;QAC5B3B,QAAQK,OAAR,CAAgBG,IAAhB,IAAwBxI,IAAIM,MAA5B,IAAsC,CAACN,IAAIM,MAAJ,CAAW+H,OAAX,CAAmBG,IAA9D,EAAoE;cAC1DH,OAAR,CAAgBG,IAAhB,GAAuB,KAAvB;cACQhG,QAAR,GAAmB,YAAY;YACvBiG,OAAOT,QAAQS,IAArB;aACK,IAAIjI,IAAI,CAAR,EAAWC,IAAIgI,KAAK/H,MAAzB,EAAiCF,IAAIC,CAArC,EAAwCD,GAAxC,EAA6C;eACtCA,CAAL,EAAQgE,MAAR;;OAHJ;;QAOEwD,QAAQO,KAAZ,EAAmB;cACTqB,QAAR;;QAEE5J,IAAIM,MAAR,EAAgB;cACNwF,MAAR;;WAEKkC,QAAQ1G,KAAf;GAhBF;;;AC7NFS,OAAO8H,gBAAP,CAAwB1E,UAAxB,EAAiC;WACtB,EAAC7D,OAAOwI,KAAR,EADsB;aAEpB,EAACxI,OAAOyI,OAAR,EAFoB;WAGtB,EAACzI,OAAOiI,QAAR,EAHsB;aAIpB,EAACjI,OAAOiI,QAAR,EAAeS,UAAU,IAAzB,EAJoB;UAKvB,EAAC1I,OAAO,KAAR,EAAe0I,UAAU,IAAzB,EALuB;UAMvB,EAAC1I,OAAO,KAAR,EAAe0I,UAAU,IAAzB,EANuB;UAOvB,EAAC1I,OAAO,KAAR,EAAe0I,UAAU,IAAzB;CAPV;;;;;;;;;;;;;AAqBA,AAAe,SAAS7E,UAAT,CAAkB7E,MAAlB,EAA0BiG,UAA1B,EAAsCjE,IAAtC,EAA4C+F,OAA5C,EAAqD;SAC3D/H,MAAP;SACO6E,WAAQ8E,OAAR,CAAgB3J,MAAhB,EAAwBiG,UAAxB,EAAoCjE,IAApC,EAA0C+F,OAA1C,CAAP;;;;;;;;;;;AAWF,SAASyB,KAAT,CAAgBzB,OAAhB,EAAyB/H,MAAzB,EAAiC;MAC3BA,MAAJ,EAAY;WACHA,MAAP;GADF,MAEO;aACI,EAAT;SACKA,MAAL;;UAEM4J,OAAR,IAAmBC,aAAa7J,MAAb,EAAqB+H,QAAQ6B,OAA7B,CAAnB;UACQ7C,IAAR,IAAgB+C,gBAAgB9J,MAAhB,EAAwB+H,QAAQhB,IAAhC,CAAhB;UACQgD,QAAR,IAAoBC,kBAAkBhK,MAAlB,EAA0B+H,QAAQgC,QAAlC,CAApB;UACQE,QAAR,IAAoBC,gBAAgBlK,MAAhB,EAAwB+H,QAAQkC,QAAhC,CAApB;SACOjK,MAAP;;;;;;;;;;;;;;;;;AAiBF,SAASyJ,OAAT,CAAkBzJ,MAAlB,EAA0BmK,IAA1B,EAAgCC,gBAAhC,EAAkDC,KAAlD,EAAyD;SAChDrK,MAAP;MACIoB,eAAJ;MAAYC,eAAZ;MACIU,WAAWqI,gBAAX,CAAJ,EAAkC;aACvBC,UAAU,KAAV,GACCjB,aAAapJ,MAAb,EAAqBoK,gBAArB,CADD,GAECA,iBAAiBE,IAAjB,CAAsB,IAAtB,CAFV;aAGSlI,IAAT;GAJF,MAKO;aACIgI,iBAAiBhF,GAAjB,GACCgF,iBAAiBC,KAAjB,KAA2B,KAA3B,IAAoCA,UAAU,KAA9C,GACEjB,aAAapJ,MAAb,EAAqBoK,iBAAiBhF,GAAtC,CADF,GAEEgF,iBAAiBhF,GAAjB,CAAqBkF,IAArB,CAA0B,IAA1B,CAHH,GAIClI,IAJV;aAKSgI,iBAAiB1H,GAAjB,GAAuB0H,iBAAiB1H,GAAjB,CAAqB4H,IAArB,CAA0B,IAA1B,CAAvB,GAAyDlI,IAAlE;;iBAEapC,MAAf,EAAuBmK,IAAvB,EAA6B/I,MAA7B,EAAqCC,MAArC;;;;;;;;;;;;;;;;AAgBF,SAAS4H,QAAT,CAAgBjJ,MAAhB,EAAwBkJ,oBAAxB,EAA8ChH,QAA9C,EAA2E;MAAnB6F,OAAmB,uEAATlD,UAAS;;SAClE7E,MAAP;SACOuK,QAAQvK,MAAR,EAAgBkJ,oBAAhB,EAAsChH,QAAtC,EAAgD6F,OAAhD,CAAP;;;;;;;AAOF,SAASyC,IAAT,CAAexK,MAAf,EAAuB;cACTA,MAAZ,EAAoBO,sBAApB,EAA4C,EAA5C,EAAgD,KAAhD;cACYP,MAAZ,EAAoBQ,mBAApB,EAAyCiB,OAAOkB,MAAP,CAAc,IAAd,CAAzC,EAA8D,KAA9D;YACU3C,OAAOQ,mBAAP,CAAV;sBACoBR,MAApB;;;AAGF,SAASyK,MAAT,CAAiBzK,MAAjB,EAAyB;MACnB,CAACyB,OAAOC,SAAP,CAAiBoD,cAAjB,CAAgCjD,IAAhC,CAAqC7B,MAArC,EAA6CO,sBAA7C,CAAL,EAA2E;SACpEP,MAAL;;;;;;;;;AASJ,SAAS6J,YAAT,CAAuB7J,MAAvB,EAA+B4J,OAA/B,EAAwC;eACzBA,OAAb,EAAsB,UAACO,IAAD,EAAO5G,MAAP,EAAkB;WAC/B4G,IAAP,IAAe5G,OAAO+G,IAAP,CAAYtK,MAAZ,CAAf;GADF;;;;;;;;;AAWF,SAAS0K,aAAT,CAAwB1K,MAAxB,EAAgC6C,GAAhC,EAAqC7B,KAArC,EAA4C;SACnCR,mBAAP,EAA4BqC,GAA5B,IAAmC7B,KAAnC;iBACehB,OAAOQ,mBAAP,CAAf,EAA4CqC,GAA5C,EAAiD7B,KAAjD;QACMhB,MAAN,EAAc6C,GAAd;;;;;;;;AAQF,SAASiH,eAAT,CAA0B9J,MAA1B,EAAkC2K,UAAlC,EAA8C;eAC/BA,UAAb,EAAyB,UAAC9H,GAAD,EAAM7B,KAAN;WAAgB0J,cAAc1K,MAAd,EAAsB6C,GAAtB,EAA2B7B,KAA3B,CAAhB;GAAzB;;;;;;;AAOF,SAAS4J,mBAAT,CAA8B5K,MAA9B,EAAsC;eACvBA,MAAb,EAAqB,UAAC6C,GAAD,EAAM7B,KAAN,EAAgB;KAClCe,WAAWf,KAAX,CAAD,IAAsB0J,cAAc1K,MAAd,EAAsB6C,GAAtB,EAA2B7B,KAA3B,CAAtB;GADF;;;;;;;;AAUF,SAASgJ,iBAAT,CAA4BhK,MAA5B,EAAoC2K,UAApC,EAAgD;eACjCA,UAAb,EAAyB,UAAC9H,GAAD,EAAM7B,KAAN;WAAgByI,QAAQzJ,MAAR,EAAgB6C,GAAhB,EAAqB7B,KAArB,CAAhB;GAAzB;;;;;;;;AAQF,SAASkJ,eAAT,CAA0BlK,MAA1B,EAAkC2K,UAAlC,EAA8C;eAC/BA,UAAb,EAAyB,UAAC1E,UAAD,EAAa4E,gBAAb,EAAkC;QACrD9I,WAAW8I,gBAAX,CAAJ,EAAkC;eAC1B7K,MAAN,EAAciG,UAAd,EAA0B4E,gBAA1B;KADF,MAEO;eACC7K,MAAN,EAAciG,UAAd,EAA0B4E,iBAAiBnD,OAA3C,EAAoDmD,gBAApD;;GAJJ;;;;;;;;AAcF,SAASC,KAAT,CAAgB9K,MAAhB,EAAwB6C,GAAxB,EAA6B;WAClBzB,MAAT,GAAmB;WACVpB,OAAOQ,mBAAP,EAA4BqC,GAA5B,CAAP;;WAEOxB,MAAT,CAAiBL,KAAjB,EAAwB;WACfR,mBAAP,EAA4BqC,GAA5B,IAAmC7B,KAAnC;;iBAEahB,MAAf,EAAuB6C,GAAvB,EAA4BzB,MAA5B,EAAoCC,MAApC;;;;;"} -------------------------------------------------------------------------------- /dist/smart-observe.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("observe",t):e.observe=t()}(this,function(){"use strict";function e(e,t,n,i){Object.defineProperty(e,t,{value:n,enumerable:!!i,writable:!0,configurable:!0})}function t(e,t,n,i){Object.defineProperty(e,t,{get:n,set:i,enumerable:!0,configurable:!0})}function n(e){return K.call(e)===L}function i(e){return null!==e&&"object"===("undefined"==typeof e?"undefined":N(e))}function o(e){return"function"==typeof e}function r(e,t){for(var n=Object.keys(e),i=0,o=n.length;i=this.length&&(this.length=Number(e)+1),this.splice(e,1,t)[0]}function c(e){if(this.length){var t=this.indexOf(e);return t>-1?this.splice(t,1):void 0}}function f(e){if(e&&"object"===("undefined"==typeof e?"undefined":N(e))){var t=void 0;return Object.prototype.hasOwnProperty.call(e,V)&&e[V]instanceof ne?t=e[V]:(J(e)||n(e))&&Object.isExtensible(e)&&(t=new ne(e)),t}}function l(e,n,i){function o(){var t=a?a.call(e):i;if(F.target&&(s.depend(),l&&l.dep.depend(),J(t)))for(var n,o=0,r=t.length;o3&&void 0!==arguments[3]?arguments[3]:O;return I(e),k(e,t,n,i)}function _(t){e(t,q,[],!1),e(t,B,Object.create(null),!1),f(t[B]),A(t)}function I(e){Object.prototype.hasOwnProperty.call(e,q)||_(e)}function x(e,t){r(t,function(t,n){e[t]=n.bind(e)})}function z(e,t,n){e[B][t]=n,l(e[B],t,n),E(e,t)}function P(e,t){r(t,function(t,n){return z(e,t,n)})}function A(e){r(e,function(t,n){!o(n)&&z(e,t,n)})}function G(e,t){r(t,function(t,n){return D(e,t,n)})}function T(e,t){r(t,function(t,n){o(n)?S(e,t,n):S(e,t,n.watcher,n)})}function E(e,n){function i(){return e[B][n]}function o(t){e[B][n]=t}t(e,n,i,o)}var N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},$=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},M=function(){function e(e,t){for(var n=0;n1;)i.unshift(arguments[o]);n=function(){e.apply(t,i)}}ie.push(n),oe||(oe=!0,te(p))},ce=[],fe={},le=!1,he=void 0,de=0,pe=function(){function e(t,n,i,o){$(this,e),t[q].push(this),this.owner=t,this.getter=n,this.callback=i,this.options=o,this.id=++de,this.active=!0,this.dirty=o.lazy,this.deps=[],this.newDeps=[],this.depIds=new R,this.newDepIds=new R,this.value=o.lazy?void 0:this.get()}return M(e,[{key:"get",value:function(){this.beforeGet();var e=this.owner,t=this.getter.call(e,e);return this.options.deep&&w(t),this.afterGet(),t}},{key:"beforeGet",value:function(){F.target=this}},{key:"addDep",value:function(e){var t=e.id;this.newDepIds.has(t)||(this.newDepIds.add(t),this.newDeps.push(e),this.depIds.has(t)||e.addSub(this))}},{key:"afterGet",value:function(){F.target=null;for(var e=this.deps.length;e--;){var t=this.deps[e];this.newDepIds.has(t.id)||t.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0}},{key:"update",value:function(){this.options.lazy?this.dirty=!0:this.options.sync?this.run():g(this)}},{key:"run",value:function(){if(this.active){var e=this.get();if(e!==this.value||i(e)||this.options.deep){var t=this.value;this.value=e,this.callback.call(this.owner,e,t)}}}},{key:"evaluate",value:function(){var e=F.target;this.value=this.get(),this.dirty=!1,F.target=e}},{key:"depend",value:function(){for(var e=this.deps.length;e--;)this.deps[e].depend()}},{key:"teardown",value:function(){if(this.active){for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1,this.owner=this.callback=this.value=null}}}]),e}();return Object.defineProperties(O,{react:{value:j},compute:{value:D},watch:{value:S},default:{value:S,writable:!0},deep:{value:!1,writable:!0},lazy:{value:!1,writable:!0},sync:{value:!1,writable:!0}}),O}); 2 | //# sourceMappingURL=smart-observe.min.js.map 3 | -------------------------------------------------------------------------------- /dist/smart-observe.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"smart-observe.min.js","sources":["../src/util.js","../src/array.js","../src/observe.js","../src/expression.js","../node_modules/smart-next-tick/nextTick.js","../src/batcher.js","../src/watcher.js","../src/index.js","../src/dep.js","../src/constants.js"],"sourcesContent":["import {DEBUGGING} from './constants'\n\n/**\n * Define property with value.\n *\n * @param {Object} object\n * @param {String} property\n * @param {*} value\n * @param {Boolean} [enumerable]\n */\n\nexport function defineValue (object, property, value, enumerable) {\n Object.defineProperty(object, property, {\n value,\n enumerable: !!enumerable,\n writable: true,\n configurable: true,\n })\n}\n\n/**\n * Define property with getter and setter.\n *\n * @param {Object} object\n * @param {String} property\n * @param {Function} getter\n * @param {Function} setter\n */\n\nexport function defineAccessor (object, property, getter, setter) {\n Object.defineProperty(object, property, {\n get: getter,\n set: setter,\n enumerable: true,\n configurable: true,\n })\n}\n\n/**\n * Array type check.\n *\n * @return {Boolean}\n */\n\nexport const isArray = Array.isArray\n\n/**\n * Strict object type check. Only returns true\n * for plain JavaScript objects.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nconst toString = Object.prototype.toString\nconst OBJECT_STRING = '[object Object]'\nexport function isPlainObject (object) {\n return toString.call(object) === OBJECT_STRING\n}\n\n/**\n * Quick object check - this is primarily used to tell\n * Objects from primitive values when we know the value\n * is a JSON-compliant type.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nexport function isObject (object) {\n return object !== null && typeof object === 'object'\n}\n\n/**\n * Function type check\n *\n * @param {*} func\n * @param {Boolean}\n */\n\nexport function isFunction (func) {\n return typeof func === 'function'\n}\n\n/**\n * Iterate object\n *\n * @param {Object} object\n * @param {Function} callback\n */\n\nexport function everyEntries (object, callback) {\n const keys = Object.keys(object)\n for (let i = 0, l = keys.length; i < l; i++) {\n callback(keys[i], object[keys[i]])\n }\n}\n\n/**\n * noop is function which is nothing to do.\n */\n\nexport function noop () {}\n\n/**\n * @param {String} string\n */\n\nexport const warn = typeof DEBUGGING !== 'undefined' && DEBUGGING\n && typeof console !== 'undefined' && console\n && isFunction(console.warn)\n ? console.warn\n : noop\n\nexport let _Set\nif (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {\n // use native Set when available.\n _Set = Set\n} else {\n // a non-standard Set polyfill that only works with primitive keys.\n _Set = function () {\n this.set = Object.create(null)\n }\n _Set.prototype.has = function (key) {\n return this.set[key] !== undefined\n }\n _Set.prototype.add = function (key) {\n this.set[key] = 1\n }\n _Set.prototype.clear = function () {\n this.set = Object.create(null)\n }\n}\n","import {defineValue} from './util'\nimport {OBSERVE_NAME} from './constants'\n\nconst arrayPrototype = Array.prototype\nconst arrayMethods = Object.create(arrayPrototype)\nconst arrayMutativeMethods = [\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n]\n\n/**\n * Augment an target Array with arrayMethods\n *\n * @param {Array} array\n */\n\nexport default function amend (array) {\n Object.setPrototypeOf(array, arrayMethods)\n}\n\n/**\n * Intercept mutating methods and emit events\n */\n\nfor (let i = 0, l = arrayMutativeMethods.length; i < l; i++) {\n const method = arrayMutativeMethods[i]\n // cache original method\n const original = arrayPrototype[method]\n defineValue(arrayMethods, method, function mutator (...args) {\n const result = original.apply(this, args)\n const observer = this[OBSERVE_NAME]\n let inserted\n switch (method) {\n case 'push':\n inserted = args\n break\n case 'unshift':\n inserted = args\n break\n case 'splice':\n inserted = args.slice(2)\n break\n }\n if (inserted) observer.observeArray(inserted)\n observer.dep.notify() // notify change\n return result\n })\n}\n\n/**\n * Swap the element at the given index with a new value\n * and emits corresponding event.\n *\n * @param {Number} index\n * @param {*} value\n * @return {*} - replaced element\n */\n\nfunction $set (index, value) {\n if (index >= this.length) {\n this.length = Number(index) + 1\n }\n return this.splice(index, 1, value)[0]\n}\ndefineValue(arrayPrototype, '$set', $set)\n\n/**\n * Convenience method to remove the element at given index\n * or target element reference.\n *\n * @param {*} item\n * @return {*} - removed element\n */\n\nfunction $remove (item) {\n if (!this.length) return\n const index = this.indexOf(item)\n if (index > -1) {\n return this.splice(index, 1)\n }\n}\ndefineValue(arrayPrototype, '$remove', $remove)\n","import Dep from './dep'\nimport amendArray from './array'\nimport {\n defineValue,\n defineAccessor,\n isArray,\n isPlainObject,\n everyEntries,\n} from './util'\nimport {OBSERVE_NAME} from './constants'\n\n/**\n * Observer class that are attached to each observed\n * object. Once attached, the observer converts target\n * object's property keys into getter/setters that\n * collect dependencies and dispatches updates.\n *\n * @class\n * @param {Array|Object} value\n */\n\nclass Observer {\n constructor (value) {\n this.value = value\n this.dep = new Dep()\n defineValue(value, OBSERVE_NAME, this)\n if (isArray(value)) {\n amendArray(value)\n this.observeArray(value)\n } else {\n this.walk(value)\n }\n }\n\n /**\n * Walk through each property and convert them into\n * getter/setters. This method should only be called when\n * value type is Object.\n *\n * @param {Object} object\n */\n\n walk (object) {\n everyEntries(object, (key, value) => this.convert(key, value))\n }\n\n /**\n * Observe a list of Array items.\n *\n * @param {Array} items\n */\n\n observeArray (items) {\n for (let i = 0, l = items.length; i < l; i++) {\n observe(items[i])\n }\n }\n\n /**\n * Convert a property into getter/setter so we can emit\n * the events when the property is accessed/changed.\n *\n * @param {String} key\n * @param {*} value\n */\n\n convert (key, value) {\n defineReactive(this.value, key, value)\n }\n}\n\n/**\n * Attempt to create an observer instance for a value,\n * returns the new observer if successfully observed,\n * or the existing observer if the value already has one.\n *\n * @param {*} value\n * @return {Observer|undefined}\n */\n\nexport function observe (value) {\n if (!value || typeof value !== 'object') return\n let observer\n if (\n Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME)\n && value[OBSERVE_NAME] instanceof Observer\n ) {\n observer = value[OBSERVE_NAME]\n } else if (\n (isArray(value) || isPlainObject(value))\n && Object.isExtensible(value)\n ) {\n observer = new Observer(value)\n }\n return observer\n}\n\n/**\n * Define a reactive property on an Object.\n *\n * @param {Object} object\n * @param {String} key\n * @param {*} value\n */\n\nexport function defineReactive (object, key, value) {\n const dep = new Dep()\n\n const desc = Object.getOwnPropertyDescriptor(object, key)\n if (desc && desc.configurable === false) return\n\n // cater for pre-defined getter/setters\n const getter = desc && desc.get\n const setter = desc && desc.set\n\n let childOb = observe(value)\n\n function reactiveGetter () {\n const currentValue = getter ? getter.call(object) : value\n if (Dep.target) {\n dep.depend()\n if (childOb) {\n childOb.dep.depend()\n }\n if (isArray(currentValue)) {\n for (let i = 0, l = currentValue.length, e; i < l; i++) {\n e = currentValue[i]\n e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend()\n }\n }\n }\n return currentValue\n }\n function reactiveSetter (newValue) {\n const oldValue = getter ? getter.call(object) : value\n if (newValue === oldValue) return\n if (setter) {\n setter.call(object, newValue)\n } else {\n value = newValue\n }\n childOb = observe(newValue)\n dep.notify()\n }\n defineAccessor(object, key, reactiveGetter, reactiveSetter)\n}\n","import {warn} from './util'\n\n/**\n * Build a getter function. Requires eval.\n *\n * We isolate the try/catch so it doesn't affect the\n * optimization of the parse function when it is not called.\n *\n * @param {String} body\n * @return {Function|undefined}\n */\n\nfunction makeGetterFunction (body) {\n try {\n /* eslint-disable no-new-func */\n return new Function('scope', `return ${body};`)\n /* eslint-enable no-new-func */\n } catch (e) {\n warn('Invalid expression. Generated function body: ' + body)\n }\n}\n\n/**\n * Parse an expression to getter.\n *\n * @param {String} expression\n * @return {Function|undefined}\n */\n\nexport default function parse (expression) {\n expression = String.prototype.trim.call(expression)\n return makeGetterFunction('scope.' + expression)\n}\n","var callbacks = []\nvar pending = false\nfunction nextTickHandler () {\n pending = false\n var callbackCopies = callbacks.slice(0)\n callbacks.length = 0\n for (var i = 0; i < callbackCopies.length; i++) {\n callbackCopies[i]()\n }\n}\n\nvar callNextTick\nif (typeof process === 'object'\n && process\n && typeof process.nextTick === 'function'\n) {\n callNextTick = process.nextTick\n} else if (typeof MutationObserver !== 'undefined') {\n var counter = 0\n var textNode = document.createTextNode(counter)\n var observer = new MutationObserver(nextTickHandler)\n observer.observe(textNode, {\n characterData: true\n })\n callNextTick = function () {\n counter = counter === 0 ? 1 : 0\n textNode.data = String(counter)\n }\n} else {\n callNextTick = setTimeout\n}\n\n\nmodule.exports = function nextTick (callback, context) {\n var func = callback\n if (context) {\n var args = []\n var l = arguments.length\n while (--l > 1) {\n args.unshift(arguments[l])\n }\n func = function () {\n callback.apply(context, args)\n }\n }\n callbacks.push(func)\n if (pending) {\n return\n }\n pending = true\n callNextTick(nextTickHandler)\n}\n","import nextTick from 'smart-next-tick'\n\nlet queue = []\nlet has = {}\nlet waiting = false\nlet queueIndex\n\n/**\n * Reset the batcher's state.\n */\n\nfunction resetBatcherState () {\n queue = []\n has = {}\n waiting = false\n}\n\n/**\n * Flush queue and run the watchers.\n */\n\nfunction flushBatcherQueue () {\n runBatcherQueue(queue)\n resetBatcherState()\n}\n\n/**\n * Run the watchers in a single queue.\n *\n * @param {Array} queue\n */\n\nfunction runBatcherQueue (queue) {\n // do not cache length because more watchers might be pushed\n // as we run existing watchers\n for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {\n const watcher = queue[queueIndex]\n const id = watcher.id\n has[id] = null\n watcher.run()\n }\n}\n\n/**\n * Push a watcher into the watcher queue.\n * Jobs with duplicate IDs will be skipped unless it's\n * pushed when the queue is being flushed.\n *\n * @param {Watcher} watcher\n * properties:\n * - {Number} id\n * - {Function} run\n */\n\nexport default function batch (watcher) {\n const id = watcher.id\n if (has[id] == null) {\n has[id] = queue.length\n queue.push(watcher)\n // queue the flush\n if (!waiting) {\n waiting = true\n nextTick(flushBatcherQueue)\n }\n }\n}\n","import observe from './index'\nimport Dep from './dep'\nimport parseExpression from './expression'\nimport batch from './batcher'\nimport {\n isArray,\n isObject,\n isFunction,\n _Set as Set,\n} from './util'\nimport {WATCHERS_PROPERTY_NAME} from './constants'\n\nlet uid = 0\n\nclass Watcher {\n\n /**\n * A watcher parses an expression, collects dependencies,\n * and fires callback when the expression value changes.\n *\n * @param {Object} owner\n * @param {String|Function} getter\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @constructor\n */\n\n constructor (owner, getter, callback, options) {\n owner[WATCHERS_PROPERTY_NAME].push(this)\n this.owner = owner\n this.getter = getter\n this.callback = callback\n this.options = options\n // uid for batching\n this.id = ++uid\n this.active = true\n // for lazy watchers\n this.dirty = options.lazy\n this.deps = []\n this.newDeps = []\n this.depIds = new Set()\n this.newDepIds = new Set()\n this.value = options.lazy\n ? undefined\n : this.get()\n }\n\n /**\n * Evaluate the getter, and re-collect dependencies.\n */\n\n get () {\n this.beforeGet()\n const scope = this.owner\n const value = this.getter.call(scope, scope)\n if (this.options.deep) {\n traverse(value)\n }\n this.afterGet()\n return value\n }\n\n /**\n * Prepare for dependency collection.\n */\n\n beforeGet () {\n Dep.target = this\n }\n\n /**\n * Add a dependency to this directive.\n *\n * @param {Dep} dep\n */\n\n addDep (dep) {\n const id = dep.id\n if (!this.newDepIds.has(id)) {\n this.newDepIds.add(id)\n this.newDeps.push(dep)\n if (!this.depIds.has(id)) {\n dep.addSub(this)\n }\n }\n }\n\n /**\n * Clean up for dependency collection.\n */\n\n afterGet () {\n Dep.target = null\n let i = this.deps.length\n while (i--) {\n const dep = this.deps[i]\n if (!this.newDepIds.has(dep.id)) {\n dep.removeSub(this)\n }\n }\n let tmp = this.depIds\n this.depIds = this.newDepIds\n this.newDepIds = tmp\n this.newDepIds.clear()\n tmp = this.deps\n this.deps = this.newDeps\n this.newDeps = tmp\n this.newDeps.length = 0\n }\n\n /**\n * Will be called when a dependency changes.\n */\n\n update () {\n if (this.options.lazy) {\n this.dirty = true\n } else if (this.options.sync) {\n this.run()\n } else {\n batch(this)\n }\n }\n\n /**\n * Will be called by the batcher.\n */\n\n run () {\n if (this.active) {\n const value = this.get()\n if (\n value !== this.value\n // Deep watchers and watchers on Object/Arrays should fire even when\n // the value is the same, because the value may have mutated;\n || ((isObject(value) || this.options.deep))\n ) {\n const oldValue = this.value\n this.value = value\n this.callback.call(this.owner, value, oldValue)\n }\n }\n }\n\n /**\n * Evaluate the value of the watcher.\n * This only gets called for lazy watchers.\n */\n\n evaluate () {\n // avoid overwriting another watcher that is being collected.\n const current = Dep.target\n this.value = this.get()\n this.dirty = false\n Dep.target = current\n }\n\n /**\n * Depend on all deps collected by this watcher.\n */\n\n depend () {\n let i = this.deps.length\n while (i--) {\n this.deps[i].depend()\n }\n }\n\n /**\n * Remove self from all dependencies' subcriber list.\n */\n\n teardown () {\n if (this.active) {\n let i = this.deps.length\n while (i--) {\n this.deps[i].removeSub(this)\n }\n this.active = false\n this.owner = this.callback = this.value = null\n }\n }\n}\n\n/**\n * Recrusively traverse an object to evoke all converted\n * getters, so that every nested property inside the object\n * is collected as a \"deep\" dependency.\n *\n * @param {*} value\n */\n\nfunction traverse (value) {\n let i, keys\n if (isArray(value)) {\n i = value.length\n while (i--) traverse(value[i])\n } else if (isObject(value)) {\n keys = Object.keys(value)\n i = keys.length\n while (i--) traverse(value[keys[i]])\n }\n}\n\n/**\n * Create an watcher instance, returns the new watcher.\n *\n * @param {Object} owner\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nexport function watch (owner, expressionOrFunction, callback, options) {\n // parse expression for getter\n const getter = isFunction(expressionOrFunction)\n ? expressionOrFunction\n : parseExpression(expressionOrFunction)\n return new Watcher(owner, getter, callback, options)\n}\n\n/**\n * Make a computed getter, which can collect dependencies.\n *\n * @param {Object} owner\n * @param {Function} getter\n */\n\nexport function makeComputed (owner, getter) {\n const watcher = new Watcher(owner, getter, null, {\n deep: observe.deep,\n lazy: true,\n sync: observe.sync,\n })\n return function computedGetter () {\n if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {\n watcher.options.lazy = false\n watcher.callback = function () {\n const deps = watcher.deps\n for (let i = 0, l = deps.length; i < l; i++) {\n deps[i].notify()\n }\n }\n }\n if (watcher.dirty) {\n watcher.evaluate()\n }\n if (Dep.target) {\n watcher.depend()\n }\n return watcher.value\n }\n}\n","import {\n observe as doObserve,\n defineReactive,\n} from './observe'\nimport {\n watch as doWatch,\n makeComputed,\n} from './watcher'\nimport {\n defineValue,\n defineAccessor,\n noop,\n isFunction,\n everyEntries,\n} from './util'\nimport {\n WATCHERS_PROPERTY_NAME,\n DATA_PROPTERTY_NAME,\n} from './constants'\n\nObject.defineProperties(observe, {\n 'react': {value: react},\n 'compute': {value: compute},\n 'watch': {value: watch},\n 'default': {value: watch, writable: true}, // Only could be react, compute or watch\n 'deep': {value: false, writable: true},\n 'lazy': {value: false, writable: true},\n 'sync': {value: false, writable: true},\n})\n\n/**\n * observe\n *\n * @public\n * @param {Object} target\n * @param {*} [expression]\n * @param {*} [func]\n * @param {*} [options]\n * @return {Function} observe\n */\n\nexport default function observe (target, expression, func, options) {\n ensure(target)\n return observe.default(target, expression, func, options)\n}\n\n/**\n * React options\n *\n * @param {Object} options\n * @param {Object} [target]\n * @return {Function} observe\n */\n\nfunction react (options, target) {\n if (target) {\n ensure(target)\n } else {\n target = {}\n init(target)\n }\n options.methods && carryMethods(target, options.methods)\n options.data && reactProperties(target, options.data)\n options.computed && computeProperties(target, options.computed)\n options.watchers && watchProperties(target, options.watchers)\n return target\n}\n\n/**\n * Compute property\n *\n * @param {Object} target\n * @param {String} name\n * @param {Function|Object} getterOrAccessor\n * - Function getter\n * - Object accessor\n * - Function [get] - getter\n * - Function [set] - setter\n * - Boolean [cache]\n * @param {Boolean} [cache]\n */\n\nfunction compute (target, name, getterOrAccessor, cache) {\n ensure(target)\n let getter, setter\n if (isFunction(getterOrAccessor)) {\n getter = cache !== false\n ? makeComputed(target, getterOrAccessor)\n : getterOrAccessor.bind(this)\n setter = noop\n } else {\n getter = getterOrAccessor.get\n ? getterOrAccessor.cache !== false || cache !== false\n ? makeComputed(target, getterOrAccessor.get)\n : getterOrAccessor.get.bind(this)\n : noop\n setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop\n }\n defineAccessor(target, name, getter, setter)\n}\n\n/**\n * Watch property\n *\n * @param {Object} target\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} [options]\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nfunction watch (target, expressionOrFunction, callback, options = observe) {\n ensure(target)\n return doWatch(target, expressionOrFunction, callback, options)\n}\n\n/**\n * @param {Object} target\n */\n\nfunction init (target) {\n defineValue(target, WATCHERS_PROPERTY_NAME, [], false)\n defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false)\n doObserve(target[DATA_PROPTERTY_NAME])\n reactSelfProperties(target)\n}\n\nfunction ensure (target) {\n if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {\n init(target)\n }\n}\n\n/**\n * @param {Object} target\n * @param {Object} methods\n */\n\nfunction carryMethods (target, methods) {\n everyEntries(methods, (name, method) => {\n target[name] = method.bind(target)\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n * @param {*} value\n */\n\nfunction reactProperty (target, key, value) {\n target[DATA_PROPTERTY_NAME][key] = value\n defineReactive(target[DATA_PROPTERTY_NAME], key, value)\n proxy(target, key)\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction reactProperties (target, properties) {\n everyEntries(properties, (key, value) => reactProperty(target, key, value))\n}\n\n/**\n * @param {Object} target\n */\n\nfunction reactSelfProperties (target) {\n everyEntries(target, (key, value) => {\n !isFunction(value) && reactProperty(target, key, value)\n })\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction computeProperties (target, properties) {\n everyEntries(properties, (key, value) => compute(target, key, value))\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction watchProperties (target, properties) {\n everyEntries(properties, (expression, functionOrOption) => {\n if (isFunction(functionOrOption)) {\n watch(target, expression, functionOrOption)\n } else {\n watch(target, expression, functionOrOption.watcher, functionOrOption)\n }\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n */\n\nfunction proxy (target, key) {\n function getter () {\n return target[DATA_PROPTERTY_NAME][key]\n }\n function setter (value) {\n target[DATA_PROPTERTY_NAME][key] = value\n }\n defineAccessor(target, key, getter, setter)\n}\n","let uid = 0\n\n/**\n * A dep is an observable that can have multiple\n * watcher subscribing to it.\n */\n\nexport default class Dep {\n // the current target watcher being evaluated.\n // this is globally unique because there could be only one\n // watcher being evaluated at any time.\n static target = null\n\n constructor () {\n this.id = uid++\n this.subs = []\n }\n\n /**\n * Add a subscriber.\n *\n * @param {Watcher} sub\n */\n\n addSub (sub) {\n this.subs.push(sub)\n }\n\n /**\n * Remove a subscriber.\n *\n * @param {Watcher} sub\n */\n\n removeSub (sub) {\n this.subs.$remove(sub)\n }\n\n /**\n * Add self as a dependency to the target watcher.\n */\n\n depend () {\n Dep.target.addDep(this)\n }\n\n /**\n * Notify all subscribers of a new value.\n */\n\n notify () {\n const subs = this.subs\n for (let i = 0, l = subs.length; i < l; i++) {\n subs[i].update()\n }\n }\n}\n","export const OBSERVE_NAME = '__s_o__'\nexport const WATCHERS_PROPERTY_NAME = '__watchers__'\nexport const DATA_PROPTERTY_NAME = '__data__'\n\nexport const DEBUGGING = typeof process !== 'undefined'\n && process.env.NODE_ENV !== 'production'\n"],"names":["defineValue","object","property","value","enumerable","defineProperty","defineAccessor","getter","setter","isPlainObject","toString","call","OBJECT_STRING","isObject","isFunction","func","everyEntries","callback","keys","Object","i","l","length","noop","amend","array","setPrototypeOf","arrayMethods","$set","index","this","Number","splice","$remove","item","indexOf","observe","observer","prototype","hasOwnProperty","OBSERVE_NAME","Observer","isArray","isExtensible","defineReactive","key","reactiveGetter","currentValue","Dep","target","depend","childOb","dep","e","reactiveSetter","newValue","oldValue","notify","desc","getOwnPropertyDescriptor","configurable","get","set","makeGetterFunction","body","Function","parse","expression","String","trim","nextTickHandler","callbackCopies","callbacks","slice","resetBatcherState","flushBatcherQueue","queue","runBatcherQueue","queueIndex","watcher","id","run","batch","has","push","waiting","traverse","watch","owner","expressionOrFunction","options","parseExpression","Watcher","makeComputed","deep","sync","lazy","deps","dirty","evaluate","default","react","methods","carryMethods","data","reactProperties","computed","computeProperties","watchers","watchProperties","compute","name","getterOrAccessor","cache","bind","doWatch","init","WATCHERS_PROPERTY_NAME","DATA_PROPTERTY_NAME","create","ensure","method","reactProperty","properties","reactSelfProperties","functionOrOption","proxy","uid","subs","sub","addDep","update","DEBUGGING","process","env","NODE_ENV","Array","warn","console","_Set","Set","match","undefined","add","clear","arrayPrototype","arrayMutativeMethods","original","args","result","apply","inserted","observeArray","callNextTick","walk","_this","convert","items","pending","nextTick","MutationObserver","counter","textNode","document","createTextNode","setTimeout","context","arguments","unshift","active","newDeps","depIds","newDepIds","beforeGet","scope","afterGet","addSub","removeSub","tmp","current","defineProperties","writable"],"mappings":"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"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smart-observe", 3 | "version": "1.0.4", 4 | "description": "smart-observe comes from Vue.js and is a small, efficient library for observing changes of javascript Object, Array and Class.", 5 | "main": "dist/smart-observe.js", 6 | "scripts": { 7 | "test": "mocha", 8 | "lint": "eslint src", 9 | "clean": "rm -rf dist/*", 10 | "rollup": "rollup --config --environment NODE_ENV:production --sourcemap", 11 | "prebuild": "npm run lint && npm run clean", 12 | "build": "npm run rollup && MIN=min npm run rollup", 13 | "postbuild": "npm run test" 14 | }, 15 | "dependencies": { 16 | "smart-next-tick": "^1.1.0" 17 | }, 18 | "devDependencies": { 19 | "babel-core": "^6.26.0", 20 | "babel-eslint": "^8.0.1", 21 | "babel-plugin-external-helpers": "^6.22.0", 22 | "babel-plugin-transform-class-properties": "^6.24.1", 23 | "babel-preset-env": "^1.6.1", 24 | "babel-preset-stage-0": "^6.24.1", 25 | "chai": "^4.1.2", 26 | "eslint": "^4.10.0", 27 | "eslint-config-standard": "^10.2.1", 28 | "eslint-plugin-import": "^2.8.0", 29 | "eslint-plugin-node": "^5.2.1", 30 | "eslint-plugin-promise": "^3.6.0", 31 | "eslint-plugin-standard": "^3.0.1", 32 | "mocha": "^4.0.1", 33 | "rollup": "^0.50.0", 34 | "rollup-plugin-babel": "^3.0.2", 35 | "rollup-plugin-commonjs": "^8.2.6", 36 | "rollup-plugin-node-resolve": "^3.0.0", 37 | "rollup-plugin-uglify": "^2.0.1" 38 | }, 39 | "keywords": [ 40 | "observe", 41 | "observer", 42 | "watch", 43 | "watcher", 44 | "computed", 45 | "vue", 46 | "vue.js", 47 | "ob.js", 48 | "ob" 49 | ], 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/cnlon/smart-observe.git" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/cnlon/smart-observe/issues" 56 | }, 57 | "homepage": "https://github.com/cnlon/smart-observe#readme", 58 | "author": "lon (http://lon.im)", 59 | "license": "MIT" 60 | } 61 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve' 2 | import babel from 'rollup-plugin-babel' 3 | import uglify from 'rollup-plugin-uglify' 4 | 5 | const needMin = !!process.env.MIN 6 | let file = 'dist/smart-observe.js' 7 | const plugins = [ 8 | resolve({ 9 | jsnext: true, 10 | browser: true, 11 | }), 12 | babel({ 13 | presets: [ 14 | ['env', { 15 | targets: { 16 | browsers: ['last 3 versions', 'IE >= 9'], 17 | node: '4' 18 | }, 19 | modules: false 20 | }] 21 | ], 22 | plugins: [ 23 | 'transform-class-properties', 24 | 'external-helpers' 25 | ], 26 | }) 27 | ] 28 | if (needMin) { 29 | file = 'dist/smart-observe.min.js' 30 | plugins.push(uglify()) 31 | } 32 | 33 | export default { 34 | input: 'src/index.js', 35 | output: { 36 | file, 37 | format: 'umd', 38 | name: 'observe', 39 | banner: 40 | `/** 41 | * smart-observe --- By lon 42 | * https://github.com/cnlon/smart-observe 43 | */`, 44 | }, 45 | plugins, 46 | } 47 | -------------------------------------------------------------------------------- /src/array.js: -------------------------------------------------------------------------------- 1 | import {defineValue} from './util' 2 | import {OBSERVE_NAME} from './constants' 3 | 4 | const arrayPrototype = Array.prototype 5 | const arrayMethods = Object.create(arrayPrototype) 6 | const arrayMutativeMethods = [ 7 | 'push', 8 | 'pop', 9 | 'shift', 10 | 'unshift', 11 | 'splice', 12 | 'sort', 13 | 'reverse', 14 | ] 15 | 16 | /** 17 | * Augment an target Array with arrayMethods 18 | * 19 | * @param {Array} array 20 | */ 21 | 22 | export default function amend (array) { 23 | Object.setPrototypeOf(array, arrayMethods) 24 | } 25 | 26 | /** 27 | * Intercept mutating methods and emit events 28 | */ 29 | 30 | for (let i = 0, l = arrayMutativeMethods.length; i < l; i++) { 31 | const method = arrayMutativeMethods[i] 32 | // cache original method 33 | const original = arrayPrototype[method] 34 | defineValue(arrayMethods, method, function mutator (...args) { 35 | const result = original.apply(this, args) 36 | const observer = this[OBSERVE_NAME] 37 | let inserted 38 | switch (method) { 39 | case 'push': 40 | inserted = args 41 | break 42 | case 'unshift': 43 | inserted = args 44 | break 45 | case 'splice': 46 | inserted = args.slice(2) 47 | break 48 | } 49 | if (inserted) observer.observeArray(inserted) 50 | observer.dep.notify() // notify change 51 | return result 52 | }) 53 | } 54 | 55 | /** 56 | * Swap the element at the given index with a new value 57 | * and emits corresponding event. 58 | * 59 | * @param {number} index 60 | * @param {*} value 61 | * @return {*} - replaced element 62 | */ 63 | 64 | function $set (index, value) { 65 | if (index >= this.length) { 66 | this.length = Number(index) + 1 67 | } 68 | return this.splice(index, 1, value)[0] 69 | } 70 | defineValue(arrayPrototype, '$set', $set) 71 | 72 | /** 73 | * Convenience method to remove the element at given index 74 | * or target element reference. 75 | * 76 | * @param {*} item 77 | * @return {*} - removed element 78 | */ 79 | 80 | function $remove (item) { 81 | if (!this.length) return 82 | const index = this.indexOf(item) 83 | if (index > -1) { 84 | return this.splice(index, 1) 85 | } 86 | } 87 | defineValue(arrayPrototype, '$remove', $remove) 88 | -------------------------------------------------------------------------------- /src/batcher.js: -------------------------------------------------------------------------------- 1 | import nextTick from 'smart-next-tick' 2 | 3 | let queue = [] 4 | let has = {} 5 | let waiting = false 6 | let queueIndex 7 | 8 | /** 9 | * Reset the batcher's state. 10 | */ 11 | 12 | function resetBatcherState () { 13 | queue = [] 14 | has = {} 15 | waiting = false 16 | } 17 | 18 | /** 19 | * Flush queue and run the watchers. 20 | */ 21 | 22 | function flushBatcherQueue () { 23 | runBatcherQueue(queue) 24 | resetBatcherState() 25 | } 26 | 27 | /** 28 | * Run the watchers in a single queue. 29 | * 30 | * @param {Array} queue 31 | */ 32 | 33 | function runBatcherQueue (queue) { 34 | // do not cache length because more watchers might be pushed 35 | // as we run existing watchers 36 | for (queueIndex = 0; queueIndex < queue.length; queueIndex++) { 37 | const watcher = queue[queueIndex] 38 | const id = watcher.id 39 | has[id] = null 40 | watcher.run() 41 | } 42 | } 43 | 44 | /** 45 | * Push a watcher into the watcher queue. 46 | * Jobs with duplicate IDs will be skipped unless it's 47 | * pushed when the queue is being flushed. 48 | * 49 | * @param {Watcher} watcher 50 | * properties: 51 | * - {number} id 52 | * - {function} run 53 | */ 54 | 55 | export default function batch (watcher) { 56 | const id = watcher.id 57 | if (has[id] == null) { 58 | has[id] = queue.length 59 | queue.push(watcher) 60 | // queue the flush 61 | if (!waiting) { 62 | waiting = true 63 | nextTick(flushBatcherQueue) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | export const OBSERVE_NAME = '__s_o__' 2 | export const WATCHERS_PROPERTY_NAME = '__watchers__' 3 | export const DATA_PROPTERTY_NAME = '__data__' 4 | 5 | export const DEBUGGING = typeof process !== 'undefined' 6 | && process.env.NODE_ENV !== 'production' 7 | -------------------------------------------------------------------------------- /src/dep.js: -------------------------------------------------------------------------------- 1 | let uid = 0 2 | 3 | /** 4 | * A dep is an observable that can have multiple 5 | * watcher subscribing to it. 6 | */ 7 | 8 | export default class Dep { 9 | // the current target watcher being evaluated. 10 | // this is globally unique because there could be only one 11 | // watcher being evaluated at any time. 12 | static target = null 13 | 14 | constructor () { 15 | this.id = uid++ 16 | this.subs = [] 17 | } 18 | 19 | /** 20 | * Add a subscriber. 21 | * 22 | * @param {Watcher} sub 23 | */ 24 | 25 | addSub (sub) { 26 | this.subs.push(sub) 27 | } 28 | 29 | /** 30 | * Remove a subscriber. 31 | * 32 | * @param {Watcher} sub 33 | */ 34 | 35 | removeSub (sub) { 36 | this.subs.$remove(sub) 37 | } 38 | 39 | /** 40 | * Add self as a dependency to the target watcher. 41 | */ 42 | 43 | depend () { 44 | Dep.target.addDep(this) 45 | } 46 | 47 | /** 48 | * Notify all subscribers of a new value. 49 | */ 50 | 51 | notify () { 52 | const subs = this.subs 53 | for (let i = 0, l = subs.length; i < l; i++) { 54 | subs[i].update() 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/expression.js: -------------------------------------------------------------------------------- 1 | import {warn} from './util' 2 | 3 | /** 4 | * Build a getter function. Requires eval. 5 | * 6 | * We isolate the try/catch so it doesn't affect the 7 | * optimization of the parse function when it is not called. 8 | * 9 | * @param {string} body 10 | * @return {function|undefined} 11 | */ 12 | 13 | function makeGetterFunction (body) { 14 | try { 15 | /* eslint-disable no-new-func */ 16 | return new Function('scope', `return ${body};`) 17 | /* eslint-enable no-new-func */ 18 | } catch (e) { 19 | warn('Invalid expression. Generated function body: ' + body) 20 | } 21 | } 22 | 23 | /** 24 | * Parse an expression to getter. 25 | * 26 | * @param {string} expression 27 | * @return {function|undefined} 28 | */ 29 | 30 | export default function parse (expression) { 31 | expression = String.prototype.trim.call(expression) 32 | return makeGetterFunction('scope.' + expression) 33 | } 34 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | observe as doObserve, 3 | defineReactive, 4 | } from './observe' 5 | import { 6 | watch as doWatch, 7 | makeComputed, 8 | } from './watcher' 9 | import { 10 | defineValue, 11 | defineAccessor, 12 | noop, 13 | isFunction, 14 | everyEntries, 15 | } from './util' 16 | import { 17 | WATCHERS_PROPERTY_NAME, 18 | DATA_PROPTERTY_NAME, 19 | } from './constants' 20 | 21 | Object.defineProperties(observe, { 22 | 'react': {value: react}, 23 | 'compute': {value: compute}, 24 | 'watch': {value: watch}, 25 | 'default': {value: watch, writable: true}, // Only could be react, compute or watch 26 | 'deep': {value: false, writable: true}, 27 | 'lazy': {value: false, writable: true}, 28 | 'sync': {value: false, writable: true}, 29 | }) 30 | 31 | /** 32 | * observe 33 | * 34 | * @public 35 | * @param {Object} target 36 | * @param {*} [expression] 37 | * @param {*} [func] 38 | * @param {*} [options] 39 | * @return {function} observe 40 | */ 41 | 42 | export default function observe (target, expression, func, options) { 43 | ensure(target) 44 | return observe.default(target, expression, func, options) 45 | } 46 | 47 | /** 48 | * React options 49 | * 50 | * @param {Object} options 51 | * @param {Object} [target] 52 | * @return {function} observe 53 | */ 54 | 55 | function react (options, target) { 56 | if (target) { 57 | ensure(target) 58 | } else { 59 | target = {} 60 | init(target) 61 | } 62 | options.methods && carryMethods(target, options.methods) 63 | options.data && reactProperties(target, options.data) 64 | options.computed && computeProperties(target, options.computed) 65 | options.watchers && watchProperties(target, options.watchers) 66 | return target 67 | } 68 | 69 | /** 70 | * Compute property 71 | * 72 | * @param {Object} target 73 | * @param {string} name 74 | * @param {function|Object} getterOrAccessor 75 | * - function getter 76 | * - Object accessor 77 | * - function [get] - getter 78 | * - function [set] - setter 79 | * - boolean [cache] 80 | * @param {boolean} [cache] 81 | */ 82 | 83 | function compute (target, name, getterOrAccessor, cache) { 84 | ensure(target) 85 | let getter, setter 86 | if (isFunction(getterOrAccessor)) { 87 | getter = cache !== false 88 | ? makeComputed(target, getterOrAccessor) 89 | : getterOrAccessor.bind(this) 90 | setter = noop 91 | } else { 92 | getter = getterOrAccessor.get 93 | ? getterOrAccessor.cache !== false || cache !== false 94 | ? makeComputed(target, getterOrAccessor.get) 95 | : getterOrAccessor.get.bind(this) 96 | : noop 97 | setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop 98 | } 99 | defineAccessor(target, name, getter, setter) 100 | } 101 | 102 | /** 103 | * Watch property 104 | * 105 | * @param {Object} target 106 | * @param {string|function} expressionOrFunction 107 | * @param {function} callback 108 | * @param {Object} [options] 109 | * - {boolean} deep 110 | * - {boolean} sync 111 | * - {boolean} lazy 112 | * @return {Watcher} 113 | */ 114 | 115 | function watch (target, expressionOrFunction, callback, options = observe) { 116 | ensure(target) 117 | return doWatch(target, expressionOrFunction, callback, options) 118 | } 119 | 120 | /** 121 | * @param {Object} target 122 | */ 123 | 124 | function init (target) { 125 | defineValue(target, WATCHERS_PROPERTY_NAME, [], false) 126 | defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false) 127 | doObserve(target[DATA_PROPTERTY_NAME]) 128 | reactSelfProperties(target) 129 | } 130 | 131 | function ensure (target) { 132 | if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) { 133 | init(target) 134 | } 135 | } 136 | 137 | /** 138 | * @param {Object} target 139 | * @param {Object} methods 140 | */ 141 | 142 | function carryMethods (target, methods) { 143 | everyEntries(methods, (name, method) => { 144 | target[name] = method.bind(target) 145 | }) 146 | } 147 | 148 | /** 149 | * @param {Object} target 150 | * @param {string} key 151 | * @param {*} value 152 | */ 153 | 154 | function reactProperty (target, key, value) { 155 | target[DATA_PROPTERTY_NAME][key] = value 156 | defineReactive(target[DATA_PROPTERTY_NAME], key, value) 157 | proxy(target, key) 158 | } 159 | 160 | /** 161 | * @param {Object} target 162 | * @param {Object} properties 163 | */ 164 | 165 | function reactProperties (target, properties) { 166 | everyEntries(properties, (key, value) => reactProperty(target, key, value)) 167 | } 168 | 169 | /** 170 | * @param {Object} target 171 | */ 172 | 173 | function reactSelfProperties (target) { 174 | everyEntries(target, (key, value) => { 175 | !isFunction(value) && reactProperty(target, key, value) 176 | }) 177 | } 178 | 179 | /** 180 | * @param {Object} target 181 | * @param {Object} properties 182 | */ 183 | 184 | function computeProperties (target, properties) { 185 | everyEntries(properties, (key, value) => compute(target, key, value)) 186 | } 187 | 188 | /** 189 | * @param {Object} target 190 | * @param {Object} properties 191 | */ 192 | 193 | function watchProperties (target, properties) { 194 | everyEntries(properties, (expression, functionOrOption) => { 195 | if (isFunction(functionOrOption)) { 196 | watch(target, expression, functionOrOption) 197 | } else { 198 | watch(target, expression, functionOrOption.watcher, functionOrOption) 199 | } 200 | }) 201 | } 202 | 203 | /** 204 | * @param {Object} target 205 | * @param {string} key 206 | */ 207 | 208 | function proxy (target, key) { 209 | function getter () { 210 | return target[DATA_PROPTERTY_NAME][key] 211 | } 212 | function setter (value) { 213 | target[DATA_PROPTERTY_NAME][key] = value 214 | } 215 | defineAccessor(target, key, getter, setter) 216 | } 217 | -------------------------------------------------------------------------------- /src/observe.js: -------------------------------------------------------------------------------- 1 | import Dep from './dep' 2 | import amendArray from './array' 3 | import { 4 | defineValue, 5 | defineAccessor, 6 | isArray, 7 | isPlainObject, 8 | everyEntries, 9 | } from './util' 10 | import {OBSERVE_NAME} from './constants' 11 | 12 | /** 13 | * Observer class that are attached to each observed 14 | * object. Once attached, the observer converts target 15 | * object's property keys into getter/setters that 16 | * collect dependencies and dispatches updates. 17 | * 18 | * @class 19 | * @param {Array|Object} value 20 | */ 21 | 22 | class Observer { 23 | constructor (value) { 24 | this.value = value 25 | this.dep = new Dep() 26 | defineValue(value, OBSERVE_NAME, this) 27 | if (isArray(value)) { 28 | amendArray(value) 29 | this.observeArray(value) 30 | } else { 31 | this.walk(value) 32 | } 33 | } 34 | 35 | /** 36 | * Walk through each property and convert them into 37 | * getter/setters. This method should only be called when 38 | * value type is Object. 39 | * 40 | * @param {Object} object 41 | */ 42 | 43 | walk (object) { 44 | everyEntries(object, (key, value) => this.convert(key, value)) 45 | } 46 | 47 | /** 48 | * Observe a list of Array items. 49 | * 50 | * @param {Array} items 51 | */ 52 | 53 | observeArray (items) { 54 | for (let i = 0, l = items.length; i < l; i++) { 55 | observe(items[i]) 56 | } 57 | } 58 | 59 | /** 60 | * Convert a property into getter/setter so we can emit 61 | * the events when the property is accessed/changed. 62 | * 63 | * @param {string} key 64 | * @param {*} value 65 | */ 66 | 67 | convert (key, value) { 68 | defineReactive(this.value, key, value) 69 | } 70 | } 71 | 72 | /** 73 | * Attempt to create an observer instance for a value, 74 | * returns the new observer if successfully observed, 75 | * or the existing observer if the value already has one. 76 | * 77 | * @param {*} value 78 | * @return {Observer|undefined} 79 | */ 80 | 81 | export function observe (value) { 82 | if (!value || typeof value !== 'object') return 83 | let observer 84 | if ( 85 | Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME) 86 | && value[OBSERVE_NAME] instanceof Observer 87 | ) { 88 | observer = value[OBSERVE_NAME] 89 | } else if ( 90 | (isArray(value) || isPlainObject(value)) 91 | && Object.isExtensible(value) 92 | ) { 93 | observer = new Observer(value) 94 | } 95 | return observer 96 | } 97 | 98 | /** 99 | * Define a reactive property on an Object. 100 | * 101 | * @param {Object} object 102 | * @param {string} key 103 | * @param {*} value 104 | */ 105 | 106 | export function defineReactive (object, key, value) { 107 | const dep = new Dep() 108 | 109 | const desc = Object.getOwnPropertyDescriptor(object, key) 110 | if (desc && desc.configurable === false) return 111 | 112 | // cater for pre-defined getter/setters 113 | const getter = desc && desc.get 114 | const setter = desc && desc.set 115 | 116 | let childOb = observe(value) 117 | 118 | function reactiveGetter () { 119 | const currentValue = getter ? getter.call(object) : value 120 | if (Dep.target) { 121 | dep.depend() 122 | if (childOb) { 123 | childOb.dep.depend() 124 | } 125 | if (isArray(currentValue)) { 126 | for (let i = 0, l = currentValue.length, e; i < l; i++) { 127 | e = currentValue[i] 128 | e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend() 129 | } 130 | } 131 | } 132 | return currentValue 133 | } 134 | function reactiveSetter (newValue) { 135 | const oldValue = getter ? getter.call(object) : value 136 | if (newValue === oldValue) return 137 | if (setter) { 138 | setter.call(object, newValue) 139 | } else { 140 | value = newValue 141 | } 142 | childOb = observe(newValue) 143 | dep.notify() 144 | } 145 | defineAccessor(object, key, reactiveGetter, reactiveSetter) 146 | } 147 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | import {DEBUGGING} from './constants' 2 | 3 | /** 4 | * Define property with value. 5 | * 6 | * @param {Object} object 7 | * @param {string} property 8 | * @param {*} value 9 | * @param {boolean} [enumerable] 10 | */ 11 | 12 | export function defineValue (object, property, value, enumerable) { 13 | Object.defineProperty(object, property, { 14 | value, 15 | enumerable: !!enumerable, 16 | writable: true, 17 | configurable: true, 18 | }) 19 | } 20 | 21 | /** 22 | * Define property with getter and setter. 23 | * 24 | * @param {Object} object 25 | * @param {string} property 26 | * @param {function} getter 27 | * @param {function} setter 28 | */ 29 | 30 | export function defineAccessor (object, property, getter, setter) { 31 | Object.defineProperty(object, property, { 32 | get: getter, 33 | set: setter, 34 | enumerable: true, 35 | configurable: true, 36 | }) 37 | } 38 | 39 | /** 40 | * Array type check. 41 | * 42 | * @return {boolean} 43 | */ 44 | 45 | export const isArray = Array.isArray 46 | 47 | /** 48 | * Strict object type check. Only returns true 49 | * for plain JavaScript objects. 50 | * 51 | * @param {*} Object 52 | * @return {boolean} 53 | */ 54 | 55 | const toString = Object.prototype.toString 56 | const OBJECT_STRING = '[object Object]' 57 | export function isPlainObject (object) { 58 | return toString.call(object) === OBJECT_STRING 59 | } 60 | 61 | /** 62 | * Quick object check - this is primarily used to tell 63 | * Objects from primitive values when we know the value 64 | * is a JSON-compliant type. 65 | * 66 | * @param {*} object 67 | * @return {boolean} 68 | */ 69 | 70 | export function isObject (object) { 71 | return object !== null && typeof object === 'object' 72 | } 73 | 74 | /** 75 | * Function type check 76 | * 77 | * @param {*} func 78 | * @param {boolean} 79 | */ 80 | 81 | export function isFunction (func) { 82 | return typeof func === 'function' 83 | } 84 | 85 | /** 86 | * Iterate object 87 | * 88 | * @param {Object} object 89 | * @param {function} callback 90 | */ 91 | 92 | export function everyEntries (object, callback) { 93 | const keys = Object.keys(object) 94 | for (let i = 0, l = keys.length; i < l; i++) { 95 | callback(keys[i], object[keys[i]]) 96 | } 97 | } 98 | 99 | /** 100 | * noop is function which is nothing to do. 101 | */ 102 | 103 | export function noop () {} 104 | 105 | /** 106 | * @param {string} string 107 | */ 108 | 109 | export const warn = typeof DEBUGGING !== 'undefined' 110 | && DEBUGGING 111 | && typeof console !== 'undefined' 112 | && console 113 | && isFunction(console.warn) 114 | ? console.warn 115 | : noop 116 | 117 | export let _Set 118 | if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) { 119 | // use native Set when available. 120 | _Set = Set 121 | } else { 122 | // a non-standard Set polyfill that only works with primitive keys. 123 | _Set = function () { 124 | this.set = Object.create(null) 125 | } 126 | _Set.prototype.has = function (key) { 127 | return this.set[key] !== undefined 128 | } 129 | _Set.prototype.add = function (key) { 130 | this.set[key] = 1 131 | } 132 | _Set.prototype.clear = function () { 133 | this.set = Object.create(null) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/watcher.js: -------------------------------------------------------------------------------- 1 | import observe from './index' 2 | import Dep from './dep' 3 | import parseExpression from './expression' 4 | import batch from './batcher' 5 | import { 6 | isArray, 7 | isObject, 8 | isFunction, 9 | _Set as Set, 10 | } from './util' 11 | import {WATCHERS_PROPERTY_NAME} from './constants' 12 | 13 | let uid = 0 14 | 15 | class Watcher { 16 | /** 17 | * A watcher parses an expression, collects dependencies, 18 | * and fires callback when the expression value changes. 19 | * 20 | * @param {Object} owner 21 | * @param {string|function} getter 22 | * @param {function} callback 23 | * @param {Object} options 24 | * - {boolean} deep 25 | * - {boolean} sync 26 | * - {boolean} lazy 27 | * @constructor 28 | */ 29 | 30 | constructor (owner, getter, callback, options) { 31 | owner[WATCHERS_PROPERTY_NAME].push(this) 32 | this.owner = owner 33 | this.getter = getter 34 | this.callback = callback 35 | this.options = options 36 | // uid for batching 37 | this.id = ++uid 38 | this.active = true 39 | // for lazy watchers 40 | this.dirty = options.lazy 41 | this.deps = [] 42 | this.newDeps = [] 43 | this.depIds = new Set() 44 | this.newDepIds = new Set() 45 | this.value = options.lazy 46 | ? undefined 47 | : this.get() 48 | } 49 | 50 | /** 51 | * Evaluate the getter, and re-collect dependencies. 52 | */ 53 | 54 | get () { 55 | this.beforeGet() 56 | const scope = this.owner 57 | const value = this.getter.call(scope, scope) 58 | if (this.options.deep) { 59 | traverse(value) 60 | } 61 | this.afterGet() 62 | return value 63 | } 64 | 65 | /** 66 | * Prepare for dependency collection. 67 | */ 68 | 69 | beforeGet () { 70 | Dep.target = this 71 | } 72 | 73 | /** 74 | * Add a dependency to this directive. 75 | * 76 | * @param {Dep} dep 77 | */ 78 | 79 | addDep (dep) { 80 | const id = dep.id 81 | if (!this.newDepIds.has(id)) { 82 | this.newDepIds.add(id) 83 | this.newDeps.push(dep) 84 | if (!this.depIds.has(id)) { 85 | dep.addSub(this) 86 | } 87 | } 88 | } 89 | 90 | /** 91 | * Clean up for dependency collection. 92 | */ 93 | 94 | afterGet () { 95 | Dep.target = null 96 | let i = this.deps.length 97 | while (i--) { 98 | const dep = this.deps[i] 99 | if (!this.newDepIds.has(dep.id)) { 100 | dep.removeSub(this) 101 | } 102 | } 103 | let tmp = this.depIds 104 | this.depIds = this.newDepIds 105 | this.newDepIds = tmp 106 | this.newDepIds.clear() 107 | tmp = this.deps 108 | this.deps = this.newDeps 109 | this.newDeps = tmp 110 | this.newDeps.length = 0 111 | } 112 | 113 | /** 114 | * Will be called when a dependency changes. 115 | */ 116 | 117 | update () { 118 | if (this.options.lazy) { 119 | this.dirty = true 120 | } else if (this.options.sync) { 121 | this.run() 122 | } else { 123 | batch(this) 124 | } 125 | } 126 | 127 | /** 128 | * Will be called by the batcher. 129 | */ 130 | 131 | run () { 132 | if (this.active) { 133 | const value = this.get() 134 | if ( 135 | value !== this.value 136 | // Deep watchers and watchers on Object/Arrays should fire even when 137 | // the value is the same, because the value may have mutated; 138 | || ((isObject(value) || this.options.deep)) 139 | ) { 140 | const oldValue = this.value 141 | this.value = value 142 | this.callback.call(this.owner, value, oldValue) 143 | } 144 | } 145 | } 146 | 147 | /** 148 | * Evaluate the value of the watcher. 149 | * This only gets called for lazy watchers. 150 | */ 151 | 152 | evaluate () { 153 | // avoid overwriting another watcher that is being collected. 154 | const current = Dep.target 155 | this.value = this.get() 156 | this.dirty = false 157 | Dep.target = current 158 | } 159 | 160 | /** 161 | * Depend on all deps collected by this watcher. 162 | */ 163 | 164 | depend () { 165 | let i = this.deps.length 166 | while (i--) { 167 | this.deps[i].depend() 168 | } 169 | } 170 | 171 | /** 172 | * Remove self from all dependencies' subcriber list. 173 | */ 174 | 175 | teardown () { 176 | if (this.active) { 177 | let i = this.deps.length 178 | while (i--) { 179 | this.deps[i].removeSub(this) 180 | } 181 | this.active = false 182 | this.owner = this.callback = this.value = null 183 | } 184 | } 185 | } 186 | 187 | /** 188 | * Recrusively traverse an Object to evoke all converted 189 | * getters, so that every nested property inside the Object 190 | * is collected as a "deep" dependency. 191 | * 192 | * @param {*} value 193 | */ 194 | 195 | function traverse (value) { 196 | let i, keys 197 | if (isArray(value)) { 198 | i = value.length 199 | while (i--) traverse(value[i]) 200 | } else if (isObject(value)) { 201 | keys = Object.keys(value) 202 | i = keys.length 203 | while (i--) traverse(value[keys[i]]) 204 | } 205 | } 206 | 207 | /** 208 | * Create an watcher instance, returns the new watcher. 209 | * 210 | * @param {Object} owner 211 | * @param {string|function} expressionOrFunction 212 | * @param {function} callback 213 | * @param {Object} options 214 | * - {boolean} deep 215 | * - {boolean} sync 216 | * - {boolean} lazy 217 | * @return {Watcher} 218 | */ 219 | 220 | export function watch (owner, expressionOrFunction, callback, options) { 221 | // parse expression for getter 222 | const getter = isFunction(expressionOrFunction) 223 | ? expressionOrFunction 224 | : parseExpression(expressionOrFunction) 225 | return new Watcher(owner, getter, callback, options) 226 | } 227 | 228 | /** 229 | * Make a computed getter, which can collect dependencies. 230 | * 231 | * @param {Object} owner 232 | * @param {function} getter 233 | */ 234 | 235 | export function makeComputed (owner, getter) { 236 | const watcher = new Watcher(owner, getter, null, { 237 | deep: observe.deep, 238 | lazy: true, 239 | sync: observe.sync, 240 | }) 241 | return function computedGetter () { 242 | if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) { 243 | watcher.options.lazy = false 244 | watcher.callback = function () { 245 | const deps = watcher.deps 246 | for (let i = 0, l = deps.length; i < l; i++) { 247 | deps[i].notify() 248 | } 249 | } 250 | } 251 | if (watcher.dirty) { 252 | watcher.evaluate() 253 | } 254 | if (Dep.target) { 255 | watcher.depend() 256 | } 257 | return watcher.value 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('chai').assert 4 | const observe = require('../dist/smart-observe.js') 5 | 6 | const equal = assert.equal 7 | 8 | /* global describe, it */ 9 | describe('smart-observe', function () { 10 | describe('#watch()', function () { 11 | const target = {a: 1, b: []} 12 | it('target.a\'s old value should equal 1, new value should equal 3, "this" should bound to target', done => { 13 | observe(target, 'a', function (newValue, oldValue) { 14 | equal(newValue, 3) 15 | equal(oldValue, 1) 16 | equal(newValue, this.a) 17 | done() 18 | }) 19 | target.a = 3 20 | }) 21 | it('target.b\'s new value should equal [1], "this" should bound to target', done => { 22 | observe(target, 'b', function (newValue) { 23 | equal(JSON.stringify(newValue), '[1]') 24 | equal(newValue, this.b) 25 | done() 26 | }) 27 | target.b.push(1) 28 | }) 29 | }) 30 | describe('#compute()', function () { 31 | class Claz { 32 | constructor () { 33 | this.a = 1 34 | observe.compute(this, 'b', () => this.double(this.a)) 35 | } 36 | double (num) { 37 | return num * 2 38 | } 39 | } 40 | const target = new Claz() 41 | target.a = 3 42 | it('target.b should equal 6', function (done) { 43 | equal(target.b, 6) 44 | done() 45 | }) 46 | }) 47 | describe('#react()', function () { 48 | it('area should equal 28.274333882308138', function (done) { 49 | const target = observe.react({ 50 | data: { 51 | PI: Math.PI, 52 | radius: 1, 53 | }, 54 | computed: { 55 | 'area': function () { 56 | return this.PI * this.square(this.radius) 57 | }, 58 | }, 59 | watchers: { 60 | 'area': function (newValue, oldValue) { 61 | equal(newValue, 28.274333882308138) 62 | done() 63 | }, 64 | }, 65 | methods: { 66 | square (num) { 67 | return num * num 68 | }, 69 | }, 70 | }) 71 | target.radius = 3 72 | }) 73 | }) 74 | }) 75 | --------------------------------------------------------------------------------