From: Evan You Date: Wed, 27 Feb 2019 02:33:50 +0000 (-0500) Subject: refactor: move prop decorator into core, expose initial props to initialziers X-Git-Tag: v3.0.0-alpha.0~1015 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ff9cddd46f61560eed7407d6a8431cd04692f3e2;p=thirdparty%2Fvuejs%2Fcore.git refactor: move prop decorator into core, expose initial props to initialziers --- diff --git a/packages/decorators/.npmignore b/packages/decorators/.npmignore deleted file mode 100644 index bb5c8a541b..0000000000 --- a/packages/decorators/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -__tests__/ -__mocks__/ -dist/packages \ No newline at end of file diff --git a/packages/decorators/README.md b/packages/decorators/README.md deleted file mode 100644 index d06feabba8..0000000000 --- a/packages/decorators/README.md +++ /dev/null @@ -1 +0,0 @@ -# @vue/decorators \ No newline at end of file diff --git a/packages/decorators/index.js b/packages/decorators/index.js deleted file mode 100644 index 6817e443c6..0000000000 --- a/packages/decorators/index.js +++ /dev/null @@ -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') -} diff --git a/packages/decorators/package.json b/packages/decorators/package.json deleted file mode 100644 index e88e438acc..0000000000 --- a/packages/decorators/package.json +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/packages/decorators/__tests__/prop.spec.ts b/packages/runtime-core/__tests__/propDecorator.spec.ts similarity index 80% rename from packages/decorators/__tests__/prop.spec.ts rename to packages/runtime-core/__tests__/propDecorator.spec.ts index b2714f3fdd..1ea33c6063 100644 --- a/packages/decorators/__tests__/prop.spec.ts +++ b/packages/runtime-core/__tests__/propDecorator.spec.ts @@ -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) }) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 08112569e9..6ce1092b6a 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -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_/ diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 01e17922ca..91defca4e3 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -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.`) } } } diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 01871522e4..b5855409ef 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -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() diff --git a/packages/runtime-core/src/componentState.ts b/packages/runtime-core/src/componentState.ts index 8b6035c9a2..b5ed9d4da9 100644 --- a/packages/runtime-core/src/componentState.ts +++ b/packages/runtime-core/src/componentState.ts @@ -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] } } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 078e319591..0760f609dc 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -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' diff --git a/packages/decorators/src/index.ts b/packages/runtime-core/src/optional/propDecorator.ts similarity index 69% rename from packages/decorators/src/index.ts rename to packages/runtime-core/src/optional/propDecorator.ts index 0989910529..8cdb088f95 100644 --- a/packages/decorators/src/index.ts +++ b/packages/runtime-core/src/optional/propDecorator.ts @@ -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, @@ -16,7 +18,7 @@ export function prop( function applyProp(target: any, key: string, options: PropValidator = {}) { // here `target` is the prototype of the component class - Object.defineProperty(target, `__prop_${key}`, { + Object.defineProperty(target, `__prop_${camelize(key)}`, { value: options }) } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 769343dd70..1f23bf403c 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -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 =>