refactor: move prop decorator into core, expose initial props to initialziers
This commit is contained in:
parent
2f165c1e87
commit
ff9cddd46f
@ -1,3 +0,0 @@
|
||||
__tests__/
|
||||
__mocks__/
|
||||
dist/packages
|
@ -1 +0,0 @@
|
||||
# @vue/decorators
|
@ -1,7 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./dist/decorators.cjs.prod.js')
|
||||
} else {
|
||||
module.exports = require('./dist/decorators.cjs.js')
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "@vue/decorators",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"description": "@vue/decorators",
|
||||
"main": "index.js",
|
||||
"module": "dist/decorators.esm-bundler.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuejs/vue.git"
|
||||
},
|
||||
"keywords": [
|
||||
"vue"
|
||||
],
|
||||
"author": "Evan You",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vuejs/vue/issues"
|
||||
},
|
||||
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/decorators#readme"
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { prop } from '../src/index'
|
||||
import { prop } from '../src/optional/propDecorator'
|
||||
import { Component, createInstance } from '@vue/runtime-test'
|
||||
|
||||
test('without options', () => {
|
||||
@ -32,16 +32,20 @@ test('without options', () => {
|
||||
test('with options', () => {
|
||||
let capturedThisValue
|
||||
let capturedPropsValue
|
||||
let capturedDataValue
|
||||
|
||||
class Foo extends Component<{ p: number }> {
|
||||
@prop({
|
||||
default: 1
|
||||
})
|
||||
p: number
|
||||
// data property should be able to make use of prop
|
||||
d: number = this.p + 1
|
||||
|
||||
created() {
|
||||
capturedThisValue = this.p
|
||||
capturedPropsValue = this.$props.p
|
||||
capturedDataValue = this.d
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +53,7 @@ test('with options', () => {
|
||||
createInstance(Foo)
|
||||
expect(capturedThisValue).toBe(1)
|
||||
expect(capturedPropsValue).toBe(1)
|
||||
expect(capturedDataValue).toBe(2)
|
||||
|
||||
// explicit override
|
||||
createInstance(Foo, {
|
||||
@ -56,4 +61,5 @@ test('with options', () => {
|
||||
})
|
||||
expect(capturedThisValue).toBe(2)
|
||||
expect(capturedPropsValue).toBe(2)
|
||||
expect(capturedDataValue).toBe(3)
|
||||
})
|
@ -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_/
|
||||
|
@ -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.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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'
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { PropValidator, Component } from '@vue/runtime-core'
|
||||
import { Component } from '../component'
|
||||
import { PropValidator } from '../componentOptions'
|
||||
import { camelize } from '@vue/shared'
|
||||
|
||||
export function prop(
|
||||
target: Component | PropValidator<any>,
|
||||
@ -16,7 +18,7 @@ export function prop(
|
||||
|
||||
function applyProp(target: any, key: string, options: PropValidator<any> = {}) {
|
||||
// here `target` is the prototype of the component class
|
||||
Object.defineProperty(target, `__prop_${key}`, {
|
||||
Object.defineProperty(target, `__prop_${camelize(key)}`, {
|
||||
value: options
|
||||
})
|
||||
}
|
@ -5,7 +5,6 @@ export const NOOP = () => {}
|
||||
export const reservedPropRE = /^(?:key|ref|slots)$|^vnode/
|
||||
|
||||
export const isOn = (key: string) => key[0] === 'o' && key[1] === 'n'
|
||||
export const isReservedKey = (key: string) => key[0] === '_' || key[0] === '$'
|
||||
|
||||
export const isArray = Array.isArray
|
||||
export const isFunction = (val: any): val is Function =>
|
||||
|
Loading…
Reference in New Issue
Block a user