|
1 | | -import { isArray, isFunction, isObject, isString, isSymbol, merge } from 'lodash'; |
| 1 | +import { isArray, isFunction, isObject, isString, isSymbol, isUndefined, merge } from 'lodash'; |
2 | 2 | import { isCtorFunction } from './functions/is-ctor-function'; |
3 | 3 | import { nameOf } from './functions/name-of'; |
4 | 4 | import { GenericArgument } from './generic-argument'; |
| 5 | +import { PropertyDecorator } from './property-decorator'; |
5 | 6 | import { PropertyOptions } from './property-options'; |
6 | 7 | import { TypeArgument } from './type-argument'; |
7 | 8 | import { TypeFn } from './type-fn'; |
@@ -54,27 +55,71 @@ export function Property<TType>( |
54 | 55 | propertyOptions.typeArgument = x; |
55 | 56 | } |
56 | 57 |
|
57 | | - return function (target: any, propertyName: string | symbol): void |
| 58 | + return function (target: any, context: any): any |
58 | 59 | { |
59 | | - if (isCtorFunction(target)) |
| 60 | + // Modern decorator has a dynamic target which is dependent from where decorator |
| 61 | + // is applied (target), context as a second parameter (context) and optional |
| 62 | + // resolver like return type. |
| 63 | + if (isObject(context) && context.hasOwnProperty('kind')) |
60 | 64 | { |
61 | | - throw new Error(`${nameOf(target)}.${String(propertyName)}: property decorator cannot be applied to a static member.`); |
62 | | - } |
| 65 | + const decoratorContext = context as any; |
| 66 | + const kind = decoratorContext.kind; |
| 67 | + const propertyName = decoratorContext.name; |
63 | 68 |
|
64 | | - if (isSymbol(propertyName)) |
65 | | - { |
66 | | - throw new Error(`${nameOf(target.constructor)}.${String(propertyName)}: property decorator cannot be applied to a symbol.`); |
| 69 | + if (kind === 'method' || kind === 'class') |
| 70 | + { |
| 71 | + throw new Error(`${String(propertyName)}: property decorator cannot be applied to a method or a class.`); |
| 72 | + } |
| 73 | + |
| 74 | + if (isUndefined(propertyName)) |
| 75 | + { |
| 76 | + throw new Error(`${String(propertyName)}: property decorator cannot be applied to undefined values.`); |
| 77 | + } |
| 78 | + |
| 79 | + if (isSymbol(propertyName)) |
| 80 | + { |
| 81 | + throw new Error(`${String(propertyName)}: property decorator cannot be applied to a symbol.`); |
| 82 | + } |
| 83 | + |
| 84 | + TypeManager.typeScope.addPropertyOptions(propertyName, propertyOptions); |
| 85 | + |
| 86 | + return; |
67 | 87 | } |
68 | 88 |
|
69 | | - if (isFunction(target[propertyName])) |
| 89 | + // Legacy decorator has class reference as a first parameter (target), property name |
| 90 | + // or symbol as a second parameter (context) and no return type. |
| 91 | + if (isObject(target) && (isString(context) || isSymbol(context))) |
70 | 92 | { |
71 | | - throw new Error(`${nameOf(target.constructor)}.${String(propertyName)}: property decorator cannot be applied to a method.`); |
72 | | - } |
| 93 | + const legacyTarget = target as any; |
| 94 | + const propertyName = context as string | symbol | undefined; |
| 95 | + |
| 96 | + if (isCtorFunction(legacyTarget)) |
| 97 | + { |
| 98 | + throw new Error(`${nameOf(legacyTarget)}.${String(propertyName)}: property decorator cannot be applied to a static member.`); |
| 99 | + } |
73 | 100 |
|
74 | | - const typeFn = target.constructor as TypeFn<any>; |
75 | | - |
76 | | - TypeManager.configureTypeMetadata(typeFn).configurePropertyMetadata(propertyName, propertyOptions); |
| 101 | + if (isUndefined(propertyName)) |
| 102 | + { |
| 103 | + throw new Error(`${nameOf(legacyTarget)}.${String(propertyName)}: property decorator cannot be applied to undefined values.`); |
| 104 | + } |
| 105 | + |
| 106 | + if (isSymbol(propertyName)) |
| 107 | + { |
| 108 | + throw new Error(`${nameOf(legacyTarget.constructor)}.${String(propertyName)}: property decorator cannot be applied to a symbol.`); |
| 109 | + } |
| 110 | + |
| 111 | + if (isFunction(legacyTarget[propertyName])) |
| 112 | + { |
| 113 | + throw new Error(`${nameOf(legacyTarget.constructor)}.${String(propertyName)}: property decorator cannot be applied to a method.`); |
| 114 | + } |
| 115 | + |
| 116 | + const typeFn = legacyTarget.constructor as TypeFn<any>; |
| 117 | + |
| 118 | + TypeManager.configureTypeMetadata(typeFn).configurePropertyMetadata(propertyName, propertyOptions); |
| 119 | + |
| 120 | + return; |
| 121 | + } |
77 | 122 |
|
78 | | - return; |
| 123 | + throw new Error(`Property decorator was not able to detect correct resolver for the following target [${target}] and context [${context}].`); |
79 | 124 | }; |
80 | 125 | } |
0 commit comments