Skip to content

Commit a13fc5a

Browse files
author
Gleb Ivanov
committed
Added reflection support
1 parent 48059b8 commit a13fc5a

8 files changed

+132
-11
lines changed

dist/vue-class-component.common.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,25 @@ Object.defineProperty(exports, '__esModule', { value: true });
99

1010
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
1111

12+
require('reflect-metadata');
1213
var Vue = _interopDefault(require('vue'));
1314

15+
function copyReflectionMetadata(from, to, reflectionMap) {
16+
shallowCopy(from.prototype, to.prototype, reflectionMap.instance);
17+
shallowCopy(from, to, reflectionMap.static);
18+
}
19+
function shallowCopy(from, to, propertyKeys) {
20+
var _loop_1 = function (propertyKey) {
21+
propertyKeys[propertyKey].forEach(function (metadataKey) {
22+
var metadata = Reflect.getOwnMetadata(metadataKey, from, propertyKey);
23+
Reflect.defineMetadata(metadataKey, metadata, to, propertyKey);
24+
});
25+
};
26+
for (var propertyKey in propertyKeys) {
27+
_loop_1(propertyKey);
28+
}
29+
}
30+
1431
var hasProto = { __proto__: [] } instanceof Array;
1532
function createDecorator(factory) {
1633
return function (target, key, index) {
@@ -105,13 +122,18 @@ var $internalHooks = [
105122
];
106123
function componentFactory(Component, options) {
107124
if (options === void 0) { options = {}; }
125+
var reflectionMap = {
126+
instance: {},
127+
static: {}
128+
};
108129
options.name = options.name || Component._componentTag || Component.name;
109130
// prototype props.
110131
var proto = Component.prototype;
111132
Object.getOwnPropertyNames(proto).forEach(function (key) {
112133
if (key === 'constructor') {
113134
return;
114135
}
136+
reflectionMap.instance[key] = Reflect.getOwnMetadataKeys(proto, key);
115137
// hooks
116138
if ($internalHooks.indexOf(key) > -1) {
117139
options[key] = proto[key];
@@ -147,7 +169,8 @@ function componentFactory(Component, options) {
147169
? superProto.constructor
148170
: Vue;
149171
var Extended = Super.extend(options);
150-
forwardStaticMembers(Extended, Component, Super);
172+
forwardStaticMembersAndCollectReflection(Extended, Component, Super, reflectionMap);
173+
copyReflectionMetadata(Component, Extended, reflectionMap);
151174
return Extended;
152175
}
153176
var reservedPropertyNames = [
@@ -165,13 +188,14 @@ var reservedPropertyNames = [
165188
'directive',
166189
'filter'
167190
];
168-
function forwardStaticMembers(Extended, Original, Super) {
191+
function forwardStaticMembersAndCollectReflection(Extended, Original, Super, reflectionMap) {
169192
// We have to use getOwnPropertyNames since Babel registers methods as non-enumerable
170193
Object.getOwnPropertyNames(Original).forEach(function (key) {
171194
// `prototype` should not be overwritten
172195
if (key === 'prototype') {
173196
return;
174197
}
198+
reflectionMap.static[key] = Reflect.getOwnMetadataKeys(Original, key);
175199
// Some browsers does not allow reconfigure built-in properties
176200
var extendedDescriptor = Object.getOwnPropertyDescriptor(Extended, key);
177201
if (extendedDescriptor && !extendedDescriptor.configurable) {

dist/vue-class-component.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,29 @@
44
* @license MIT
55
*/
66
(function (global, factory) {
7-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
8-
typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
9-
(factory((global.VueClassComponent = {}),global.Vue));
10-
}(this, (function (exports,Vue) { 'use strict';
7+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('reflect-metadata'), require('vue')) :
8+
typeof define === 'function' && define.amd ? define(['exports', 'reflect-metadata', 'vue'], factory) :
9+
(factory((global.VueClassComponent = {}),null,global.Vue));
10+
}(this, (function (exports,reflectMetadata,Vue) { 'use strict';
1111

1212
Vue = Vue && Vue.hasOwnProperty('default') ? Vue['default'] : Vue;
1313

14+
function copyReflectionMetadata(from, to, reflectionMap) {
15+
shallowCopy(from.prototype, to.prototype, reflectionMap.instance);
16+
shallowCopy(from, to, reflectionMap.static);
17+
}
18+
function shallowCopy(from, to, propertyKeys) {
19+
var _loop_1 = function (propertyKey) {
20+
propertyKeys[propertyKey].forEach(function (metadataKey) {
21+
var metadata = Reflect.getOwnMetadata(metadataKey, from, propertyKey);
22+
Reflect.defineMetadata(metadataKey, metadata, to, propertyKey);
23+
});
24+
};
25+
for (var propertyKey in propertyKeys) {
26+
_loop_1(propertyKey);
27+
}
28+
}
29+
1430
var hasProto = { __proto__: [] } instanceof Array;
1531
function createDecorator(factory) {
1632
return function (target, key, index) {
@@ -105,13 +121,18 @@ var $internalHooks = [
105121
];
106122
function componentFactory(Component, options) {
107123
if (options === void 0) { options = {}; }
124+
var reflectionMap = {
125+
instance: {},
126+
static: {}
127+
};
108128
options.name = options.name || Component._componentTag || Component.name;
109129
// prototype props.
110130
var proto = Component.prototype;
111131
Object.getOwnPropertyNames(proto).forEach(function (key) {
112132
if (key === 'constructor') {
113133
return;
114134
}
135+
reflectionMap.instance[key] = Reflect.getOwnMetadataKeys(proto, key);
115136
// hooks
116137
if ($internalHooks.indexOf(key) > -1) {
117138
options[key] = proto[key];
@@ -147,7 +168,8 @@ function componentFactory(Component, options) {
147168
? superProto.constructor
148169
: Vue;
149170
var Extended = Super.extend(options);
150-
forwardStaticMembers(Extended, Component, Super);
171+
forwardStaticMembersAndCollectReflection(Extended, Component, Super, reflectionMap);
172+
copyReflectionMetadata(Component, Extended, reflectionMap);
151173
return Extended;
152174
}
153175
var reservedPropertyNames = [
@@ -165,13 +187,14 @@ var reservedPropertyNames = [
165187
'directive',
166188
'filter'
167189
];
168-
function forwardStaticMembers(Extended, Original, Super) {
190+
function forwardStaticMembersAndCollectReflection(Extended, Original, Super, reflectionMap) {
169191
// We have to use getOwnPropertyNames since Babel registers methods as non-enumerable
170192
Object.getOwnPropertyNames(Original).forEach(function (key) {
171193
// `prototype` should not be overwritten
172194
if (key === 'prototype') {
173195
return;
174196
}
197+
reflectionMap.static[key] = Reflect.getOwnMetadataKeys(Original, key);
175198
// Some browsers does not allow reconfigure built-in properties
176199
var extendedDescriptor = Object.getOwnPropertyDescriptor(Extended, key);
177200
if (extendedDescriptor && !extendedDescriptor.configurable) {

dist/vue-class-component.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,8 @@
6060
"vue-loader": "^14.1.1",
6161
"vue-template-compiler": "^2.5.13",
6262
"webpack": "^3.11.0"
63+
},
64+
"dependencies": {
65+
"reflect-metadata": "^0.1.12"
6366
}
6467
}

src/component.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import 'reflect-metadata'
12
import Vue, { ComponentOptions } from 'vue'
3+
import { copyReflectionMetadata, ReflectionMap } from './reflect'
24
import { VueClass, DecoratedClass } from './declarations'
35
import { collectDataFromConstructor } from './data'
46
import { hasProto, isPrimitive, warn } from './util'
@@ -23,13 +25,19 @@ export function componentFactory (
2325
Component: VueClass<Vue>,
2426
options: ComponentOptions<Vue> = {}
2527
): VueClass<Vue> {
28+
const reflectionMap: ReflectionMap = {
29+
instance: {},
30+
static: {}
31+
};
32+
2633
options.name = options.name || (Component as any)._componentTag || (Component as any).name
2734
// prototype props.
2835
const proto = Component.prototype
2936
Object.getOwnPropertyNames(proto).forEach(function (key) {
3037
if (key === 'constructor') {
3138
return
3239
}
40+
reflectionMap.instance[key] = Reflect.getOwnMetadataKeys(proto, key);
3341
// hooks
3442
if ($internalHooks.indexOf(key) > -1) {
3543
options[key] = proto[key]
@@ -69,7 +77,8 @@ export function componentFactory (
6977
: Vue
7078
const Extended = Super.extend(options)
7179

72-
forwardStaticMembers(Extended, Component, Super)
80+
forwardStaticMembersAndCollectReflection(Extended, Component, Super, reflectionMap)
81+
copyReflectionMetadata(Component, Extended, reflectionMap)
7382

7483
return Extended
7584
}
@@ -93,14 +102,21 @@ const reservedPropertyNames = [
93102
'filter'
94103
]
95104

96-
function forwardStaticMembers (Extended: typeof Vue, Original: typeof Vue, Super: typeof Vue): void {
105+
function forwardStaticMembersAndCollectReflection (
106+
Extended: typeof Vue,
107+
Original: typeof Vue,
108+
Super: typeof Vue,
109+
reflectionMap: ReflectionMap
110+
): void {
97111
// We have to use getOwnPropertyNames since Babel registers methods as non-enumerable
98112
Object.getOwnPropertyNames(Original).forEach(key => {
99113
// `prototype` should not be overwritten
100114
if (key === 'prototype') {
101115
return
102116
}
103117

118+
reflectionMap.static[key] = Reflect.getOwnMetadataKeys(Original, key);
119+
104120
// Some browsers does not allow reconfigure built-in properties
105121
const extendedDescriptor = Object.getOwnPropertyDescriptor(Extended, key)
106122
if (extendedDescriptor && !extendedDescriptor.configurable) {

src/reflect.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { VueConstructor } from 'vue'
2+
import 'reflect-metadata'
3+
4+
export type StringToArrayMap = {
5+
[key: string]: Array<string>
6+
}
7+
8+
export type ReflectionMap = {
9+
instance: StringToArrayMap,
10+
static: StringToArrayMap
11+
}
12+
13+
export function copyReflectionMetadata(
14+
from: VueConstructor,
15+
to: VueConstructor,
16+
reflectionMap: ReflectionMap
17+
) {
18+
shallowCopy(from.prototype, to.prototype, reflectionMap.instance);
19+
shallowCopy(from, to, reflectionMap.static);
20+
}
21+
22+
function shallowCopy(from: VueConstructor, to: VueConstructor, propertyKeys: StringToArrayMap) {
23+
for (const propertyKey in propertyKeys) {
24+
propertyKeys[propertyKey].forEach((metadataKey) => {
25+
const metadata = Reflect.getOwnMetadata(metadataKey, from, propertyKey)
26+
Reflect.defineMetadata(metadataKey, metadata, to, propertyKey)
27+
})
28+
}
29+
}

test/test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'reflect-metadata';
12
import Component, { createDecorator, mixins } from '../lib'
23
import { expect } from 'chai'
34
import * as td from 'testdouble'
@@ -369,4 +370,23 @@ describe('vue-class-component', () => {
369370
expect(vm.valueA).to.equal('hi')
370371
expect(vm.valueB).to.equal(456)
371372
})
373+
374+
it('copies reflection metadata', function () {
375+
@Component
376+
class Test extends Vue {
377+
@Reflect.metadata('worksStatic', true)
378+
static staticValue: string = 'staticValue';
379+
380+
@Reflect.metadata('worksMethod', true)
381+
test(): void { }
382+
383+
@Reflect.metadata('worksAccessor', true)
384+
get testAccessor(): boolean { return true; }
385+
set testAccessor(value: boolean) { void(value) }
386+
}
387+
388+
expect(Reflect.getOwnMetadata('worksStatic', Test, 'staticValue')).to.equal(true);
389+
expect(Reflect.getOwnMetadata('worksMethod', Test.prototype, 'test')).to.equal(true);
390+
expect(Reflect.getOwnMetadata('worksAccessor', Test.prototype, 'testAccessor')).to.equal(true);
391+
})
372392
})

0 commit comments

Comments
 (0)