├── .babelrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── dist └── vue-testing.js ├── package.json ├── src └── index.js └── webpack ├── webpack-bundle.config.js ├── webpack-test.config.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["transform-object-rest-spread"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | yarn.lock 4 | 5 | test/ 6 | karma.conf.js 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build/ 2 | src/ 3 | test/ 4 | webpack/ 5 | 6 | .babelrc 7 | browser.html 8 | index.html 9 | karma.conf.js 10 | yarn.lock 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Naufal Rabbani 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.md: -------------------------------------------------------------------------------- 1 | # Vue Testing 2 | 3 | Let's make Vue Testing And [Mocking](https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html) Become Easier And Much Fun. 4 | 5 | ## Installation 6 | ```bash 7 | npm install vue-testing inject-loader --save-dev 8 | ``` 9 | 10 | ## Motivation 11 | If you're testing without [```vue-testing```](https://github.com/BosNaufal/vue-testing) you'll realize that you have a long boilerplate code to mock up your component. Let me show you how it looks. It's taken from [https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html](https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html) 12 | 13 | ```html 14 | 15 | 18 | 19 | 31 | ``` 32 | 33 | ```javascript 34 | // example.spec.js 35 | 36 | // Import the component and make the injection preparation 37 | const ExampleInjector = require('!!vue?inject!./example.vue') 38 | 39 | // Inject and Mock External Resource 40 | const ExampleWithMocks = ExampleInjector({ 41 | // mock it 42 | '../service': { 43 | msg: 'Hello from a mocked service!' 44 | } 45 | }) 46 | 47 | it('should render', () => { 48 | // Render the component manually 49 | const vm = new Vue({ 50 | template: '
', 51 | components: { 52 | 'test': ExampleWithMocks 53 | } 54 | }).$mount() 55 | expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!') 56 | }) 57 | ``` 58 | 59 | ### Magic Vue Properties 60 | Probably, you'll not get frustated with that code. Cause it's simple. until your component uses vue properties that magically injected by some plugin. For example ```vue-router``` injects ```this.$router``` and ```this.$route``` Or ```vuex``` injects ```this.$store```. It will throw error variable undefined since we not render the whole app. So, How do you handle it without touching your component code? It needs some effort. 61 | 62 | ```html 63 | 64 | 67 | 68 | 85 | ``` 86 | 87 | ```javascript 88 | // example.spec.js 89 | 90 | // Import the component and make the injection preparation 91 | const ExampleInjector = require('!!vue?inject!./example.vue') 92 | 93 | // Inject and Mock External Resource 94 | const ExampleWithMocks = ExampleInjector({ 95 | // mock it 96 | '../service': { 97 | msg: 'Hello from a mocked service!' 98 | } 99 | }) 100 | 101 | // You can inject magic properties this way 102 | ExampleWithMocks.beforeCreate = function () { 103 | this.$route = { params: {} } 104 | this.$router = { push: () => {} } 105 | } 106 | 107 | it('should render', () => { 108 | // Render the component manually 109 | const vm = new Vue({ 110 | template: '
', 111 | components: { 112 | 'test': ExampleWithMocks 113 | } 114 | }).$mount() 115 | 116 | expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!') 117 | }) 118 | ``` 119 | 120 | ### Vuex Helper Function 121 | Oke, let's say that you always pass the router params via props since ```vue-router@2.2.x```. But you'll still get the problem when you're using vuex helper function like ```mapActions```, ```mapStates```, ```mapGetters```. Sure, you need write more. 122 | 123 | ```html 124 | 125 | 128 | 129 | 158 | ``` 159 | 160 | ```javascript 161 | // example.spec.js 162 | 163 | // Import the component and make the injection preparation 164 | const ExampleInjector = require('!!vue?inject!./example.vue') 165 | 166 | // Inject and Mock External Resource 167 | const ExampleWithMocks = ExampleInjector({ 168 | // mock it 169 | '../service': { 170 | msg: 'Hello from a mocked service!' 171 | }, 172 | 173 | 'vuex': { 174 | mapActions: () => {} 175 | } 176 | }) 177 | 178 | // Mock The Method To Put Your Spy 179 | ExampleWithMocks.methods = { 180 | ...ExampleWithMocks.methods, 181 | test: function() { 182 | return spy 183 | } 184 | } 185 | 186 | // You can inject magic properties this way 187 | ExampleWithMocks.beforeCreate = function () { 188 | this.$route = { params: {} } 189 | this.$router = { push: () => {} } 190 | } 191 | 192 | it('should render', () => { 193 | // Render the component manually 194 | const vm = new Vue({ 195 | template: '
', 196 | components: { 197 | 'test': ExampleWithMocks 198 | } 199 | }).$mount() 200 | 201 | expect(vm.$el.querySelector('.msg').textContent).toBe('Hello from a mocked service!') 202 | }) 203 | ``` 204 | 205 | ## Let's Make It Simple! 206 | Let's make it simple with ```vue-testing```. You'll just need little effort to mock your component constructor. Take a peek. 207 | ```javascript 208 | // example.spec.js 209 | 210 | // Import Vue Testing Helpers 211 | import { mockComponent, mount } from 'vue-testing'; 212 | 213 | // Import the component and make the injection preparation 214 | const ExampleInjector = require('!!vue?inject!./example.vue') 215 | 216 | // Mock It! 217 | let Component = mockComponent(ExampleInjector, { 218 | 219 | // You can inject component properties via propsData 220 | propsData: { 221 | msg: 'hai' 222 | }, 223 | 224 | // Even You can inject the local state without breaking your beforeCreate function 225 | // It will save you from mapStates and mapGetters vuex function error in testing 226 | states: { 227 | localState: 'hello', 228 | $route: { 229 | params: {} 230 | }, 231 | $router: { 232 | push: () => {} 233 | } 234 | }, 235 | 236 | // You can inject the actions to be your local methods! 237 | // It will save you from mapActions vuex function error in testing 238 | actions: { 239 | test: () => spy 240 | }, 241 | 242 | 243 | // Default integrated with vuex-saga 244 | // It will save you from mapSagas vuex-saga function error in testing 245 | sagas: { 246 | test: () => {} 247 | }, 248 | 249 | 250 | // Mock the external module 251 | // You can just put all in one scope 252 | '../service': { 253 | msg: 'Hello from a mocked service!' 254 | }, 255 | 'jquery': () => {} 256 | 'external-module': {} 257 | }) 258 | 259 | 260 | describe('ExampleComponent', function () { 261 | 262 | let vm; 263 | beforeEach(function () { 264 | // Mount it! 265 | // Mount it in every test scope. So you'll get fresh component 266 | vm = mount(Component) 267 | }) 268 | 269 | // Focus On Your Test! 270 | it('Some Test', function () { 271 | const actual = vm.$el.querySelector('.msg').textContent 272 | const expected = 'Hello from a mocked service!' 273 | expect(actual).toBe(expected) 274 | }) 275 | 276 | }) 277 | ``` 278 | 279 | ## Have You Tested Your Components? You Should Be~ 280 | 281 | ## Thank You for Making this useful~ 282 | 283 | ## Let's talk about some projects with me 284 | Just Contact Me At: 285 | - Email: [bosnaufalemail@gmail.com](mailto:bosnaufalemail@gmail.com) 286 | - Skype Id: bosnaufal254 287 | - twitter: [@BosNaufal](https://twitter.com/BosNaufal) 288 | 289 | 290 | ## License 291 | [MIT](http://opensource.org/licenses/MIT) 292 | Copyright (c) Naufal Rabbani 293 | -------------------------------------------------------------------------------- /dist/vue-testing.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) Naufal Rabbani (http://github.com/BosNaufal) 3 | * Licensed Under MIT (http://opensource.org/licenses/MIT) 4 | * 5 | * Vue Testing @ Version 0.0.2 6 | * 7 | */ 8 | (function webpackUniversalModuleDefinition(root, factory) { 9 | if(typeof exports === 'object' && typeof module === 'object') 10 | module.exports = factory(); 11 | else if(typeof define === 'function' && define.amd) 12 | define([], factory); 13 | else if(typeof exports === 'object') 14 | exports["VueTesting"] = factory(); 15 | else 16 | root["VueTesting"] = factory(); 17 | })(this, function() { 18 | return /******/ (function(modules) { // webpackBootstrap 19 | /******/ // The module cache 20 | /******/ var installedModules = {}; 21 | 22 | /******/ // The require function 23 | /******/ function __webpack_require__(moduleId) { 24 | 25 | /******/ // Check if module is in cache 26 | /******/ if(installedModules[moduleId]) 27 | /******/ return installedModules[moduleId].exports; 28 | 29 | /******/ // Create a new module (and put it into the cache) 30 | /******/ var module = installedModules[moduleId] = { 31 | /******/ exports: {}, 32 | /******/ id: moduleId, 33 | /******/ loaded: false 34 | /******/ }; 35 | 36 | /******/ // Execute the module function 37 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 38 | 39 | /******/ // Flag the module as loaded 40 | /******/ module.loaded = true; 41 | 42 | /******/ // Return the exports of the module 43 | /******/ return module.exports; 44 | /******/ } 45 | 46 | 47 | /******/ // expose the modules object (__webpack_modules__) 48 | /******/ __webpack_require__.m = modules; 49 | 50 | /******/ // expose the module cache 51 | /******/ __webpack_require__.c = installedModules; 52 | 53 | /******/ // __webpack_public_path__ 54 | /******/ __webpack_require__.p = "../dist/"; 55 | 56 | /******/ // Load entry module and return exports 57 | /******/ return __webpack_require__(0); 58 | /******/ }) 59 | /************************************************************************/ 60 | /******/ ([ 61 | /* 0 */ 62 | /***/ function(module, exports, __webpack_require__) { 63 | 64 | 'use strict'; 65 | 66 | Object.defineProperty(exports, "__esModule", { 67 | value: true 68 | }); 69 | 70 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 71 | 72 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 73 | 74 | exports.mount = mount; 75 | exports.injectState = injectState; 76 | exports.defaultInjections = defaultInjections; 77 | exports.mockComponent = mockComponent; 78 | 79 | var _vue = __webpack_require__(1); 80 | 81 | var _vue2 = _interopRequireDefault(_vue); 82 | 83 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 84 | 85 | // To Mount Component 86 | function mount(component) { 87 | var Ctor = _vue2.default.extend(component); 88 | var propsData = component.$propsDataInjection; 89 | var vm = new Ctor({ propsData: propsData }).$mount(); 90 | return vm; 91 | } 92 | 93 | // To Make State Injections 94 | function injectState(Component, injections) { 95 | var defaultValue = Component.data ? Component.data() : {}; 96 | Component.data = function () { 97 | return _extends({}, defaultValue, injections); 98 | }; 99 | return Component; 100 | } 101 | 102 | // To Make a Mock Injection for default Injections 103 | function defaultInjections(injects) { 104 | 105 | // If No Injections 106 | var injections = { 107 | 'vuex': { 108 | mapStates: function mapStates() {}, 109 | mapActions: function mapActions() {}, 110 | mapGetters: function mapGetters() {} 111 | }, 112 | 'vuex-saga': { 113 | mapSagas: function mapSagas() {} 114 | } 115 | }; 116 | 117 | if (!injects) return { injections: injections, stateInjections: {}, propsData: {} }; 118 | 119 | // If there's an injection 120 | // Destruct 121 | var internal = {}; 122 | var others = {}; 123 | var keys = Object.keys(injects); 124 | keys.forEach(function (key) { 125 | if (key !== 'states' && key !== 'actions' && key !== 'getters' && key !== 'sagas' && key !== 'propsData') { 126 | others[key] = injects[key]; 127 | } else { 128 | internal[key] = injects[key]; 129 | } 130 | }); 131 | 132 | // Vuex Injections 133 | if (internal['sagas']) injections['vuex-saga'].mapSagas = function () { 134 | return internal['sagas']; 135 | }; 136 | if (internal['actions']) injections['vuex'].mapActions = function () { 137 | return internal['actions']; 138 | }; 139 | 140 | // Others injections 141 | if ((typeof others === 'undefined' ? 'undefined' : _typeof(others)) === 'object') injections = _extends({}, injections, others); 142 | 143 | // If There's some state Injections 144 | var stateInjections = void 0; 145 | if (internal['getters'] || internal['states']) { 146 | // Combine Getters and States Injections 147 | var states = _extends({}, internal['getters'], internal['states']); 148 | 149 | // Save the state injections 150 | stateInjections = states; 151 | } 152 | 153 | return { injections: injections, stateInjections: stateInjections, propsData: internal['propsData'] }; 154 | } 155 | 156 | // Wrap it all to mock a component constructor 157 | function mockComponent(injector, injects) { 158 | var _defaultInjections = defaultInjections(injects), 159 | injections = _defaultInjections.injections, 160 | stateInjections = _defaultInjections.stateInjections, 161 | propsData = _defaultInjections.propsData; 162 | 163 | // Inject it! 164 | 165 | 166 | var Component = injector(_extends({}, injections)); 167 | 168 | // Inject States From getters And states Argumen 169 | Component = injectState(Component, stateInjections); 170 | 171 | // Inject propsData 172 | Component.$propsDataInjection = propsData; 173 | 174 | return Component; 175 | } 176 | 177 | var combine = { mockComponent: mockComponent, mount: mount }; 178 | exports.default = combine; 179 | 180 | /***/ }, 181 | /* 1 */ 182 | /***/ function(module, exports, __webpack_require__) { 183 | 184 | /* WEBPACK VAR INJECTION */(function(global) {/*! 185 | * Vue.js v2.1.10 186 | * (c) 2014-2017 Evan You 187 | * Released under the MIT License. 188 | */ 189 | 'use strict'; 190 | 191 | /* */ 192 | 193 | /** 194 | * Convert a value to a string that is actually rendered. 195 | */ 196 | function _toString (val) { 197 | return val == null 198 | ? '' 199 | : typeof val === 'object' 200 | ? JSON.stringify(val, null, 2) 201 | : String(val) 202 | } 203 | 204 | /** 205 | * Convert a input value to a number for persistence. 206 | * If the conversion fails, return original string. 207 | */ 208 | function toNumber (val) { 209 | var n = parseFloat(val); 210 | return isNaN(n) ? val : n 211 | } 212 | 213 | /** 214 | * Make a map and return a function for checking if a key 215 | * is in that map. 216 | */ 217 | function makeMap ( 218 | str, 219 | expectsLowerCase 220 | ) { 221 | var map = Object.create(null); 222 | var list = str.split(','); 223 | for (var i = 0; i < list.length; i++) { 224 | map[list[i]] = true; 225 | } 226 | return expectsLowerCase 227 | ? function (val) { return map[val.toLowerCase()]; } 228 | : function (val) { return map[val]; } 229 | } 230 | 231 | /** 232 | * Check if a tag is a built-in tag. 233 | */ 234 | var isBuiltInTag = makeMap('slot,component', true); 235 | 236 | /** 237 | * Remove an item from an array 238 | */ 239 | function remove$1 (arr, item) { 240 | if (arr.length) { 241 | var index = arr.indexOf(item); 242 | if (index > -1) { 243 | return arr.splice(index, 1) 244 | } 245 | } 246 | } 247 | 248 | /** 249 | * Check whether the object has the property. 250 | */ 251 | var hasOwnProperty = Object.prototype.hasOwnProperty; 252 | function hasOwn (obj, key) { 253 | return hasOwnProperty.call(obj, key) 254 | } 255 | 256 | /** 257 | * Check if value is primitive 258 | */ 259 | function isPrimitive (value) { 260 | return typeof value === 'string' || typeof value === 'number' 261 | } 262 | 263 | /** 264 | * Create a cached version of a pure function. 265 | */ 266 | function cached (fn) { 267 | var cache = Object.create(null); 268 | return (function cachedFn (str) { 269 | var hit = cache[str]; 270 | return hit || (cache[str] = fn(str)) 271 | }) 272 | } 273 | 274 | /** 275 | * Camelize a hyphen-delimited string. 276 | */ 277 | var camelizeRE = /-(\w)/g; 278 | var camelize = cached(function (str) { 279 | return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) 280 | }); 281 | 282 | /** 283 | * Capitalize a string. 284 | */ 285 | var capitalize = cached(function (str) { 286 | return str.charAt(0).toUpperCase() + str.slice(1) 287 | }); 288 | 289 | /** 290 | * Hyphenate a camelCase string. 291 | */ 292 | var hyphenateRE = /([^-])([A-Z])/g; 293 | var hyphenate = cached(function (str) { 294 | return str 295 | .replace(hyphenateRE, '$1-$2') 296 | .replace(hyphenateRE, '$1-$2') 297 | .toLowerCase() 298 | }); 299 | 300 | /** 301 | * Simple bind, faster than native 302 | */ 303 | function bind$1 (fn, ctx) { 304 | function boundFn (a) { 305 | var l = arguments.length; 306 | return l 307 | ? l > 1 308 | ? fn.apply(ctx, arguments) 309 | : fn.call(ctx, a) 310 | : fn.call(ctx) 311 | } 312 | // record original fn length 313 | boundFn._length = fn.length; 314 | return boundFn 315 | } 316 | 317 | /** 318 | * Convert an Array-like object to a real Array. 319 | */ 320 | function toArray (list, start) { 321 | start = start || 0; 322 | var i = list.length - start; 323 | var ret = new Array(i); 324 | while (i--) { 325 | ret[i] = list[i + start]; 326 | } 327 | return ret 328 | } 329 | 330 | /** 331 | * Mix properties into target object. 332 | */ 333 | function extend (to, _from) { 334 | for (var key in _from) { 335 | to[key] = _from[key]; 336 | } 337 | return to 338 | } 339 | 340 | /** 341 | * Quick object check - this is primarily used to tell 342 | * Objects from primitive values when we know the value 343 | * is a JSON-compliant type. 344 | */ 345 | function isObject (obj) { 346 | return obj !== null && typeof obj === 'object' 347 | } 348 | 349 | /** 350 | * Strict object type check. Only returns true 351 | * for plain JavaScript objects. 352 | */ 353 | var toString = Object.prototype.toString; 354 | var OBJECT_STRING = '[object Object]'; 355 | function isPlainObject (obj) { 356 | return toString.call(obj) === OBJECT_STRING 357 | } 358 | 359 | /** 360 | * Merge an Array of Objects into a single Object. 361 | */ 362 | function toObject (arr) { 363 | var res = {}; 364 | for (var i = 0; i < arr.length; i++) { 365 | if (arr[i]) { 366 | extend(res, arr[i]); 367 | } 368 | } 369 | return res 370 | } 371 | 372 | /** 373 | * Perform no operation. 374 | */ 375 | function noop () {} 376 | 377 | /** 378 | * Always return false. 379 | */ 380 | var no = function () { return false; }; 381 | 382 | /** 383 | * Return same value 384 | */ 385 | var identity = function (_) { return _; }; 386 | 387 | /** 388 | * Generate a static keys string from compiler modules. 389 | */ 390 | function genStaticKeys (modules) { 391 | return modules.reduce(function (keys, m) { 392 | return keys.concat(m.staticKeys || []) 393 | }, []).join(',') 394 | } 395 | 396 | /** 397 | * Check if two values are loosely equal - that is, 398 | * if they are plain objects, do they have the same shape? 399 | */ 400 | function looseEqual (a, b) { 401 | var isObjectA = isObject(a); 402 | var isObjectB = isObject(b); 403 | if (isObjectA && isObjectB) { 404 | return JSON.stringify(a) === JSON.stringify(b) 405 | } else if (!isObjectA && !isObjectB) { 406 | return String(a) === String(b) 407 | } else { 408 | return false 409 | } 410 | } 411 | 412 | function looseIndexOf (arr, val) { 413 | for (var i = 0; i < arr.length; i++) { 414 | if (looseEqual(arr[i], val)) { return i } 415 | } 416 | return -1 417 | } 418 | 419 | /* */ 420 | 421 | var config = { 422 | /** 423 | * Option merge strategies (used in core/util/options) 424 | */ 425 | optionMergeStrategies: Object.create(null), 426 | 427 | /** 428 | * Whether to suppress warnings. 429 | */ 430 | silent: false, 431 | 432 | /** 433 | * Whether to enable devtools 434 | */ 435 | devtools: ("production") !== 'production', 436 | 437 | /** 438 | * Error handler for watcher errors 439 | */ 440 | errorHandler: null, 441 | 442 | /** 443 | * Ignore certain custom elements 444 | */ 445 | ignoredElements: [], 446 | 447 | /** 448 | * Custom user key aliases for v-on 449 | */ 450 | keyCodes: Object.create(null), 451 | 452 | /** 453 | * Check if a tag is reserved so that it cannot be registered as a 454 | * component. This is platform-dependent and may be overwritten. 455 | */ 456 | isReservedTag: no, 457 | 458 | /** 459 | * Check if a tag is an unknown element. 460 | * Platform-dependent. 461 | */ 462 | isUnknownElement: no, 463 | 464 | /** 465 | * Get the namespace of an element 466 | */ 467 | getTagNamespace: noop, 468 | 469 | /** 470 | * Parse the real tag name for the specific platform. 471 | */ 472 | parsePlatformTagName: identity, 473 | 474 | /** 475 | * Check if an attribute must be bound using property, e.g. value 476 | * Platform-dependent. 477 | */ 478 | mustUseProp: no, 479 | 480 | /** 481 | * List of asset types that a component can own. 482 | */ 483 | _assetTypes: [ 484 | 'component', 485 | 'directive', 486 | 'filter' 487 | ], 488 | 489 | /** 490 | * List of lifecycle hooks. 491 | */ 492 | _lifecycleHooks: [ 493 | 'beforeCreate', 494 | 'created', 495 | 'beforeMount', 496 | 'mounted', 497 | 'beforeUpdate', 498 | 'updated', 499 | 'beforeDestroy', 500 | 'destroyed', 501 | 'activated', 502 | 'deactivated' 503 | ], 504 | 505 | /** 506 | * Max circular updates allowed in a scheduler flush cycle. 507 | */ 508 | _maxUpdateCount: 100 509 | }; 510 | 511 | /* */ 512 | 513 | /** 514 | * Check if a string starts with $ or _ 515 | */ 516 | function isReserved (str) { 517 | var c = (str + '').charCodeAt(0); 518 | return c === 0x24 || c === 0x5F 519 | } 520 | 521 | /** 522 | * Define a property. 523 | */ 524 | function def (obj, key, val, enumerable) { 525 | Object.defineProperty(obj, key, { 526 | value: val, 527 | enumerable: !!enumerable, 528 | writable: true, 529 | configurable: true 530 | }); 531 | } 532 | 533 | /** 534 | * Parse simple path. 535 | */ 536 | var bailRE = /[^\w.$]/; 537 | function parsePath (path) { 538 | if (bailRE.test(path)) { 539 | return 540 | } else { 541 | var segments = path.split('.'); 542 | return function (obj) { 543 | for (var i = 0; i < segments.length; i++) { 544 | if (!obj) { return } 545 | obj = obj[segments[i]]; 546 | } 547 | return obj 548 | } 549 | } 550 | } 551 | 552 | /* */ 553 | /* globals MutationObserver */ 554 | 555 | // can we use __proto__? 556 | var hasProto = '__proto__' in {}; 557 | 558 | // Browser environment sniffing 559 | var inBrowser = typeof window !== 'undefined'; 560 | var UA = inBrowser && window.navigator.userAgent.toLowerCase(); 561 | var isIE = UA && /msie|trident/.test(UA); 562 | var isIE9 = UA && UA.indexOf('msie 9.0') > 0; 563 | var isEdge = UA && UA.indexOf('edge/') > 0; 564 | var isAndroid = UA && UA.indexOf('android') > 0; 565 | var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); 566 | 567 | // this needs to be lazy-evaled because vue may be required before 568 | // vue-server-renderer can set VUE_ENV 569 | var _isServer; 570 | var isServerRendering = function () { 571 | if (_isServer === undefined) { 572 | /* istanbul ignore if */ 573 | if (!inBrowser && typeof global !== 'undefined') { 574 | // detect presence of vue-server-renderer and avoid 575 | // Webpack shimming the process 576 | _isServer = global['process'].env.VUE_ENV === 'server'; 577 | } else { 578 | _isServer = false; 579 | } 580 | } 581 | return _isServer 582 | }; 583 | 584 | // detect devtools 585 | var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; 586 | 587 | /* istanbul ignore next */ 588 | function isNative (Ctor) { 589 | return /native code/.test(Ctor.toString()) 590 | } 591 | 592 | /** 593 | * Defer a task to execute it asynchronously. 594 | */ 595 | var nextTick = (function () { 596 | var callbacks = []; 597 | var pending = false; 598 | var timerFunc; 599 | 600 | function nextTickHandler () { 601 | pending = false; 602 | var copies = callbacks.slice(0); 603 | callbacks.length = 0; 604 | for (var i = 0; i < copies.length; i++) { 605 | copies[i](); 606 | } 607 | } 608 | 609 | // the nextTick behavior leverages the microtask queue, which can be accessed 610 | // via either native Promise.then or MutationObserver. 611 | // MutationObserver has wider support, however it is seriously bugged in 612 | // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It 613 | // completely stops working after triggering a few times... so, if native 614 | // Promise is available, we will use it: 615 | /* istanbul ignore if */ 616 | if (typeof Promise !== 'undefined' && isNative(Promise)) { 617 | var p = Promise.resolve(); 618 | var logError = function (err) { console.error(err); }; 619 | timerFunc = function () { 620 | p.then(nextTickHandler).catch(logError); 621 | // in problematic UIWebViews, Promise.then doesn't completely break, but 622 | // it can get stuck in a weird state where callbacks are pushed into the 623 | // microtask queue but the queue isn't being flushed, until the browser 624 | // needs to do some other work, e.g. handle a timer. Therefore we can 625 | // "force" the microtask queue to be flushed by adding an empty timer. 626 | if (isIOS) { setTimeout(noop); } 627 | }; 628 | } else if (typeof MutationObserver !== 'undefined' && ( 629 | isNative(MutationObserver) || 630 | // PhantomJS and iOS 7.x 631 | MutationObserver.toString() === '[object MutationObserverConstructor]' 632 | )) { 633 | // use MutationObserver where native Promise is not available, 634 | // e.g. PhantomJS IE11, iOS7, Android 4.4 635 | var counter = 1; 636 | var observer = new MutationObserver(nextTickHandler); 637 | var textNode = document.createTextNode(String(counter)); 638 | observer.observe(textNode, { 639 | characterData: true 640 | }); 641 | timerFunc = function () { 642 | counter = (counter + 1) % 2; 643 | textNode.data = String(counter); 644 | }; 645 | } else { 646 | // fallback to setTimeout 647 | /* istanbul ignore next */ 648 | timerFunc = function () { 649 | setTimeout(nextTickHandler, 0); 650 | }; 651 | } 652 | 653 | return function queueNextTick (cb, ctx) { 654 | var _resolve; 655 | callbacks.push(function () { 656 | if (cb) { cb.call(ctx); } 657 | if (_resolve) { _resolve(ctx); } 658 | }); 659 | if (!pending) { 660 | pending = true; 661 | timerFunc(); 662 | } 663 | if (!cb && typeof Promise !== 'undefined') { 664 | return new Promise(function (resolve) { 665 | _resolve = resolve; 666 | }) 667 | } 668 | } 669 | })(); 670 | 671 | var _Set; 672 | /* istanbul ignore if */ 673 | if (typeof Set !== 'undefined' && isNative(Set)) { 674 | // use native Set when available. 675 | _Set = Set; 676 | } else { 677 | // a non-standard Set polyfill that only works with primitive keys. 678 | _Set = (function () { 679 | function Set () { 680 | this.set = Object.create(null); 681 | } 682 | Set.prototype.has = function has (key) { 683 | return this.set[key] === true 684 | }; 685 | Set.prototype.add = function add (key) { 686 | this.set[key] = true; 687 | }; 688 | Set.prototype.clear = function clear () { 689 | this.set = Object.create(null); 690 | }; 691 | 692 | return Set; 693 | }()); 694 | } 695 | 696 | var warn = noop; 697 | var formatComponentName; 698 | 699 | if (false) { 700 | var hasConsole = typeof console !== 'undefined'; 701 | 702 | warn = function (msg, vm) { 703 | if (hasConsole && (!config.silent)) { 704 | console.error("[Vue warn]: " + msg + " " + ( 705 | vm ? formatLocation(formatComponentName(vm)) : '' 706 | )); 707 | } 708 | }; 709 | 710 | formatComponentName = function (vm) { 711 | if (vm.$root === vm) { 712 | return 'root instance' 713 | } 714 | var name = vm._isVue 715 | ? vm.$options.name || vm.$options._componentTag 716 | : vm.name; 717 | return ( 718 | (name ? ("component <" + name + ">") : "anonymous component") + 719 | (vm._isVue && vm.$options.__file ? (" at " + (vm.$options.__file)) : '') 720 | ) 721 | }; 722 | 723 | var formatLocation = function (str) { 724 | if (str === 'anonymous component') { 725 | str += " - use the \"name\" option for better debugging messages."; 726 | } 727 | return ("\n(found in " + str + ")") 728 | }; 729 | } 730 | 731 | /* */ 732 | 733 | 734 | var uid$1 = 0; 735 | 736 | /** 737 | * A dep is an observable that can have multiple 738 | * directives subscribing to it. 739 | */ 740 | var Dep = function Dep () { 741 | this.id = uid$1++; 742 | this.subs = []; 743 | }; 744 | 745 | Dep.prototype.addSub = function addSub (sub) { 746 | this.subs.push(sub); 747 | }; 748 | 749 | Dep.prototype.removeSub = function removeSub (sub) { 750 | remove$1(this.subs, sub); 751 | }; 752 | 753 | Dep.prototype.depend = function depend () { 754 | if (Dep.target) { 755 | Dep.target.addDep(this); 756 | } 757 | }; 758 | 759 | Dep.prototype.notify = function notify () { 760 | // stablize the subscriber list first 761 | var subs = this.subs.slice(); 762 | for (var i = 0, l = subs.length; i < l; i++) { 763 | subs[i].update(); 764 | } 765 | }; 766 | 767 | // the current target watcher being evaluated. 768 | // this is globally unique because there could be only one 769 | // watcher being evaluated at any time. 770 | Dep.target = null; 771 | var targetStack = []; 772 | 773 | function pushTarget (_target) { 774 | if (Dep.target) { targetStack.push(Dep.target); } 775 | Dep.target = _target; 776 | } 777 | 778 | function popTarget () { 779 | Dep.target = targetStack.pop(); 780 | } 781 | 782 | /* 783 | * not type checking this file because flow doesn't play well with 784 | * dynamically accessing methods on Array prototype 785 | */ 786 | 787 | var arrayProto = Array.prototype; 788 | var arrayMethods = Object.create(arrayProto);[ 789 | 'push', 790 | 'pop', 791 | 'shift', 792 | 'unshift', 793 | 'splice', 794 | 'sort', 795 | 'reverse' 796 | ] 797 | .forEach(function (method) { 798 | // cache original method 799 | var original = arrayProto[method]; 800 | def(arrayMethods, method, function mutator () { 801 | var arguments$1 = arguments; 802 | 803 | // avoid leaking arguments: 804 | // http://jsperf.com/closure-with-arguments 805 | var i = arguments.length; 806 | var args = new Array(i); 807 | while (i--) { 808 | args[i] = arguments$1[i]; 809 | } 810 | var result = original.apply(this, args); 811 | var ob = this.__ob__; 812 | var inserted; 813 | switch (method) { 814 | case 'push': 815 | inserted = args; 816 | break 817 | case 'unshift': 818 | inserted = args; 819 | break 820 | case 'splice': 821 | inserted = args.slice(2); 822 | break 823 | } 824 | if (inserted) { ob.observeArray(inserted); } 825 | // notify change 826 | ob.dep.notify(); 827 | return result 828 | }); 829 | }); 830 | 831 | /* */ 832 | 833 | var arrayKeys = Object.getOwnPropertyNames(arrayMethods); 834 | 835 | /** 836 | * By default, when a reactive property is set, the new value is 837 | * also converted to become reactive. However when passing down props, 838 | * we don't want to force conversion because the value may be a nested value 839 | * under a frozen data structure. Converting it would defeat the optimization. 840 | */ 841 | var observerState = { 842 | shouldConvert: true, 843 | isSettingProps: false 844 | }; 845 | 846 | /** 847 | * Observer class that are attached to each observed 848 | * object. Once attached, the observer converts target 849 | * object's property keys into getter/setters that 850 | * collect dependencies and dispatches updates. 851 | */ 852 | var Observer = function Observer (value) { 853 | this.value = value; 854 | this.dep = new Dep(); 855 | this.vmCount = 0; 856 | def(value, '__ob__', this); 857 | if (Array.isArray(value)) { 858 | var augment = hasProto 859 | ? protoAugment 860 | : copyAugment; 861 | augment(value, arrayMethods, arrayKeys); 862 | this.observeArray(value); 863 | } else { 864 | this.walk(value); 865 | } 866 | }; 867 | 868 | /** 869 | * Walk through each property and convert them into 870 | * getter/setters. This method should only be called when 871 | * value type is Object. 872 | */ 873 | Observer.prototype.walk = function walk (obj) { 874 | var keys = Object.keys(obj); 875 | for (var i = 0; i < keys.length; i++) { 876 | defineReactive$$1(obj, keys[i], obj[keys[i]]); 877 | } 878 | }; 879 | 880 | /** 881 | * Observe a list of Array items. 882 | */ 883 | Observer.prototype.observeArray = function observeArray (items) { 884 | for (var i = 0, l = items.length; i < l; i++) { 885 | observe(items[i]); 886 | } 887 | }; 888 | 889 | // helpers 890 | 891 | /** 892 | * Augment an target Object or Array by intercepting 893 | * the prototype chain using __proto__ 894 | */ 895 | function protoAugment (target, src) { 896 | /* eslint-disable no-proto */ 897 | target.__proto__ = src; 898 | /* eslint-enable no-proto */ 899 | } 900 | 901 | /** 902 | * Augment an target Object or Array by defining 903 | * hidden properties. 904 | */ 905 | /* istanbul ignore next */ 906 | function copyAugment (target, src, keys) { 907 | for (var i = 0, l = keys.length; i < l; i++) { 908 | var key = keys[i]; 909 | def(target, key, src[key]); 910 | } 911 | } 912 | 913 | /** 914 | * Attempt to create an observer instance for a value, 915 | * returns the new observer if successfully observed, 916 | * or the existing observer if the value already has one. 917 | */ 918 | function observe (value, asRootData) { 919 | if (!isObject(value)) { 920 | return 921 | } 922 | var ob; 923 | if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { 924 | ob = value.__ob__; 925 | } else if ( 926 | observerState.shouldConvert && 927 | !isServerRendering() && 928 | (Array.isArray(value) || isPlainObject(value)) && 929 | Object.isExtensible(value) && 930 | !value._isVue 931 | ) { 932 | ob = new Observer(value); 933 | } 934 | if (asRootData && ob) { 935 | ob.vmCount++; 936 | } 937 | return ob 938 | } 939 | 940 | /** 941 | * Define a reactive property on an Object. 942 | */ 943 | function defineReactive$$1 ( 944 | obj, 945 | key, 946 | val, 947 | customSetter 948 | ) { 949 | var dep = new Dep(); 950 | 951 | var property = Object.getOwnPropertyDescriptor(obj, key); 952 | if (property && property.configurable === false) { 953 | return 954 | } 955 | 956 | // cater for pre-defined getter/setters 957 | var getter = property && property.get; 958 | var setter = property && property.set; 959 | 960 | var childOb = observe(val); 961 | Object.defineProperty(obj, key, { 962 | enumerable: true, 963 | configurable: true, 964 | get: function reactiveGetter () { 965 | var value = getter ? getter.call(obj) : val; 966 | if (Dep.target) { 967 | dep.depend(); 968 | if (childOb) { 969 | childOb.dep.depend(); 970 | } 971 | if (Array.isArray(value)) { 972 | dependArray(value); 973 | } 974 | } 975 | return value 976 | }, 977 | set: function reactiveSetter (newVal) { 978 | var value = getter ? getter.call(obj) : val; 979 | /* eslint-disable no-self-compare */ 980 | if (newVal === value || (newVal !== newVal && value !== value)) { 981 | return 982 | } 983 | /* eslint-enable no-self-compare */ 984 | if (false) { 985 | customSetter(); 986 | } 987 | if (setter) { 988 | setter.call(obj, newVal); 989 | } else { 990 | val = newVal; 991 | } 992 | childOb = observe(newVal); 993 | dep.notify(); 994 | } 995 | }); 996 | } 997 | 998 | /** 999 | * Set a property on an object. Adds the new property and 1000 | * triggers change notification if the property doesn't 1001 | * already exist. 1002 | */ 1003 | function set$1 (obj, key, val) { 1004 | if (Array.isArray(obj)) { 1005 | obj.length = Math.max(obj.length, key); 1006 | obj.splice(key, 1, val); 1007 | return val 1008 | } 1009 | if (hasOwn(obj, key)) { 1010 | obj[key] = val; 1011 | return 1012 | } 1013 | var ob = obj.__ob__; 1014 | if (obj._isVue || (ob && ob.vmCount)) { 1015 | ("production") !== 'production' && warn( 1016 | 'Avoid adding reactive properties to a Vue instance or its root $data ' + 1017 | 'at runtime - declare it upfront in the data option.' 1018 | ); 1019 | return 1020 | } 1021 | if (!ob) { 1022 | obj[key] = val; 1023 | return 1024 | } 1025 | defineReactive$$1(ob.value, key, val); 1026 | ob.dep.notify(); 1027 | return val 1028 | } 1029 | 1030 | /** 1031 | * Delete a property and trigger change if necessary. 1032 | */ 1033 | function del (obj, key) { 1034 | var ob = obj.__ob__; 1035 | if (obj._isVue || (ob && ob.vmCount)) { 1036 | ("production") !== 'production' && warn( 1037 | 'Avoid deleting properties on a Vue instance or its root $data ' + 1038 | '- just set it to null.' 1039 | ); 1040 | return 1041 | } 1042 | if (!hasOwn(obj, key)) { 1043 | return 1044 | } 1045 | delete obj[key]; 1046 | if (!ob) { 1047 | return 1048 | } 1049 | ob.dep.notify(); 1050 | } 1051 | 1052 | /** 1053 | * Collect dependencies on array elements when the array is touched, since 1054 | * we cannot intercept array element access like property getters. 1055 | */ 1056 | function dependArray (value) { 1057 | for (var e = (void 0), i = 0, l = value.length; i < l; i++) { 1058 | e = value[i]; 1059 | e && e.__ob__ && e.__ob__.dep.depend(); 1060 | if (Array.isArray(e)) { 1061 | dependArray(e); 1062 | } 1063 | } 1064 | } 1065 | 1066 | /* */ 1067 | 1068 | /** 1069 | * Option overwriting strategies are functions that handle 1070 | * how to merge a parent option value and a child option 1071 | * value into the final value. 1072 | */ 1073 | var strats = config.optionMergeStrategies; 1074 | 1075 | /** 1076 | * Options with restrictions 1077 | */ 1078 | if (false) { 1079 | strats.el = strats.propsData = function (parent, child, vm, key) { 1080 | if (!vm) { 1081 | warn( 1082 | "option \"" + key + "\" can only be used during instance " + 1083 | 'creation with the `new` keyword.' 1084 | ); 1085 | } 1086 | return defaultStrat(parent, child) 1087 | }; 1088 | } 1089 | 1090 | /** 1091 | * Helper that recursively merges two data objects together. 1092 | */ 1093 | function mergeData (to, from) { 1094 | if (!from) { return to } 1095 | var key, toVal, fromVal; 1096 | var keys = Object.keys(from); 1097 | for (var i = 0; i < keys.length; i++) { 1098 | key = keys[i]; 1099 | toVal = to[key]; 1100 | fromVal = from[key]; 1101 | if (!hasOwn(to, key)) { 1102 | set$1(to, key, fromVal); 1103 | } else if (isPlainObject(toVal) && isPlainObject(fromVal)) { 1104 | mergeData(toVal, fromVal); 1105 | } 1106 | } 1107 | return to 1108 | } 1109 | 1110 | /** 1111 | * Data 1112 | */ 1113 | strats.data = function ( 1114 | parentVal, 1115 | childVal, 1116 | vm 1117 | ) { 1118 | if (!vm) { 1119 | // in a Vue.extend merge, both should be functions 1120 | if (!childVal) { 1121 | return parentVal 1122 | } 1123 | if (typeof childVal !== 'function') { 1124 | ("production") !== 'production' && warn( 1125 | 'The "data" option should be a function ' + 1126 | 'that returns a per-instance value in component ' + 1127 | 'definitions.', 1128 | vm 1129 | ); 1130 | return parentVal 1131 | } 1132 | if (!parentVal) { 1133 | return childVal 1134 | } 1135 | // when parentVal & childVal are both present, 1136 | // we need to return a function that returns the 1137 | // merged result of both functions... no need to 1138 | // check if parentVal is a function here because 1139 | // it has to be a function to pass previous merges. 1140 | return function mergedDataFn () { 1141 | return mergeData( 1142 | childVal.call(this), 1143 | parentVal.call(this) 1144 | ) 1145 | } 1146 | } else if (parentVal || childVal) { 1147 | return function mergedInstanceDataFn () { 1148 | // instance merge 1149 | var instanceData = typeof childVal === 'function' 1150 | ? childVal.call(vm) 1151 | : childVal; 1152 | var defaultData = typeof parentVal === 'function' 1153 | ? parentVal.call(vm) 1154 | : undefined; 1155 | if (instanceData) { 1156 | return mergeData(instanceData, defaultData) 1157 | } else { 1158 | return defaultData 1159 | } 1160 | } 1161 | } 1162 | }; 1163 | 1164 | /** 1165 | * Hooks and param attributes are merged as arrays. 1166 | */ 1167 | function mergeHook ( 1168 | parentVal, 1169 | childVal 1170 | ) { 1171 | return childVal 1172 | ? parentVal 1173 | ? parentVal.concat(childVal) 1174 | : Array.isArray(childVal) 1175 | ? childVal 1176 | : [childVal] 1177 | : parentVal 1178 | } 1179 | 1180 | config._lifecycleHooks.forEach(function (hook) { 1181 | strats[hook] = mergeHook; 1182 | }); 1183 | 1184 | /** 1185 | * Assets 1186 | * 1187 | * When a vm is present (instance creation), we need to do 1188 | * a three-way merge between constructor options, instance 1189 | * options and parent options. 1190 | */ 1191 | function mergeAssets (parentVal, childVal) { 1192 | var res = Object.create(parentVal || null); 1193 | return childVal 1194 | ? extend(res, childVal) 1195 | : res 1196 | } 1197 | 1198 | config._assetTypes.forEach(function (type) { 1199 | strats[type + 's'] = mergeAssets; 1200 | }); 1201 | 1202 | /** 1203 | * Watchers. 1204 | * 1205 | * Watchers hashes should not overwrite one 1206 | * another, so we merge them as arrays. 1207 | */ 1208 | strats.watch = function (parentVal, childVal) { 1209 | /* istanbul ignore if */ 1210 | if (!childVal) { return parentVal } 1211 | if (!parentVal) { return childVal } 1212 | var ret = {}; 1213 | extend(ret, parentVal); 1214 | for (var key in childVal) { 1215 | var parent = ret[key]; 1216 | var child = childVal[key]; 1217 | if (parent && !Array.isArray(parent)) { 1218 | parent = [parent]; 1219 | } 1220 | ret[key] = parent 1221 | ? parent.concat(child) 1222 | : [child]; 1223 | } 1224 | return ret 1225 | }; 1226 | 1227 | /** 1228 | * Other object hashes. 1229 | */ 1230 | strats.props = 1231 | strats.methods = 1232 | strats.computed = function (parentVal, childVal) { 1233 | if (!childVal) { return parentVal } 1234 | if (!parentVal) { return childVal } 1235 | var ret = Object.create(null); 1236 | extend(ret, parentVal); 1237 | extend(ret, childVal); 1238 | return ret 1239 | }; 1240 | 1241 | /** 1242 | * Default strategy. 1243 | */ 1244 | var defaultStrat = function (parentVal, childVal) { 1245 | return childVal === undefined 1246 | ? parentVal 1247 | : childVal 1248 | }; 1249 | 1250 | /** 1251 | * Validate component names 1252 | */ 1253 | function checkComponents (options) { 1254 | for (var key in options.components) { 1255 | var lower = key.toLowerCase(); 1256 | if (isBuiltInTag(lower) || config.isReservedTag(lower)) { 1257 | warn( 1258 | 'Do not use built-in or reserved HTML elements as component ' + 1259 | 'id: ' + key 1260 | ); 1261 | } 1262 | } 1263 | } 1264 | 1265 | /** 1266 | * Ensure all props option syntax are normalized into the 1267 | * Object-based format. 1268 | */ 1269 | function normalizeProps (options) { 1270 | var props = options.props; 1271 | if (!props) { return } 1272 | var res = {}; 1273 | var i, val, name; 1274 | if (Array.isArray(props)) { 1275 | i = props.length; 1276 | while (i--) { 1277 | val = props[i]; 1278 | if (typeof val === 'string') { 1279 | name = camelize(val); 1280 | res[name] = { type: null }; 1281 | } else if (false) { 1282 | warn('props must be strings when using array syntax.'); 1283 | } 1284 | } 1285 | } else if (isPlainObject(props)) { 1286 | for (var key in props) { 1287 | val = props[key]; 1288 | name = camelize(key); 1289 | res[name] = isPlainObject(val) 1290 | ? val 1291 | : { type: val }; 1292 | } 1293 | } 1294 | options.props = res; 1295 | } 1296 | 1297 | /** 1298 | * Normalize raw function directives into object format. 1299 | */ 1300 | function normalizeDirectives (options) { 1301 | var dirs = options.directives; 1302 | if (dirs) { 1303 | for (var key in dirs) { 1304 | var def = dirs[key]; 1305 | if (typeof def === 'function') { 1306 | dirs[key] = { bind: def, update: def }; 1307 | } 1308 | } 1309 | } 1310 | } 1311 | 1312 | /** 1313 | * Merge two option objects into a new one. 1314 | * Core utility used in both instantiation and inheritance. 1315 | */ 1316 | function mergeOptions ( 1317 | parent, 1318 | child, 1319 | vm 1320 | ) { 1321 | if (false) { 1322 | checkComponents(child); 1323 | } 1324 | normalizeProps(child); 1325 | normalizeDirectives(child); 1326 | var extendsFrom = child.extends; 1327 | if (extendsFrom) { 1328 | parent = typeof extendsFrom === 'function' 1329 | ? mergeOptions(parent, extendsFrom.options, vm) 1330 | : mergeOptions(parent, extendsFrom, vm); 1331 | } 1332 | if (child.mixins) { 1333 | for (var i = 0, l = child.mixins.length; i < l; i++) { 1334 | var mixin = child.mixins[i]; 1335 | if (mixin.prototype instanceof Vue$2) { 1336 | mixin = mixin.options; 1337 | } 1338 | parent = mergeOptions(parent, mixin, vm); 1339 | } 1340 | } 1341 | var options = {}; 1342 | var key; 1343 | for (key in parent) { 1344 | mergeField(key); 1345 | } 1346 | for (key in child) { 1347 | if (!hasOwn(parent, key)) { 1348 | mergeField(key); 1349 | } 1350 | } 1351 | function mergeField (key) { 1352 | var strat = strats[key] || defaultStrat; 1353 | options[key] = strat(parent[key], child[key], vm, key); 1354 | } 1355 | return options 1356 | } 1357 | 1358 | /** 1359 | * Resolve an asset. 1360 | * This function is used because child instances need access 1361 | * to assets defined in its ancestor chain. 1362 | */ 1363 | function resolveAsset ( 1364 | options, 1365 | type, 1366 | id, 1367 | warnMissing 1368 | ) { 1369 | /* istanbul ignore if */ 1370 | if (typeof id !== 'string') { 1371 | return 1372 | } 1373 | var assets = options[type]; 1374 | // check local registration variations first 1375 | if (hasOwn(assets, id)) { return assets[id] } 1376 | var camelizedId = camelize(id); 1377 | if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } 1378 | var PascalCaseId = capitalize(camelizedId); 1379 | if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } 1380 | // fallback to prototype chain 1381 | var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; 1382 | if (false) { 1383 | warn( 1384 | 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, 1385 | options 1386 | ); 1387 | } 1388 | return res 1389 | } 1390 | 1391 | /* */ 1392 | 1393 | function validateProp ( 1394 | key, 1395 | propOptions, 1396 | propsData, 1397 | vm 1398 | ) { 1399 | var prop = propOptions[key]; 1400 | var absent = !hasOwn(propsData, key); 1401 | var value = propsData[key]; 1402 | // handle boolean props 1403 | if (isType(Boolean, prop.type)) { 1404 | if (absent && !hasOwn(prop, 'default')) { 1405 | value = false; 1406 | } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { 1407 | value = true; 1408 | } 1409 | } 1410 | // check default value 1411 | if (value === undefined) { 1412 | value = getPropDefaultValue(vm, prop, key); 1413 | // since the default value is a fresh copy, 1414 | // make sure to observe it. 1415 | var prevShouldConvert = observerState.shouldConvert; 1416 | observerState.shouldConvert = true; 1417 | observe(value); 1418 | observerState.shouldConvert = prevShouldConvert; 1419 | } 1420 | if (false) { 1421 | assertProp(prop, key, value, vm, absent); 1422 | } 1423 | return value 1424 | } 1425 | 1426 | /** 1427 | * Get the default value of a prop. 1428 | */ 1429 | function getPropDefaultValue (vm, prop, key) { 1430 | // no default, return undefined 1431 | if (!hasOwn(prop, 'default')) { 1432 | return undefined 1433 | } 1434 | var def = prop.default; 1435 | // warn against non-factory defaults for Object & Array 1436 | if (isObject(def)) { 1437 | ("production") !== 'production' && warn( 1438 | 'Invalid default value for prop "' + key + '": ' + 1439 | 'Props with type Object/Array must use a factory function ' + 1440 | 'to return the default value.', 1441 | vm 1442 | ); 1443 | } 1444 | // the raw prop value was also undefined from previous render, 1445 | // return previous default value to avoid unnecessary watcher trigger 1446 | if (vm && vm.$options.propsData && 1447 | vm.$options.propsData[key] === undefined && 1448 | vm[key] !== undefined) { 1449 | return vm[key] 1450 | } 1451 | // call factory function for non-Function types 1452 | return typeof def === 'function' && prop.type !== Function 1453 | ? def.call(vm) 1454 | : def 1455 | } 1456 | 1457 | /** 1458 | * Assert whether a prop is valid. 1459 | */ 1460 | function assertProp ( 1461 | prop, 1462 | name, 1463 | value, 1464 | vm, 1465 | absent 1466 | ) { 1467 | if (prop.required && absent) { 1468 | warn( 1469 | 'Missing required prop: "' + name + '"', 1470 | vm 1471 | ); 1472 | return 1473 | } 1474 | if (value == null && !prop.required) { 1475 | return 1476 | } 1477 | var type = prop.type; 1478 | var valid = !type || type === true; 1479 | var expectedTypes = []; 1480 | if (type) { 1481 | if (!Array.isArray(type)) { 1482 | type = [type]; 1483 | } 1484 | for (var i = 0; i < type.length && !valid; i++) { 1485 | var assertedType = assertType(value, type[i]); 1486 | expectedTypes.push(assertedType.expectedType || ''); 1487 | valid = assertedType.valid; 1488 | } 1489 | } 1490 | if (!valid) { 1491 | warn( 1492 | 'Invalid prop: type check failed for prop "' + name + '".' + 1493 | ' Expected ' + expectedTypes.map(capitalize).join(', ') + 1494 | ', got ' + Object.prototype.toString.call(value).slice(8, -1) + '.', 1495 | vm 1496 | ); 1497 | return 1498 | } 1499 | var validator = prop.validator; 1500 | if (validator) { 1501 | if (!validator(value)) { 1502 | warn( 1503 | 'Invalid prop: custom validator check failed for prop "' + name + '".', 1504 | vm 1505 | ); 1506 | } 1507 | } 1508 | } 1509 | 1510 | /** 1511 | * Assert the type of a value 1512 | */ 1513 | function assertType (value, type) { 1514 | var valid; 1515 | var expectedType = getType(type); 1516 | if (expectedType === 'String') { 1517 | valid = typeof value === (expectedType = 'string'); 1518 | } else if (expectedType === 'Number') { 1519 | valid = typeof value === (expectedType = 'number'); 1520 | } else if (expectedType === 'Boolean') { 1521 | valid = typeof value === (expectedType = 'boolean'); 1522 | } else if (expectedType === 'Function') { 1523 | valid = typeof value === (expectedType = 'function'); 1524 | } else if (expectedType === 'Object') { 1525 | valid = isPlainObject(value); 1526 | } else if (expectedType === 'Array') { 1527 | valid = Array.isArray(value); 1528 | } else { 1529 | valid = value instanceof type; 1530 | } 1531 | return { 1532 | valid: valid, 1533 | expectedType: expectedType 1534 | } 1535 | } 1536 | 1537 | /** 1538 | * Use function string name to check built-in types, 1539 | * because a simple equality check will fail when running 1540 | * across different vms / iframes. 1541 | */ 1542 | function getType (fn) { 1543 | var match = fn && fn.toString().match(/^\s*function (\w+)/); 1544 | return match && match[1] 1545 | } 1546 | 1547 | function isType (type, fn) { 1548 | if (!Array.isArray(fn)) { 1549 | return getType(fn) === getType(type) 1550 | } 1551 | for (var i = 0, len = fn.length; i < len; i++) { 1552 | if (getType(fn[i]) === getType(type)) { 1553 | return true 1554 | } 1555 | } 1556 | /* istanbul ignore next */ 1557 | return false 1558 | } 1559 | 1560 | 1561 | 1562 | var util = Object.freeze({ 1563 | defineReactive: defineReactive$$1, 1564 | _toString: _toString, 1565 | toNumber: toNumber, 1566 | makeMap: makeMap, 1567 | isBuiltInTag: isBuiltInTag, 1568 | remove: remove$1, 1569 | hasOwn: hasOwn, 1570 | isPrimitive: isPrimitive, 1571 | cached: cached, 1572 | camelize: camelize, 1573 | capitalize: capitalize, 1574 | hyphenate: hyphenate, 1575 | bind: bind$1, 1576 | toArray: toArray, 1577 | extend: extend, 1578 | isObject: isObject, 1579 | isPlainObject: isPlainObject, 1580 | toObject: toObject, 1581 | noop: noop, 1582 | no: no, 1583 | identity: identity, 1584 | genStaticKeys: genStaticKeys, 1585 | looseEqual: looseEqual, 1586 | looseIndexOf: looseIndexOf, 1587 | isReserved: isReserved, 1588 | def: def, 1589 | parsePath: parsePath, 1590 | hasProto: hasProto, 1591 | inBrowser: inBrowser, 1592 | UA: UA, 1593 | isIE: isIE, 1594 | isIE9: isIE9, 1595 | isEdge: isEdge, 1596 | isAndroid: isAndroid, 1597 | isIOS: isIOS, 1598 | isServerRendering: isServerRendering, 1599 | devtools: devtools, 1600 | nextTick: nextTick, 1601 | get _Set () { return _Set; }, 1602 | mergeOptions: mergeOptions, 1603 | resolveAsset: resolveAsset, 1604 | get warn () { return warn; }, 1605 | get formatComponentName () { return formatComponentName; }, 1606 | validateProp: validateProp 1607 | }); 1608 | 1609 | /* not type checking this file because flow doesn't play well with Proxy */ 1610 | 1611 | var initProxy; 1612 | 1613 | if (false) { 1614 | var allowedGlobals = makeMap( 1615 | 'Infinity,undefined,NaN,isFinite,isNaN,' + 1616 | 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 1617 | 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 1618 | 'require' // for Webpack/Browserify 1619 | ); 1620 | 1621 | var warnNonPresent = function (target, key) { 1622 | warn( 1623 | "Property or method \"" + key + "\" is not defined on the instance but " + 1624 | "referenced during render. Make sure to declare reactive data " + 1625 | "properties in the data option.", 1626 | target 1627 | ); 1628 | }; 1629 | 1630 | var hasProxy = 1631 | typeof Proxy !== 'undefined' && 1632 | Proxy.toString().match(/native code/); 1633 | 1634 | if (hasProxy) { 1635 | var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta'); 1636 | config.keyCodes = new Proxy(config.keyCodes, { 1637 | set: function set (target, key, value) { 1638 | if (isBuiltInModifier(key)) { 1639 | warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); 1640 | return false 1641 | } else { 1642 | target[key] = value; 1643 | return true 1644 | } 1645 | } 1646 | }); 1647 | } 1648 | 1649 | var hasHandler = { 1650 | has: function has (target, key) { 1651 | var has = key in target; 1652 | var isAllowed = allowedGlobals(key) || key.charAt(0) === '_'; 1653 | if (!has && !isAllowed) { 1654 | warnNonPresent(target, key); 1655 | } 1656 | return has || !isAllowed 1657 | } 1658 | }; 1659 | 1660 | var getHandler = { 1661 | get: function get (target, key) { 1662 | if (typeof key === 'string' && !(key in target)) { 1663 | warnNonPresent(target, key); 1664 | } 1665 | return target[key] 1666 | } 1667 | }; 1668 | 1669 | initProxy = function initProxy (vm) { 1670 | if (hasProxy) { 1671 | // determine which proxy handler to use 1672 | var options = vm.$options; 1673 | var handlers = options.render && options.render._withStripped 1674 | ? getHandler 1675 | : hasHandler; 1676 | vm._renderProxy = new Proxy(vm, handlers); 1677 | } else { 1678 | vm._renderProxy = vm; 1679 | } 1680 | }; 1681 | } 1682 | 1683 | /* */ 1684 | 1685 | var VNode = function VNode ( 1686 | tag, 1687 | data, 1688 | children, 1689 | text, 1690 | elm, 1691 | context, 1692 | componentOptions 1693 | ) { 1694 | this.tag = tag; 1695 | this.data = data; 1696 | this.children = children; 1697 | this.text = text; 1698 | this.elm = elm; 1699 | this.ns = undefined; 1700 | this.context = context; 1701 | this.functionalContext = undefined; 1702 | this.key = data && data.key; 1703 | this.componentOptions = componentOptions; 1704 | this.componentInstance = undefined; 1705 | this.parent = undefined; 1706 | this.raw = false; 1707 | this.isStatic = false; 1708 | this.isRootInsert = true; 1709 | this.isComment = false; 1710 | this.isCloned = false; 1711 | this.isOnce = false; 1712 | }; 1713 | 1714 | var prototypeAccessors = { child: {} }; 1715 | 1716 | // DEPRECATED: alias for componentInstance for backwards compat. 1717 | /* istanbul ignore next */ 1718 | prototypeAccessors.child.get = function () { 1719 | return this.componentInstance 1720 | }; 1721 | 1722 | Object.defineProperties( VNode.prototype, prototypeAccessors ); 1723 | 1724 | var createEmptyVNode = function () { 1725 | var node = new VNode(); 1726 | node.text = ''; 1727 | node.isComment = true; 1728 | return node 1729 | }; 1730 | 1731 | function createTextVNode (val) { 1732 | return new VNode(undefined, undefined, undefined, String(val)) 1733 | } 1734 | 1735 | // optimized shallow clone 1736 | // used for static nodes and slot nodes because they may be reused across 1737 | // multiple renders, cloning them avoids errors when DOM manipulations rely 1738 | // on their elm reference. 1739 | function cloneVNode (vnode) { 1740 | var cloned = new VNode( 1741 | vnode.tag, 1742 | vnode.data, 1743 | vnode.children, 1744 | vnode.text, 1745 | vnode.elm, 1746 | vnode.context, 1747 | vnode.componentOptions 1748 | ); 1749 | cloned.ns = vnode.ns; 1750 | cloned.isStatic = vnode.isStatic; 1751 | cloned.key = vnode.key; 1752 | cloned.isCloned = true; 1753 | return cloned 1754 | } 1755 | 1756 | function cloneVNodes (vnodes) { 1757 | var res = new Array(vnodes.length); 1758 | for (var i = 0; i < vnodes.length; i++) { 1759 | res[i] = cloneVNode(vnodes[i]); 1760 | } 1761 | return res 1762 | } 1763 | 1764 | /* */ 1765 | 1766 | var hooks = { init: init, prepatch: prepatch, insert: insert, destroy: destroy$1 }; 1767 | var hooksToMerge = Object.keys(hooks); 1768 | 1769 | function createComponent ( 1770 | Ctor, 1771 | data, 1772 | context, 1773 | children, 1774 | tag 1775 | ) { 1776 | if (!Ctor) { 1777 | return 1778 | } 1779 | 1780 | var baseCtor = context.$options._base; 1781 | if (isObject(Ctor)) { 1782 | Ctor = baseCtor.extend(Ctor); 1783 | } 1784 | 1785 | if (typeof Ctor !== 'function') { 1786 | if (false) { 1787 | warn(("Invalid Component definition: " + (String(Ctor))), context); 1788 | } 1789 | return 1790 | } 1791 | 1792 | // async component 1793 | if (!Ctor.cid) { 1794 | if (Ctor.resolved) { 1795 | Ctor = Ctor.resolved; 1796 | } else { 1797 | Ctor = resolveAsyncComponent(Ctor, baseCtor, function () { 1798 | // it's ok to queue this on every render because 1799 | // $forceUpdate is buffered by the scheduler. 1800 | context.$forceUpdate(); 1801 | }); 1802 | if (!Ctor) { 1803 | // return nothing if this is indeed an async component 1804 | // wait for the callback to trigger parent update. 1805 | return 1806 | } 1807 | } 1808 | } 1809 | 1810 | // resolve constructor options in case global mixins are applied after 1811 | // component constructor creation 1812 | resolveConstructorOptions(Ctor); 1813 | 1814 | data = data || {}; 1815 | 1816 | // extract props 1817 | var propsData = extractProps(data, Ctor); 1818 | 1819 | // functional component 1820 | if (Ctor.options.functional) { 1821 | return createFunctionalComponent(Ctor, propsData, data, context, children) 1822 | } 1823 | 1824 | // extract listeners, since these needs to be treated as 1825 | // child component listeners instead of DOM listeners 1826 | var listeners = data.on; 1827 | // replace with listeners with .native modifier 1828 | data.on = data.nativeOn; 1829 | 1830 | if (Ctor.options.abstract) { 1831 | // abstract components do not keep anything 1832 | // other than props & listeners 1833 | data = {}; 1834 | } 1835 | 1836 | // merge component management hooks onto the placeholder node 1837 | mergeHooks(data); 1838 | 1839 | // return a placeholder vnode 1840 | var name = Ctor.options.name || tag; 1841 | var vnode = new VNode( 1842 | ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), 1843 | data, undefined, undefined, undefined, context, 1844 | { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children } 1845 | ); 1846 | return vnode 1847 | } 1848 | 1849 | function createFunctionalComponent ( 1850 | Ctor, 1851 | propsData, 1852 | data, 1853 | context, 1854 | children 1855 | ) { 1856 | var props = {}; 1857 | var propOptions = Ctor.options.props; 1858 | if (propOptions) { 1859 | for (var key in propOptions) { 1860 | props[key] = validateProp(key, propOptions, propsData); 1861 | } 1862 | } 1863 | // ensure the createElement function in functional components 1864 | // gets a unique context - this is necessary for correct named slot check 1865 | var _context = Object.create(context); 1866 | var h = function (a, b, c, d) { return createElement(_context, a, b, c, d, true); }; 1867 | var vnode = Ctor.options.render.call(null, h, { 1868 | props: props, 1869 | data: data, 1870 | parent: context, 1871 | children: children, 1872 | slots: function () { return resolveSlots(children, context); } 1873 | }); 1874 | if (vnode instanceof VNode) { 1875 | vnode.functionalContext = context; 1876 | if (data.slot) { 1877 | (vnode.data || (vnode.data = {})).slot = data.slot; 1878 | } 1879 | } 1880 | return vnode 1881 | } 1882 | 1883 | function createComponentInstanceForVnode ( 1884 | vnode, // we know it's MountedComponentVNode but flow doesn't 1885 | parent, // activeInstance in lifecycle state 1886 | parentElm, 1887 | refElm 1888 | ) { 1889 | var vnodeComponentOptions = vnode.componentOptions; 1890 | var options = { 1891 | _isComponent: true, 1892 | parent: parent, 1893 | propsData: vnodeComponentOptions.propsData, 1894 | _componentTag: vnodeComponentOptions.tag, 1895 | _parentVnode: vnode, 1896 | _parentListeners: vnodeComponentOptions.listeners, 1897 | _renderChildren: vnodeComponentOptions.children, 1898 | _parentElm: parentElm || null, 1899 | _refElm: refElm || null 1900 | }; 1901 | // check inline-template render functions 1902 | var inlineTemplate = vnode.data.inlineTemplate; 1903 | if (inlineTemplate) { 1904 | options.render = inlineTemplate.render; 1905 | options.staticRenderFns = inlineTemplate.staticRenderFns; 1906 | } 1907 | return new vnodeComponentOptions.Ctor(options) 1908 | } 1909 | 1910 | function init ( 1911 | vnode, 1912 | hydrating, 1913 | parentElm, 1914 | refElm 1915 | ) { 1916 | if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) { 1917 | var child = vnode.componentInstance = createComponentInstanceForVnode( 1918 | vnode, 1919 | activeInstance, 1920 | parentElm, 1921 | refElm 1922 | ); 1923 | child.$mount(hydrating ? vnode.elm : undefined, hydrating); 1924 | } else if (vnode.data.keepAlive) { 1925 | // kept-alive components, treat as a patch 1926 | var mountedNode = vnode; // work around flow 1927 | prepatch(mountedNode, mountedNode); 1928 | } 1929 | } 1930 | 1931 | function prepatch ( 1932 | oldVnode, 1933 | vnode 1934 | ) { 1935 | var options = vnode.componentOptions; 1936 | var child = vnode.componentInstance = oldVnode.componentInstance; 1937 | child._updateFromParent( 1938 | options.propsData, // updated props 1939 | options.listeners, // updated listeners 1940 | vnode, // new parent vnode 1941 | options.children // new children 1942 | ); 1943 | } 1944 | 1945 | function insert (vnode) { 1946 | if (!vnode.componentInstance._isMounted) { 1947 | vnode.componentInstance._isMounted = true; 1948 | callHook(vnode.componentInstance, 'mounted'); 1949 | } 1950 | if (vnode.data.keepAlive) { 1951 | vnode.componentInstance._inactive = false; 1952 | callHook(vnode.componentInstance, 'activated'); 1953 | } 1954 | } 1955 | 1956 | function destroy$1 (vnode) { 1957 | if (!vnode.componentInstance._isDestroyed) { 1958 | if (!vnode.data.keepAlive) { 1959 | vnode.componentInstance.$destroy(); 1960 | } else { 1961 | vnode.componentInstance._inactive = true; 1962 | callHook(vnode.componentInstance, 'deactivated'); 1963 | } 1964 | } 1965 | } 1966 | 1967 | function resolveAsyncComponent ( 1968 | factory, 1969 | baseCtor, 1970 | cb 1971 | ) { 1972 | if (factory.requested) { 1973 | // pool callbacks 1974 | factory.pendingCallbacks.push(cb); 1975 | } else { 1976 | factory.requested = true; 1977 | var cbs = factory.pendingCallbacks = [cb]; 1978 | var sync = true; 1979 | 1980 | var resolve = function (res) { 1981 | if (isObject(res)) { 1982 | res = baseCtor.extend(res); 1983 | } 1984 | // cache resolved 1985 | factory.resolved = res; 1986 | // invoke callbacks only if this is not a synchronous resolve 1987 | // (async resolves are shimmed as synchronous during SSR) 1988 | if (!sync) { 1989 | for (var i = 0, l = cbs.length; i < l; i++) { 1990 | cbs[i](res); 1991 | } 1992 | } 1993 | }; 1994 | 1995 | var reject = function (reason) { 1996 | ("production") !== 'production' && warn( 1997 | "Failed to resolve async component: " + (String(factory)) + 1998 | (reason ? ("\nReason: " + reason) : '') 1999 | ); 2000 | }; 2001 | 2002 | var res = factory(resolve, reject); 2003 | 2004 | // handle promise 2005 | if (res && typeof res.then === 'function' && !factory.resolved) { 2006 | res.then(resolve, reject); 2007 | } 2008 | 2009 | sync = false; 2010 | // return in case resolved synchronously 2011 | return factory.resolved 2012 | } 2013 | } 2014 | 2015 | function extractProps (data, Ctor) { 2016 | // we are only extracting raw values here. 2017 | // validation and default values are handled in the child 2018 | // component itself. 2019 | var propOptions = Ctor.options.props; 2020 | if (!propOptions) { 2021 | return 2022 | } 2023 | var res = {}; 2024 | var attrs = data.attrs; 2025 | var props = data.props; 2026 | var domProps = data.domProps; 2027 | if (attrs || props || domProps) { 2028 | for (var key in propOptions) { 2029 | var altKey = hyphenate(key); 2030 | checkProp(res, props, key, altKey, true) || 2031 | checkProp(res, attrs, key, altKey) || 2032 | checkProp(res, domProps, key, altKey); 2033 | } 2034 | } 2035 | return res 2036 | } 2037 | 2038 | function checkProp ( 2039 | res, 2040 | hash, 2041 | key, 2042 | altKey, 2043 | preserve 2044 | ) { 2045 | if (hash) { 2046 | if (hasOwn(hash, key)) { 2047 | res[key] = hash[key]; 2048 | if (!preserve) { 2049 | delete hash[key]; 2050 | } 2051 | return true 2052 | } else if (hasOwn(hash, altKey)) { 2053 | res[key] = hash[altKey]; 2054 | if (!preserve) { 2055 | delete hash[altKey]; 2056 | } 2057 | return true 2058 | } 2059 | } 2060 | return false 2061 | } 2062 | 2063 | function mergeHooks (data) { 2064 | if (!data.hook) { 2065 | data.hook = {}; 2066 | } 2067 | for (var i = 0; i < hooksToMerge.length; i++) { 2068 | var key = hooksToMerge[i]; 2069 | var fromParent = data.hook[key]; 2070 | var ours = hooks[key]; 2071 | data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours; 2072 | } 2073 | } 2074 | 2075 | function mergeHook$1 (one, two) { 2076 | return function (a, b, c, d) { 2077 | one(a, b, c, d); 2078 | two(a, b, c, d); 2079 | } 2080 | } 2081 | 2082 | /* */ 2083 | 2084 | function mergeVNodeHook (def, hookKey, hook, key) { 2085 | key = key + hookKey; 2086 | var injectedHash = def.__injected || (def.__injected = {}); 2087 | if (!injectedHash[key]) { 2088 | injectedHash[key] = true; 2089 | var oldHook = def[hookKey]; 2090 | if (oldHook) { 2091 | def[hookKey] = function () { 2092 | oldHook.apply(this, arguments); 2093 | hook.apply(this, arguments); 2094 | }; 2095 | } else { 2096 | def[hookKey] = hook; 2097 | } 2098 | } 2099 | } 2100 | 2101 | /* */ 2102 | 2103 | var normalizeEvent = cached(function (name) { 2104 | var once = name.charAt(0) === '~'; // Prefixed last, checked first 2105 | name = once ? name.slice(1) : name; 2106 | var capture = name.charAt(0) === '!'; 2107 | name = capture ? name.slice(1) : name; 2108 | return { 2109 | name: name, 2110 | once: once, 2111 | capture: capture 2112 | } 2113 | }); 2114 | 2115 | function createEventHandle (fn) { 2116 | var handle = { 2117 | fn: fn, 2118 | invoker: function () { 2119 | var arguments$1 = arguments; 2120 | 2121 | var fn = handle.fn; 2122 | if (Array.isArray(fn)) { 2123 | for (var i = 0; i < fn.length; i++) { 2124 | fn[i].apply(null, arguments$1); 2125 | } 2126 | } else { 2127 | fn.apply(null, arguments); 2128 | } 2129 | } 2130 | }; 2131 | return handle 2132 | } 2133 | 2134 | function updateListeners ( 2135 | on, 2136 | oldOn, 2137 | add, 2138 | remove$$1, 2139 | vm 2140 | ) { 2141 | var name, cur, old, event; 2142 | for (name in on) { 2143 | cur = on[name]; 2144 | old = oldOn[name]; 2145 | event = normalizeEvent(name); 2146 | if (!cur) { 2147 | ("production") !== 'production' && warn( 2148 | "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), 2149 | vm 2150 | ); 2151 | } else if (!old) { 2152 | if (!cur.invoker) { 2153 | cur = on[name] = createEventHandle(cur); 2154 | } 2155 | add(event.name, cur.invoker, event.once, event.capture); 2156 | } else if (cur !== old) { 2157 | old.fn = cur; 2158 | on[name] = old; 2159 | } 2160 | } 2161 | for (name in oldOn) { 2162 | if (!on[name]) { 2163 | event = normalizeEvent(name); 2164 | remove$$1(event.name, oldOn[name].invoker, event.capture); 2165 | } 2166 | } 2167 | } 2168 | 2169 | /* */ 2170 | 2171 | // The template compiler attempts to minimize the need for normalization by 2172 | // statically analyzing the template at compile time. 2173 | // 2174 | // For plain HTML markup, normalization can be completely skipped because the 2175 | // generated render function is guaranteed to return Array. There are 2176 | // two cases where extra normalization is needed: 2177 | 2178 | // 1. When the children contains components - because a functional component 2179 | // may return an Array instead of a single root. In this case, just a simple 2180 | // nomralization is needed - if any child is an Array, we flatten the whole 2181 | // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep 2182 | // because functional components already normalize their own children. 2183 | function simpleNormalizeChildren (children) { 2184 | for (var i = 0; i < children.length; i++) { 2185 | if (Array.isArray(children[i])) { 2186 | return Array.prototype.concat.apply([], children) 2187 | } 2188 | } 2189 | return children 2190 | } 2191 | 2192 | // 2. When the children contains constrcuts that always generated nested Arrays, 2193 | // e.g.