1import config from '../config'2import Watcher from '../observer/watcher'3import Dep, { pushTarget, popTarget } from '../observer/dep'4import { isUpdatingChildComponent } from './lifecycle'5import { initSetup } from 'v3/apiSetup'67import {8 set,9 del,10 observe,11 defineReactive,12 toggleObserving13} from '../observer/index'1415import {16 warn,17 bind,18 noop,19 hasOwn,20 isArray,21 hyphenate,22 isReserved,23 handleError,24 nativeWatch,25 validateProp,26 isPlainObject,27 isServerRendering,28 isReservedAttribute,29 invokeWithErrorHandling,30 isFunction31} from '../util/index'32import type { Component } from 'types/component'33import { shallowReactive, TrackOpTypes } from 'v3'3435const sharedPropertyDefinition = {36 enumerable: true,37 configurable: true,38 get: noop,39 set: noop40}4142export function proxy(target: Object, sourceKey: string, key: string) {43 sharedPropertyDefinition.get = function proxyGetter() {44 return this[sourceKey][key]45 }46 sharedPropertyDefinition.set = function proxySetter(val) {47 this[sourceKey][key] = val48 }49 Object.defineProperty(target, key, sharedPropertyDefinition)50}5152export function initState(vm: Component) {53 const opts = vm.$options54 if (opts.props) initProps(vm, opts.props)5556 // Composition API57 initSetup(vm)5859 if (opts.methods) initMethods(vm, opts.methods)60 if (opts.data) {61 initData(vm)62 } else {63 const ob = observe((vm._data = {}))64 ob && ob.vmCount++65 }66 if (opts.computed) initComputed(vm, opts.computed)67 if (opts.watch && opts.watch !== nativeWatch) {68 initWatch(vm, opts.watch)69 }70}7172function initProps(vm: Component, propsOptions: Object) {73 const propsData = vm.$options.propsData || {}74 const props = (vm._props = shallowReactive({}))75 // cache prop keys so that future props updates can iterate using Array76 // instead of dynamic object key enumeration.77 const keys: string[] = (vm.$options._propKeys = [])78 const isRoot = !vm.$parent79 // root instance props should be converted80 if (!isRoot) {81 toggleObserving(false)82 }83 for (const key in propsOptions) {84 keys.push(key)85 const value = validateProp(key, propsOptions, propsData, vm)86 /* istanbul ignore else */87 if (__DEV__) {88 const hyphenatedKey = hyphenate(key)89 if (90 isReservedAttribute(hyphenatedKey) ||91 config.isReservedAttr(hyphenatedKey)92 ) {93 warn(94 `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,95 vm96 )97 }98 defineReactive(99 props,100 key,101 value,102 () => {103 if (!isRoot && !isUpdatingChildComponent) {104 warn(105 `Avoid mutating a prop directly since the value will be ` +106 `overwritten whenever the parent component re-renders. ` +107 `Instead, use a data or computed property based on the prop's ` +108 `value. Prop being mutated: "${key}"`,109 vm110 )111 }112 },113 true /* shallow */114 )115 } else {116 defineReactive(props, key, value, undefined, true /* shallow */)117 }118 // static props are already proxied on the component's prototype119 // during Vue.extend(). We only need to proxy props defined at120 // instantiation here.121 if (!(key in vm)) {122 proxy(vm, `_props`, key)123 }124 }125 toggleObserving(true)126}127128function initData(vm: Component) {129 let data: any = vm.$options.data130 data = vm._data = isFunction(data) ? getData(data, vm) : data || {}131 if (!isPlainObject(data)) {132 data = {}133 __DEV__ &&134 warn(135 'data functions should return an object:\n' +136 'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',137 vm138 )139 }140 // proxy data on instance141 const keys = Object.keys(data)142 const props = vm.$options.props143 const methods = vm.$options.methods144 let i = keys.length145 while (i--) {146 const key = keys[i]147 if (__DEV__) {148 if (methods && hasOwn(methods, key)) {149 warn(`Method "${key}" has already been defined as a data property.`, vm)150 }151 }152 if (props && hasOwn(props, key)) {153 __DEV__ &&154 warn(155 `The data property "${key}" is already declared as a prop. ` +156 `Use prop default value instead.`,157 vm158 )159 } else if (!isReserved(key)) {160 proxy(vm, `_data`, key)161 }162 }163 // observe data164 const ob = observe(data)165 ob && ob.vmCount++166}167168export function getData(data: Function, vm: Component): any {169 // #7573 disable dep collection when invoking data getters170 pushTarget()171 try {172 return data.call(vm, vm)173 } catch (e: any) {174 handleError(e, vm, `data()`)175 return {}176 } finally {177 popTarget()178 }179}180181const computedWatcherOptions = { lazy: true }182183function initComputed(vm: Component, computed: Object) {184 // $flow-disable-line185 const watchers = (vm._computedWatchers = Object.create(null))186 // computed properties are just getters during SSR187 const isSSR = isServerRendering()188189 for (const key in computed) {190 const userDef = computed[key]191 const getter = isFunction(userDef) ? userDef : userDef.get192 if (__DEV__ && getter == null) {193 warn(`Getter is missing for computed property "${key}".`, vm)194 }195196 if (!isSSR) {197 // create internal watcher for the computed property.198 watchers[key] = new Watcher(199 vm,200 getter || noop,201 noop,202 computedWatcherOptions203 )204 }205206 // component-defined computed properties are already defined on the207 // component prototype. We only need to define computed properties defined208 // at instantiation here.209 if (!(key in vm)) {210 defineComputed(vm, key, userDef)211 } else if (__DEV__) {212 if (key in vm.$data) {213 warn(`The computed property "${key}" is already defined in data.`, vm)214 } else if (vm.$options.props && key in vm.$options.props) {215 warn(`The computed property "${key}" is already defined as a prop.`, vm)216 } else if (vm.$options.methods && key in vm.$options.methods) {217 warn(218 `The computed property "${key}" is already defined as a method.`,219 vm220 )221 }222 }223 }224}225226export function defineComputed(227 target: any,228 key: string,229 userDef: Record<string, any> | (() => any)230) {231 const shouldCache = !isServerRendering()232 if (isFunction(userDef)) {233 sharedPropertyDefinition.get = shouldCache234 ? createComputedGetter(key)235 : createGetterInvoker(userDef)236 sharedPropertyDefinition.set = noop237 } else {238 sharedPropertyDefinition.get = userDef.get239 ? shouldCache && userDef.cache !== false240 ? createComputedGetter(key)241 : createGetterInvoker(userDef.get)242 : noop243 sharedPropertyDefinition.set = userDef.set || noop244 }245 if (__DEV__ && sharedPropertyDefinition.set === noop) {246 sharedPropertyDefinition.set = function () {247 warn(248 `Computed property "${key}" was assigned to but it has no setter.`,249 this250 )251 }252 }253 Object.defineProperty(target, key, sharedPropertyDefinition)254}255256function createComputedGetter(key) {257 return function computedGetter() {258 const watcher = this._computedWatchers && this._computedWatchers[key]259 if (watcher) {260 if (watcher.dirty) {261 watcher.evaluate()262 }263 if (Dep.target) {264 if (__DEV__ && Dep.target.onTrack) {265 Dep.target.onTrack({266 effect: Dep.target,267 target: this,268 type: TrackOpTypes.GET,269 key270 })271 }272 watcher.depend()273 }274 return watcher.value275 }276 }277}278279function createGetterInvoker(fn) {280 return function computedGetter() {281 return fn.call(this, this)282 }283}284285function initMethods(vm: Component, methods: Object) {286 const props = vm.$options.props287 for (const key in methods) {288 if (__DEV__) {289 if (typeof methods[key] !== 'function') {290 warn(291 `Method "${key}" has type "${typeof methods[292 key293 ]}" in the component definition. ` +294 `Did you reference the function correctly?`,295 vm296 )297 }298 if (props && hasOwn(props, key)) {299 warn(`Method "${key}" has already been defined as a prop.`, vm)300 }301 if (key in vm && isReserved(key)) {302 warn(303 `Method "${key}" conflicts with an existing Vue instance method. ` +304 `Avoid defining component methods that start with _ or $.`305 )306 }307 }308 vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)309 }310}311312function initWatch(vm: Component, watch: Object) {313 for (const key in watch) {314 const handler = watch[key]315 if (isArray(handler)) {316 for (let i = 0; i < handler.length; i++) {317 createWatcher(vm, key, handler[i])318 }319 } else {320 createWatcher(vm, key, handler)321 }322 }323}324325function createWatcher(326 vm: Component,327 expOrFn: string | (() => any),328 handler: any,329 options?: Object330) {331 if (isPlainObject(handler)) {332 options = handler333 handler = handler.handler334 }335 if (typeof handler === 'string') {336 handler = vm[handler]337 }338 return vm.$watch(expOrFn, handler, options)339}340341export function stateMixin(Vue: typeof Component) {342 // flow somehow has problems with directly declared definition object343 // when using Object.defineProperty, so we have to procedurally build up344 // the object here.345 const dataDef: any = {}346 dataDef.get = function () {347 return this._data348 }349 const propsDef: any = {}350 propsDef.get = function () {351 return this._props352 }353 if (__DEV__) {354 dataDef.set = function () {355 warn(356 'Avoid replacing instance root $data. ' +357 'Use nested data properties instead.',358 this359 )360 }361 propsDef.set = function () {362 warn(`$props is readonly.`, this)363 }364 }365 Object.defineProperty(Vue.prototype, '$data', dataDef)366 Object.defineProperty(Vue.prototype, '$props', propsDef)367368 Vue.prototype.$set = set369 Vue.prototype.$delete = del370371 Vue.prototype.$watch = function (372 expOrFn: string | (() => any),373 cb: any,374 options?: Record<string, any>375 ): Function {376 const vm: Component = this377 if (isPlainObject(cb)) {378 return createWatcher(vm, expOrFn, cb, options)379 }380 options = options || {}381 options.user = true382 const watcher = new Watcher(vm, expOrFn, cb, options)383 if (options.immediate) {384 const info = `callback for immediate watcher "${watcher.expression}"`385 pushTarget()386 invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)387 popTarget()388 }389 return function unwatchFn() {390 watcher.teardown()391 }392 }393}
Findings
✓ No findings reported for this file.