diff --git a/package-lock.json b/package-lock.json index 953fddf..df95416 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5222,6 +5222,12 @@ } } }, + "reflect-metadata": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", + "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==", + "dev": true + }, "regenerate": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", diff --git a/package.json b/package.json index 5b0769a..df971d8 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "chai": "^4.1.2", "css-loader": "^0.28.9", "mocha": "^5.0.1", + "reflect-metadata": "^0.1.12", "rimraf": "^2.6.2", "rollup": "^0.55.5", "rollup-plugin-replace": "^2.0.0", @@ -60,5 +61,6 @@ "vue-loader": "^14.1.1", "vue-template-compiler": "^2.5.13", "webpack": "^3.11.0" - } + }, + "dependencies": {} } diff --git a/src/component.ts b/src/component.ts index d110df1..c07063b 100644 --- a/src/component.ts +++ b/src/component.ts @@ -1,4 +1,5 @@ import Vue, { ComponentOptions } from 'vue' +import { copyReflectionMetadata, reflectionIsSupported, ReflectionMap } from './reflect' import { VueClass, DecoratedClass } from './declarations' import { collectDataFromConstructor } from './data' import { hasProto, isPrimitive, warn } from './util' @@ -23,6 +24,15 @@ export function componentFactory ( Component: VueClass, options: ComponentOptions = {} ): VueClass { + const reflectionMap: ReflectionMap = { + instance: {}, + static: {}, + constructor: [] + } + + if (reflectionIsSupported()) { + reflectionMap.constructor = Reflect.getOwnMetadataKeys(Component) + } options.name = options.name || (Component as any)._componentTag || (Component as any).name // prototype props. const proto = Component.prototype @@ -30,6 +40,11 @@ export function componentFactory ( if (key === 'constructor') { return } + + if (reflectionIsSupported()) { + reflectionMap.instance[key] = Reflect.getOwnMetadataKeys(proto, key) + } + // hooks if ($internalHooks.indexOf(key) > -1) { options[key] = proto[key] @@ -69,7 +84,11 @@ export function componentFactory ( : Vue const Extended = Super.extend(options) - forwardStaticMembers(Extended, Component, Super) + forwardStaticMembersAndCollectReflection(Extended, Component, Super, reflectionMap) + + if (reflectionIsSupported()) { + copyReflectionMetadata(Component, Extended, reflectionMap) + } return Extended } @@ -93,7 +112,12 @@ const reservedPropertyNames = [ 'filter' ] -function forwardStaticMembers (Extended: typeof Vue, Original: typeof Vue, Super: typeof Vue): void { +function forwardStaticMembersAndCollectReflection ( + Extended: typeof Vue, + Original: typeof Vue, + Super: typeof Vue, + reflectionMap: ReflectionMap +): void { // We have to use getOwnPropertyNames since Babel registers methods as non-enumerable Object.getOwnPropertyNames(Original).forEach(key => { // `prototype` should not be overwritten @@ -101,6 +125,10 @@ function forwardStaticMembers (Extended: typeof Vue, Original: typeof Vue, Super return } + if (reflectionIsSupported()) { + reflectionMap.static[key] = Reflect.getOwnMetadataKeys(Original, key) + } + // Some browsers does not allow reconfigure built-in properties const extendedDescriptor = Object.getOwnPropertyDescriptor(Extended, key) if (extendedDescriptor && !extendedDescriptor.configurable) { diff --git a/src/globals.d.ts b/src/globals.d.ts index 89a7ede..eca4ca2 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -3,8 +3,33 @@ * should not expose to userland */ +declare namespace Reflect { + function decorate(decorators: ClassDecorator[], target: Function): Function + function decorate(decorators: (PropertyDecorator | MethodDecorator)[], target: Object, propertyKey: string | symbol, attributes?: PropertyDescriptor): PropertyDescriptor + function metadata(metadataKey: any, metadataValue: any): { + (target: Function): void + (target: Object, propertyKey: string | symbol): void + } + function defineMetadata(metadataKey: any, metadataValue: any, target: Object): void + function defineMetadata(metadataKey: any, metadataValue: any, target: Object, propertyKey: string | symbol): void + function hasMetadata(metadataKey: any, target: Object): boolean + function hasMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean + function hasOwnMetadata(metadataKey: any, target: Object): boolean + function hasOwnMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean + function getMetadata(metadataKey: any, target: Object): any + function getMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): any + function getOwnMetadata(metadataKey: any, target: Object): any + function getOwnMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): any + function getMetadataKeys(target: Object): any[] + function getMetadataKeys(target: Object, propertyKey: string | symbol): any[] + function getOwnMetadataKeys(target: Object): any[] + function getOwnMetadataKeys(target: Object, propertyKey: string | symbol): any[] + function deleteMetadata(metadataKey: any, target: Object): boolean + function deleteMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): boolean + } + declare const process: { env: { NODE_ENV: string } -} \ No newline at end of file +} diff --git a/src/reflect.ts b/src/reflect.ts new file mode 100644 index 0000000..56b7a27 --- /dev/null +++ b/src/reflect.ts @@ -0,0 +1,39 @@ +import { VueConstructor } from 'vue' + +export type StringToArrayMap = { + [key: string]: Array +} + +export type ReflectionMap = { + constructor: Array, + instance: StringToArrayMap, + static: StringToArrayMap +} + +export function reflectionIsSupported () { + return (Reflect && Reflect.defineMetadata) !== undefined +} + +export function copyReflectionMetadata ( + from: VueConstructor, + to: VueConstructor, + reflectionMap: ReflectionMap +) { + shallowCopy(from.prototype, to.prototype, reflectionMap.instance) + shallowCopy(from, to, reflectionMap.static) + shallowCopy(from, to, {'constructor': reflectionMap.constructor}) +} + +function shallowCopy (from: VueConstructor, to: VueConstructor, propertyKeys: StringToArrayMap) { + for (const propertyKey in propertyKeys) { + propertyKeys[propertyKey].forEach((metadataKey) => { + if (propertyKey == 'constructor') { + const metadata = Reflect.getOwnMetadata(metadataKey, from) + Reflect.defineMetadata(metadataKey, metadata, to) + } else { + const metadata = Reflect.getOwnMetadata(metadataKey, from, propertyKey) + Reflect.defineMetadata(metadataKey, metadata, to, propertyKey) + } + }) + } +} diff --git a/test/test.ts b/test/test.ts index 9ff686c..8fb1557 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,3 +1,4 @@ +import 'reflect-metadata'; import Component, { createDecorator, mixins } from '../lib' import { expect } from 'chai' import * as td from 'testdouble' @@ -369,4 +370,34 @@ describe('vue-class-component', () => { expect(vm.valueA).to.equal('hi') expect(vm.valueB).to.equal(456) }) + + it('copies reflection metadata', function () { + @Component + @Reflect.metadata('worksConstructor', true) + class Test extends Vue { + @Reflect.metadata('worksStatic', true) + static staticValue: string = 'staticValue' + + private _test: boolean = false; + + @Reflect.metadata('worksMethod', true) + test (): void { + void 0 + } + + @Reflect.metadata('worksAccessor', true) + get testAccessor (): boolean { + return this._test + } + + set testAccessor (value: boolean) { + this._test = value + } + } + + expect(Reflect.getOwnMetadata('worksConstructor', Test)).to.equal(true) + expect(Reflect.getOwnMetadata('worksStatic', Test, 'staticValue')).to.equal(true) + expect(Reflect.getOwnMetadata('worksMethod', Test.prototype, 'test')).to.equal(true) + expect(Reflect.getOwnMetadata('worksAccessor', Test.prototype, 'testAccessor')).to.equal(true) + }) }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy