refactor: move prop decorator into core, expose initial props to initialziers

This commit is contained in:
Evan You
2019-02-26 21:33:50 -05:00
parent 2f165c1e87
commit ff9cddd46f
12 changed files with 53 additions and 62 deletions

View File

@@ -105,6 +105,10 @@ export const reservedMethods: ReservedKeys = {
renderTriggered: 1
}
export function isReservedKey(key: string): boolean {
return key[0] === '_' || key[0] === '$' || reservedMethods.hasOwnProperty(key)
}
// This is a special marker from the @prop decorator.
// The decorator stores prop options on the Class' prototype as __prop_xxx
const propPrefixRE = /^__prop_/

View File

@@ -5,7 +5,8 @@ import {
PropOptions,
Prop,
PropType,
ComponentPropsOptions
ComponentPropsOptions,
isReservedKey
} from './componentOptions'
import {
EMPTY_OBJ,
@@ -43,6 +44,15 @@ export function initializeProps(
? immutable(attrs)
: attrs
: instance.$props
// expose initial props on the raw instance so that they can be accessed
// in the child class constructor by class field initializers.
if (options != null) {
for (const key in props) {
// it's okay to just set it here because props options are normalized
// and reserved keys should have been filtered away
;(instance as any)[key] = props[key]
}
}
}
// resolve raw VNode data.
@@ -59,7 +69,7 @@ export function resolveProps(
rawData: any,
_options: NormalizedPropsOptions | void
): [Data, Data] {
const hasDeclaredProps = _options !== void 0
const hasDeclaredProps = _options != null
const options = _options as NormalizedPropsOptions
if (!rawData && !hasDeclaredProps) {
return EMPTY_PROPS
@@ -129,22 +139,32 @@ export function normalizePropsOptions(
if (__DEV__ && !isString(raw[i])) {
warn(`props must be strings when using array syntax.`, raw[i])
}
normalized[camelize(raw[i])] = EMPTY_OBJ
const normalizedKey = camelize(raw[i])
if (!isReservedKey(normalizedKey)) {
normalized[normalizedKey] = EMPTY_OBJ
} else if (__DEV__) {
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
}
}
} else {
if (__DEV__ && !isObject(raw)) {
warn(`invalid props options`, raw)
}
for (const key in raw) {
const opt = raw[key]
const prop = (normalized[camelize(key)] =
isArray(opt) || isFunction(opt) ? { type: opt } : opt)
if (prop) {
const booleanIndex = getTypeIndex(Boolean, prop.type)
const stringIndex = getTypeIndex(String, prop.type)
;(prop as NormalizedProp)[BooleanFlags.shouldCast] = booleanIndex > -1
;(prop as NormalizedProp)[BooleanFlags.shouldCastTrue] =
booleanIndex < stringIndex
const normalizedKey = camelize(key)
if (!isReservedKey(normalizedKey)) {
const opt = raw[key]
const prop = (normalized[normalizedKey] =
isArray(opt) || isFunction(opt) ? { type: opt } : opt)
if (prop) {
const booleanIndex = getTypeIndex(Boolean, prop.type)
const stringIndex = getTypeIndex(String, prop.type)
;(prop as NormalizedProp)[BooleanFlags.shouldCast] = booleanIndex > -1
;(prop as NormalizedProp)[BooleanFlags.shouldCastTrue] =
booleanIndex < stringIndex
}
} else if (__DEV__) {
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`)
}
}
}

View File

@@ -1,7 +1,7 @@
import { ComponentInstance } from './component'
import { isFunction, isReservedKey } from '@vue/shared'
import { isFunction } from '@vue/shared'
import { isRendering } from './componentRenderUtils'
import { reservedMethods } from './componentOptions'
import { isReservedKey, reservedMethods } from './componentOptions'
import { warn } from './warning'
const bindCache = new WeakMap()

View File

@@ -1,7 +1,6 @@
import { ComponentInstance } from './component'
import { observable } from '@vue/observer'
import { isReservedKey } from '@vue/shared'
import { warn } from './warning'
import { isReservedKey } from './componentOptions'
export function initializeState(
instance: ComponentInstance,
@@ -25,16 +24,8 @@ export function extractInitializers(
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (!isReservedKey(key)) {
// it's possible for a prop to be present here when it's declared with
// decorators and has a default value.
if (props && props.hasOwnProperty(key)) {
__DEV__ &&
warn(
`Class property "${key}" is declared as a prop but also has an initializer. ` +
`If you are trying to provide a default value for the prop, use the ` +
`prop's "default" option instead.`
)
} else {
// it's possible for a prop to be present here when it's declared
if (!props || !props.hasOwnProperty(key)) {
data[key] = (instance as any)[key]
}
}

View File

@@ -31,6 +31,7 @@ export { KeepAlive } from './optional/keepAlive'
export { mixins } from './optional/mixins'
export { EventEmitter } from './optional/eventEmitter'
export { memoize } from './optional/memoize'
export { prop } from './optional/propDecorator'
// flags & types
export { ComponentType, ComponentClass, FunctionalComponent } from './component'

View File

@@ -0,0 +1,24 @@
import { Component } from '../component'
import { PropValidator } from '../componentOptions'
import { camelize } from '@vue/shared'
export function prop(
target: Component | PropValidator<any>,
key?: string
): any {
if (key) {
applyProp(target, key)
} else {
const options = target as PropValidator<any>
return (target: any, key: string) => {
applyProp(target, key, options)
}
}
}
function applyProp(target: any, key: string, options: PropValidator<any> = {}) {
// here `target` is the prototype of the component class
Object.defineProperty(target, `__prop_${camelize(key)}`, {
value: options
})
}