UNPKG

13.4 kBJavaScriptView Raw
1var toArray = require("./toArray");
2
3var toPropertyKey = require("./toPropertyKey");
4
5function _decorate(decorators, factory, superClass, mixins) {
6 var api = _getDecoratorsApi();
7
8 if (mixins) {
9 for (var i = 0; i < mixins.length; i++) {
10 api = mixins[i](api);
11 }
12 }
13
14 var r = factory(function initialize(O) {
15 api.initializeInstanceElements(O, decorated.elements);
16 }, superClass);
17 var decorated = api.decorateClass(_coalesceClassElements(r.d.map(_createElementDescriptor)), decorators);
18 api.initializeClassElements(r.F, decorated.elements);
19 return api.runClassFinishers(r.F, decorated.finishers);
20}
21
22function _getDecoratorsApi() {
23 _getDecoratorsApi = function _getDecoratorsApi() {
24 return api;
25 };
26
27 var api = {
28 elementsDefinitionOrder: [["method"], ["field"]],
29 initializeInstanceElements: function initializeInstanceElements(O, elements) {
30 ["method", "field"].forEach(function (kind) {
31 elements.forEach(function (element) {
32 if (element.kind === kind && element.placement === "own") {
33 this.defineClassElement(O, element);
34 }
35 }, this);
36 }, this);
37 },
38 initializeClassElements: function initializeClassElements(F, elements) {
39 var proto = F.prototype;
40 ["method", "field"].forEach(function (kind) {
41 elements.forEach(function (element) {
42 var placement = element.placement;
43
44 if (element.kind === kind && (placement === "static" || placement === "prototype")) {
45 var receiver = placement === "static" ? F : proto;
46 this.defineClassElement(receiver, element);
47 }
48 }, this);
49 }, this);
50 },
51 defineClassElement: function defineClassElement(receiver, element) {
52 var descriptor = element.descriptor;
53
54 if (element.kind === "field") {
55 var initializer = element.initializer;
56 descriptor = {
57 enumerable: descriptor.enumerable,
58 writable: descriptor.writable,
59 configurable: descriptor.configurable,
60 value: initializer === void 0 ? void 0 : initializer.call(receiver)
61 };
62 }
63
64 Object.defineProperty(receiver, element.key, descriptor);
65 },
66 decorateClass: function decorateClass(elements, decorators) {
67 var newElements = [];
68 var finishers = [];
69 var placements = {
70 "static": [],
71 prototype: [],
72 own: []
73 };
74 elements.forEach(function (element) {
75 this.addElementPlacement(element, placements);
76 }, this);
77 elements.forEach(function (element) {
78 if (!_hasDecorators(element)) return newElements.push(element);
79 var elementFinishersExtras = this.decorateElement(element, placements);
80 newElements.push(elementFinishersExtras.element);
81 newElements.push.apply(newElements, elementFinishersExtras.extras);
82 finishers.push.apply(finishers, elementFinishersExtras.finishers);
83 }, this);
84
85 if (!decorators) {
86 return {
87 elements: newElements,
88 finishers: finishers
89 };
90 }
91
92 var result = this.decorateConstructor(newElements, decorators);
93 finishers.push.apply(finishers, result.finishers);
94 result.finishers = finishers;
95 return result;
96 },
97 addElementPlacement: function addElementPlacement(element, placements, silent) {
98 var keys = placements[element.placement];
99
100 if (!silent && keys.indexOf(element.key) !== -1) {
101 throw new TypeError("Duplicated element (" + element.key + ")");
102 }
103
104 keys.push(element.key);
105 },
106 decorateElement: function decorateElement(element, placements) {
107 var extras = [];
108 var finishers = [];
109
110 for (var decorators = element.decorators, i = decorators.length - 1; i >= 0; i--) {
111 var keys = placements[element.placement];
112 keys.splice(keys.indexOf(element.key), 1);
113 var elementObject = this.fromElementDescriptor(element);
114 var elementFinisherExtras = this.toElementFinisherExtras((0, decorators[i])(elementObject) || elementObject);
115 element = elementFinisherExtras.element;
116 this.addElementPlacement(element, placements);
117
118 if (elementFinisherExtras.finisher) {
119 finishers.push(elementFinisherExtras.finisher);
120 }
121
122 var newExtras = elementFinisherExtras.extras;
123
124 if (newExtras) {
125 for (var j = 0; j < newExtras.length; j++) {
126 this.addElementPlacement(newExtras[j], placements);
127 }
128
129 extras.push.apply(extras, newExtras);
130 }
131 }
132
133 return {
134 element: element,
135 finishers: finishers,
136 extras: extras
137 };
138 },
139 decorateConstructor: function decorateConstructor(elements, decorators) {
140 var finishers = [];
141
142 for (var i = decorators.length - 1; i >= 0; i--) {
143 var obj = this.fromClassDescriptor(elements);
144 var elementsAndFinisher = this.toClassDescriptor((0, decorators[i])(obj) || obj);
145
146 if (elementsAndFinisher.finisher !== undefined) {
147 finishers.push(elementsAndFinisher.finisher);
148 }
149
150 if (elementsAndFinisher.elements !== undefined) {
151 elements = elementsAndFinisher.elements;
152
153 for (var j = 0; j < elements.length - 1; j++) {
154 for (var k = j + 1; k < elements.length; k++) {
155 if (elements[j].key === elements[k].key && elements[j].placement === elements[k].placement) {
156 throw new TypeError("Duplicated element (" + elements[j].key + ")");
157 }
158 }
159 }
160 }
161 }
162
163 return {
164 elements: elements,
165 finishers: finishers
166 };
167 },
168 fromElementDescriptor: function fromElementDescriptor(element) {
169 var obj = {
170 kind: element.kind,
171 key: element.key,
172 placement: element.placement,
173 descriptor: element.descriptor
174 };
175 var desc = {
176 value: "Descriptor",
177 configurable: true
178 };
179 Object.defineProperty(obj, Symbol.toStringTag, desc);
180 if (element.kind === "field") obj.initializer = element.initializer;
181 return obj;
182 },
183 toElementDescriptors: function toElementDescriptors(elementObjects) {
184 if (elementObjects === undefined) return;
185 return toArray(elementObjects).map(function (elementObject) {
186 var element = this.toElementDescriptor(elementObject);
187 this.disallowProperty(elementObject, "finisher", "An element descriptor");
188 this.disallowProperty(elementObject, "extras", "An element descriptor");
189 return element;
190 }, this);
191 },
192 toElementDescriptor: function toElementDescriptor(elementObject) {
193 var kind = String(elementObject.kind);
194
195 if (kind !== "method" && kind !== "field") {
196 throw new TypeError('An element descriptor\'s .kind property must be either "method" or' + ' "field", but a decorator created an element descriptor with' + ' .kind "' + kind + '"');
197 }
198
199 var key = toPropertyKey(elementObject.key);
200 var placement = String(elementObject.placement);
201
202 if (placement !== "static" && placement !== "prototype" && placement !== "own") {
203 throw new TypeError('An element descriptor\'s .placement property must be one of "static",' + ' "prototype" or "own", but a decorator created an element descriptor' + ' with .placement "' + placement + '"');
204 }
205
206 var descriptor = elementObject.descriptor;
207 this.disallowProperty(elementObject, "elements", "An element descriptor");
208 var element = {
209 kind: kind,
210 key: key,
211 placement: placement,
212 descriptor: Object.assign({}, descriptor)
213 };
214
215 if (kind !== "field") {
216 this.disallowProperty(elementObject, "initializer", "A method descriptor");
217 } else {
218 this.disallowProperty(descriptor, "get", "The property descriptor of a field descriptor");
219 this.disallowProperty(descriptor, "set", "The property descriptor of a field descriptor");
220 this.disallowProperty(descriptor, "value", "The property descriptor of a field descriptor");
221 element.initializer = elementObject.initializer;
222 }
223
224 return element;
225 },
226 toElementFinisherExtras: function toElementFinisherExtras(elementObject) {
227 var element = this.toElementDescriptor(elementObject);
228
229 var finisher = _optionalCallableProperty(elementObject, "finisher");
230
231 var extras = this.toElementDescriptors(elementObject.extras);
232 return {
233 element: element,
234 finisher: finisher,
235 extras: extras
236 };
237 },
238 fromClassDescriptor: function fromClassDescriptor(elements) {
239 var obj = {
240 kind: "class",
241 elements: elements.map(this.fromElementDescriptor, this)
242 };
243 var desc = {
244 value: "Descriptor",
245 configurable: true
246 };
247 Object.defineProperty(obj, Symbol.toStringTag, desc);
248 return obj;
249 },
250 toClassDescriptor: function toClassDescriptor(obj) {
251 var kind = String(obj.kind);
252
253 if (kind !== "class") {
254 throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator' + ' created a class descriptor with .kind "' + kind + '"');
255 }
256
257 this.disallowProperty(obj, "key", "A class descriptor");
258 this.disallowProperty(obj, "placement", "A class descriptor");
259 this.disallowProperty(obj, "descriptor", "A class descriptor");
260 this.disallowProperty(obj, "initializer", "A class descriptor");
261 this.disallowProperty(obj, "extras", "A class descriptor");
262
263 var finisher = _optionalCallableProperty(obj, "finisher");
264
265 var elements = this.toElementDescriptors(obj.elements);
266 return {
267 elements: elements,
268 finisher: finisher
269 };
270 },
271 runClassFinishers: function runClassFinishers(constructor, finishers) {
272 for (var i = 0; i < finishers.length; i++) {
273 var newConstructor = (0, finishers[i])(constructor);
274
275 if (newConstructor !== undefined) {
276 if (typeof newConstructor !== "function") {
277 throw new TypeError("Finishers must return a constructor.");
278 }
279
280 constructor = newConstructor;
281 }
282 }
283
284 return constructor;
285 },
286 disallowProperty: function disallowProperty(obj, name, objectType) {
287 if (obj[name] !== undefined) {
288 throw new TypeError(objectType + " can't have a ." + name + " property.");
289 }
290 }
291 };
292 return api;
293}
294
295function _createElementDescriptor(def) {
296 var key = toPropertyKey(def.key);
297 var descriptor;
298
299 if (def.kind === "method") {
300 descriptor = {
301 value: def.value,
302 writable: true,
303 configurable: true,
304 enumerable: false
305 };
306 } else if (def.kind === "get") {
307 descriptor = {
308 get: def.value,
309 configurable: true,
310 enumerable: false
311 };
312 } else if (def.kind === "set") {
313 descriptor = {
314 set: def.value,
315 configurable: true,
316 enumerable: false
317 };
318 } else if (def.kind === "field") {
319 descriptor = {
320 configurable: true,
321 writable: true,
322 enumerable: true
323 };
324 }
325
326 var element = {
327 kind: def.kind === "field" ? "field" : "method",
328 key: key,
329 placement: def["static"] ? "static" : def.kind === "field" ? "own" : "prototype",
330 descriptor: descriptor
331 };
332 if (def.decorators) element.decorators = def.decorators;
333 if (def.kind === "field") element.initializer = def.value;
334 return element;
335}
336
337function _coalesceGetterSetter(element, other) {
338 if (element.descriptor.get !== undefined) {
339 other.descriptor.get = element.descriptor.get;
340 } else {
341 other.descriptor.set = element.descriptor.set;
342 }
343}
344
345function _coalesceClassElements(elements) {
346 var newElements = [];
347
348 var isSameElement = function isSameElement(other) {
349 return other.kind === "method" && other.key === element.key && other.placement === element.placement;
350 };
351
352 for (var i = 0; i < elements.length; i++) {
353 var element = elements[i];
354 var other;
355
356 if (element.kind === "method" && (other = newElements.find(isSameElement))) {
357 if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) {
358 if (_hasDecorators(element) || _hasDecorators(other)) {
359 throw new ReferenceError("Duplicated methods (" + element.key + ") can't be decorated.");
360 }
361
362 other.descriptor = element.descriptor;
363 } else {
364 if (_hasDecorators(element)) {
365 if (_hasDecorators(other)) {
366 throw new ReferenceError("Decorators can't be placed on different accessors with for " + "the same property (" + element.key + ").");
367 }
368
369 other.decorators = element.decorators;
370 }
371
372 _coalesceGetterSetter(element, other);
373 }
374 } else {
375 newElements.push(element);
376 }
377 }
378
379 return newElements;
380}
381
382function _hasDecorators(element) {
383 return element.decorators && element.decorators.length;
384}
385
386function _isDataDescriptor(desc) {
387 return desc !== undefined && !(desc.value === undefined && desc.writable === undefined);
388}
389
390function _optionalCallableProperty(obj, name) {
391 var value = obj[name];
392
393 if (value !== undefined && typeof value !== "function") {
394 throw new TypeError("Expected '" + name + "' to be a function");
395 }
396
397 return value;
398}
399
400module.exports = _decorate;
\No newline at end of file