UNPKG

9.75 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google Inc. All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8import { __spreadArrays } from "tslib";
9import { global, stringify } from '../facade/lang';
10var _nextClassId = 0;
11var Reflect = global['Reflect'];
12function extractAnnotation(annotation) {
13 if (typeof annotation === 'function' && annotation.hasOwnProperty('annotation')) {
14 // it is a decorator, extract annotation
15 annotation = annotation.annotation;
16 }
17 return annotation;
18}
19function applyParams(fnOrArray, key) {
20 if (fnOrArray === Object || fnOrArray === String || fnOrArray === Function || fnOrArray === Number || fnOrArray === Array) {
21 throw new Error("Can not use native " + stringify(fnOrArray) + " as constructor");
22 }
23 if (typeof fnOrArray === 'function') {
24 return fnOrArray;
25 }
26 if (Array.isArray(fnOrArray)) {
27 var annotations = fnOrArray;
28 var annoLength = annotations.length - 1;
29 var fn = fnOrArray[annoLength];
30 if (typeof fn !== 'function') {
31 throw new Error("Last position of Class method array must be Function in key " + key + " was '" + stringify(fn) + "'");
32 }
33 if (annoLength !== fn.length) {
34 throw new Error("Number of annotations (" + annoLength + ") does not match number of arguments (" + fn.length + ") in the function: " + stringify(fn));
35 }
36 var paramsAnnotations = [];
37 for (var i = 0, ii = annotations.length - 1; i < ii; i++) {
38 var paramAnnotations = [];
39 paramsAnnotations.push(paramAnnotations);
40 var annotation = annotations[i];
41 if (Array.isArray(annotation)) {
42 for (var j = 0; j < annotation.length; j++) {
43 paramAnnotations.push(extractAnnotation(annotation[j]));
44 }
45 }
46 else if (typeof annotation === 'function') {
47 paramAnnotations.push(extractAnnotation(annotation));
48 }
49 else {
50 paramAnnotations.push(annotation);
51 }
52 }
53 Reflect.defineMetadata('parameters', paramsAnnotations, fn);
54 return fn;
55 }
56 throw new Error("Only Function or Array is supported in Class definition for key '" + key + "' is '" + stringify(fnOrArray) + "'");
57}
58/**
59 * Provides a way for expressing ES6 classes with parameter annotations in ES5.
60 *
61 * ## Basic Example
62 *
63 * ```
64 * var Greeter = ng.Class({
65 * constructor: function(name) {
66 * this.name = name;
67 * },
68 *
69 * greet: function() {
70 * alert('Hello ' + this.name + '!');
71 * }
72 * });
73 * ```
74 *
75 * is equivalent to ES6:
76 *
77 * ```
78 * class Greeter {
79 * constructor(name) {
80 * this.name = name;
81 * }
82 *
83 * greet() {
84 * alert('Hello ' + this.name + '!');
85 * }
86 * }
87 * ```
88 *
89 * or equivalent to ES5:
90 *
91 * ```
92 * var Greeter = function (name) {
93 * this.name = name;
94 * }
95 *
96 * Greeter.prototype.greet = function () {
97 * alert('Hello ' + this.name + '!');
98 * }
99 * ```
100 *
101 * ### Example with parameter annotations
102 *
103 * ```
104 * var MyService = ng.Class({
105 * constructor: [String, [new Optional(), Service], function(name, myService) {
106 * ...
107 * }]
108 * });
109 * ```
110 *
111 * is equivalent to ES6:
112 *
113 * ```
114 * class MyService {
115 * constructor(name: string, @Optional() myService: Service) {
116 * ...
117 * }
118 * }
119 * ```
120 *
121 * ### Example with inheritance
122 *
123 * ```
124 * var Shape = ng.Class({
125 * constructor: (color) {
126 * this.color = color;
127 * }
128 * });
129 *
130 * var Square = ng.Class({
131 * extends: Shape,
132 * constructor: function(color, size) {
133 * Shape.call(this, color);
134 * this.size = size;
135 * }
136 * });
137 * ```
138 * @suppress {globalThis}
139 * @stable
140 */
141export function Class(clsDef) {
142 var constructor = applyParams(clsDef.hasOwnProperty('constructor') ? clsDef.constructor : undefined, 'constructor');
143 var proto = constructor.prototype;
144 if (clsDef.hasOwnProperty('extends')) {
145 if (typeof clsDef.extends === 'function') {
146 constructor.prototype = proto = Object.create(clsDef.extends.prototype);
147 }
148 else {
149 throw new Error("Class definition 'extends' property must be a constructor function was: " + stringify(clsDef.extends));
150 }
151 }
152 for (var key in clsDef) {
153 if (key !== 'extends' && key !== 'prototype' && clsDef.hasOwnProperty(key)) {
154 proto[key] = applyParams(clsDef[key], key);
155 }
156 }
157 if (this && this.annotations instanceof Array) {
158 Reflect.defineMetadata('annotations', this.annotations, constructor);
159 }
160 var constructorName = constructor['name'];
161 if (!constructorName || constructorName === 'constructor') {
162 constructor['overriddenName'] = "class" + _nextClassId++;
163 }
164 return constructor;
165}
166/**
167 * @suppress {globalThis}
168 */
169export function makeDecorator(name, props, parentClass, chainFn) {
170 var metaCtor = makeMetadataCtor([props]);
171 function DecoratorFactory(objOrType) {
172 if (!(Reflect && Reflect.getOwnMetadata)) {
173 throw 'reflect-metadata shim is required when using class decorators';
174 }
175 if (this instanceof DecoratorFactory) {
176 metaCtor.call(this, objOrType);
177 return this;
178 }
179 var annotationInstance = new DecoratorFactory(objOrType);
180 var chainAnnotation = typeof this === 'function' && Array.isArray(this.annotations) ? this.annotations : [];
181 chainAnnotation.push(annotationInstance);
182 var TypeDecorator = function TypeDecorator(cls) {
183 var annotations = Reflect.getOwnMetadata('annotations', cls) || [];
184 annotations.push(annotationInstance);
185 Reflect.defineMetadata('annotations', annotations, cls);
186 return cls;
187 };
188 TypeDecorator.annotations = chainAnnotation;
189 TypeDecorator.Class = Class;
190 if (chainFn)
191 chainFn(TypeDecorator);
192 return TypeDecorator;
193 }
194 if (parentClass) {
195 DecoratorFactory.prototype = Object.create(parentClass.prototype);
196 }
197 DecoratorFactory.prototype.toString = function () { return "@" + name; };
198 DecoratorFactory.annotationCls = DecoratorFactory;
199 return DecoratorFactory;
200}
201function makeMetadataCtor(props) {
202 return function ctor() {
203 var _this = this;
204 var args = [];
205 for (var _i = 0; _i < arguments.length; _i++) {
206 args[_i] = arguments[_i];
207 }
208 props.forEach(function (prop, i) {
209 var argVal = args[i];
210 if (Array.isArray(prop)) {
211 // plain parameter
212 _this[prop[0]] = argVal === undefined ? prop[1] : argVal;
213 }
214 else {
215 for (var propName in prop) {
216 _this[propName] = argVal && argVal.hasOwnProperty(propName) ? argVal[propName] : prop[propName];
217 }
218 }
219 });
220 };
221}
222export function makeParamDecorator(name, props, parentClass) {
223 var metaCtor = makeMetadataCtor(props);
224 function ParamDecoratorFactory() {
225 var _a;
226 var args = [];
227 for (var _i = 0; _i < arguments.length; _i++) {
228 args[_i] = arguments[_i];
229 }
230 if (this instanceof ParamDecoratorFactory) {
231 metaCtor.apply(this, args);
232 return this;
233 }
234 var annotationInstance = new ((_a = ParamDecoratorFactory).bind.apply(_a, __spreadArrays([void 0], args)))();
235 ParamDecorator.annotation = annotationInstance;
236 return ParamDecorator;
237 function ParamDecorator(cls, unusedKey, index) {
238 var parameters = Reflect.getOwnMetadata('parameters', cls) || [];
239 // there might be gaps if some in between parameters do not have annotations.
240 // we pad with nulls.
241 while (parameters.length <= index) {
242 parameters.push(null);
243 }
244 parameters[index] = parameters[index] || [];
245 parameters[index].push(annotationInstance);
246 Reflect.defineMetadata('parameters', parameters, cls);
247 return cls;
248 }
249 }
250 if (parentClass) {
251 ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
252 }
253 ParamDecoratorFactory.prototype.toString = function () { return "@" + name; };
254 ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
255 return ParamDecoratorFactory;
256}
257export function makePropDecorator(name, props, parentClass) {
258 var metaCtor = makeMetadataCtor(props);
259 function PropDecoratorFactory() {
260 var _a;
261 var args = [];
262 for (var _i = 0; _i < arguments.length; _i++) {
263 args[_i] = arguments[_i];
264 }
265 if (this instanceof PropDecoratorFactory) {
266 metaCtor.apply(this, args);
267 return this;
268 }
269 var decoratorInstance = new ((_a = PropDecoratorFactory).bind.apply(_a, __spreadArrays([void 0], args)))();
270 return function PropDecorator(target, name) {
271 var meta = Reflect.getOwnMetadata('propMetadata', target.constructor) || {};
272 meta[name] = (meta.hasOwnProperty(name) && meta[name]) || [];
273 meta[name].unshift(decoratorInstance);
274 Reflect.defineMetadata('propMetadata', meta, target.constructor);
275 };
276 }
277 if (parentClass) {
278 PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
279 }
280 PropDecoratorFactory.prototype.toString = function () { return "@" + name; };
281 PropDecoratorFactory.annotationCls = PropDecoratorFactory;
282 return PropDecoratorFactory;
283}
284//# sourceMappingURL=decorators.js.map
\No newline at end of file