This repository was archived by the owner on Jun 21, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathcompose.js
More file actions
109 lines (90 loc) · 3.84 KB
/
compose.js
File metadata and controls
109 lines (90 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import assign from 'lodash/assign';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import mergeWith from 'lodash/mergeWith';
//import compose from 'stamp-specification';
import {
parseDesc,
wrapMethods,
} from './';
const isDescriptor = isObject;
const merge = (dst, src) => mergeWith(dst, src, (dstValue, srcValue) => {
if (Array.isArray(dstValue)) {
if (Array.isArray(srcValue)) return dstValue.concat(srcValue);
if (isObject(srcValue)) return merge({}, srcValue);
}
return undefined;
});
/**
* Given a description object, return a stamp aka composable.
*
* (desc?: SpecDesc) => Stamp
*/
function createStamp (specDesc = {}, composeFunction) {
const Component = (options, ...args) => {
let instance = Object.create(specDesc.methods || {});
merge(instance, specDesc.deepProperties);
assign(instance, specDesc.properties, specDesc.configuration);
Object.defineProperties(instance, specDesc.propertyDescriptors || {});
if (specDesc.initializers) {
specDesc.initializers.forEach(initializer => {
const result = initializer.call(instance, options,
{ instance, stamp: Component, args: [options].concat(args) });
typeof result !== 'undefined' && (instance = result);
});
}
return instance;
};
merge(Component, specDesc.staticDeepProperties);
assign(Component, specDesc.staticProperties);
Object.defineProperties(Component, specDesc.staticPropertyDescriptors || {});
!Component.displayName && (Component.displayName = 'Component');
const composeImplementation = isFunction(Component.compose) ? Component.compose : composeFunction;
Component.compose = function () {
return composeImplementation.apply(this, arguments);
};
assign(Component.compose, specDesc);
return Component;
}
/**
* Mutates the dstDescriptor by merging the srcComposable data into it.
* @param {object} dstDescriptor The descriptor object to merge into.
* @param {object} [srcComposable] The composable (either descriptor or stamp) to merge data form.
* @returns {object} Returns the dstDescriptor argument.
*/
function mergeComposable (dstDescriptor, srcComposable) {
const srcDescriptor = parseDesc(srcComposable && srcComposable.compose || srcComposable);
if (!isDescriptor(srcDescriptor)) return dstDescriptor;
const combineProperty = (propName, action) => {
if (!isObject(srcDescriptor[propName])) return;
if (!isObject(dstDescriptor[propName])) dstDescriptor[propName] = {};
action(dstDescriptor[propName], srcDescriptor[propName]);
};
console.log(dstDescriptor.methods);
combineProperty('methods', wrapMethods); // Wrap React lifecycle methods
//console.log(dstDescriptor.methods);
combineProperty('properties', assign);
combineProperty('deepProperties', merge);
combineProperty('propertyDescriptors', assign);
combineProperty('staticProperties', assign);
combineProperty('staticDeepProperties', merge);
combineProperty('staticPropertyDescriptors', assign);
combineProperty('configuration', assign);
combineProperty('deepConfiguration', merge);
if (Array.isArray(srcDescriptor.initializers)) {
if (!Array.isArray(dstDescriptor.initializers)) dstDescriptor.initializers = [];
dstDescriptor.initializers.push.apply(dstDescriptor.initializers, srcDescriptor.initializers.filter(isFunction));
}
//console.log(dstDescriptor);
return dstDescriptor;
}
/**
* Given the list of composables (stamp descriptors and stamps) returns a new stamp (composable factory function).
* @param {...(object|Function)} [composables] The list of composables.
* @returns {Function} A new stamp (aka composable factory function).
*/
export default function compose (...composables) {
const descriptor = [this].concat(composables).filter(isObject).reduce(mergeComposable, {});
//console.log(descriptor);
return createStamp(descriptor, compose);
}