1
1
import { assignInWith , set , get , mapValues , isFunction , isString , zipObject , memoize } from 'lodash' ;
2
2
3
3
const aggregator = ( paths : any , object : any ) => {
4
- return paths . reduce ( ( delta : any , path : any ) => {
5
- return set ( delta , path , get ( object , path ) ) ;
6
- } , { } ) ;
4
+ return paths . reduce ( ( delta : any , path : any ) => {
5
+ return set ( delta , path , get ( object , path ) ) ;
6
+ } , { } ) ;
7
7
} ;
8
8
9
9
function isUndefined ( value : any ) {
10
- return value === undefined ;
10
+ return value === undefined ;
11
11
}
12
12
13
13
function isObject ( value : any ) {
14
- const type = typeof value ;
15
- return value != null && ( type === 'object' || type === 'function' ) ;
14
+ const type = typeof value ;
15
+ return value != null && ( type === 'object' || type === 'function' ) ;
16
16
}
17
17
18
18
/**
@@ -24,64 +24,64 @@ function isObject(value: any) {
24
24
* @param { } constructed Created tranformed object of a given type
25
25
*/
26
26
function transformValuesFromObject ( object : any , schema : any , items : any [ ] , constructed : any ) {
27
- return mapValues ( schema , ( action , targetProperty ) => {
28
- // iterate on every action of the schema
29
- if ( isString ( action ) ) {
30
- // Action<String>: string path => [ target: 'source' ]
31
- return get ( object , action ) ;
32
- } else if ( isFunction ( action ) ) {
33
- // Action<Function>: Free Computin - a callback called with the current object and collection [ destination: (object) => {...} ]
34
- return action . call ( undefined , object , items , constructed ) ;
35
- } else if ( Array . isArray ( action ) ) {
36
- // Action<Array>: Aggregator - string paths => : [ destination: ['source1', 'source2', 'source3'] ]
37
- return aggregator ( action , object ) ;
38
- } else if ( isObject ( action ) ) {
39
- // Action<Object>: a path and a function: [ destination : { path: 'source', fn:(fieldValue, items) }]
40
- let value ;
41
- if ( Array . isArray ( action . path ) ) {
42
- value = aggregator ( action . path , object ) ;
43
- } else if ( isString ( action . path ) ) {
44
- value = get ( object , action . path ) ;
45
- }
46
- let result ;
47
- try {
48
- result = action . fn . call ( undefined , value , object , items , constructed ) ;
49
- } catch ( e ) {
50
- e . message = `Unable to set target property [${ targetProperty } ].
27
+ return mapValues ( schema , ( action , targetProperty ) => {
28
+ // iterate on every action of the schema
29
+ if ( isString ( action ) ) {
30
+ // Action<String>: string path => [ target: 'source' ]
31
+ return get ( object , action ) ;
32
+ } else if ( isFunction ( action ) ) {
33
+ // Action<Function>: Free Computin - a callback called with the current object and collection [ destination: (object) => {...} ]
34
+ return action . call ( undefined , object , items , constructed ) ;
35
+ } else if ( Array . isArray ( action ) ) {
36
+ // Action<Array>: Aggregator - string paths => : [ destination: ['source1', 'source2', 'source3'] ]
37
+ return aggregator ( action , object ) ;
38
+ } else if ( isObject ( action ) ) {
39
+ // Action<Object>: a path and a function: [ destination : { path: 'source', fn:(fieldValue, items) }]
40
+ let value ;
41
+ if ( Array . isArray ( action . path ) ) {
42
+ value = aggregator ( action . path , object ) ;
43
+ } else if ( isString ( action . path ) ) {
44
+ value = get ( object , action . path ) ;
45
+ }
46
+ let result ;
47
+ try {
48
+ result = action . fn . call ( undefined , value , object , items , constructed ) ;
49
+ } catch ( e ) {
50
+ e . message = `Unable to set target property [${ targetProperty } ].
51
51
\n An error occured when applying [${ action . fn . name } ] on property [${ action . path } ]
52
52
\n Internal error: ${ e . message } ` ;
53
- throw e ;
54
- }
53
+ throw e ;
54
+ }
55
55
56
- return result ;
57
- }
58
- } ) ;
56
+ return result ;
57
+ }
58
+ } ) ;
59
59
}
60
60
61
61
const transformItems = ( schema : any , customizer : any , constructed : any ) => ( input : any ) => {
62
- if ( ! input ) {
63
- return input ;
64
- }
65
- if ( Array . isArray ( input ) ) {
66
- return input . map ( obj => {
67
- if ( customizer ) {
68
- return customizer ( transformValuesFromObject ( obj , schema , input , constructed ) ) ;
69
- } else {
70
- return transformValuesFromObject ( obj , schema , input , null ) ;
71
- }
72
- } ) ;
73
- } else {
74
- const object = input ;
75
- if ( customizer ) {
76
- return customizer ( transformValuesFromObject ( object , schema , [ object ] , constructed ) ) ;
77
- } else {
78
- return transformValuesFromObject ( object , schema , [ object ] , null ) ;
79
- }
80
- }
62
+ if ( ! input ) {
63
+ return input ;
64
+ }
65
+ if ( Array . isArray ( input ) ) {
66
+ return input . map ( obj => {
67
+ if ( customizer ) {
68
+ return customizer ( transformValuesFromObject ( obj , schema , input , constructed ) ) ;
69
+ } else {
70
+ return transformValuesFromObject ( obj , schema , input , null ) ;
71
+ }
72
+ } ) ;
73
+ } else {
74
+ const object = input ;
75
+ if ( customizer ) {
76
+ return customizer ( transformValuesFromObject ( object , schema , [ object ] , constructed ) ) ;
77
+ } else {
78
+ return transformValuesFromObject ( object , schema , [ object ] , null ) ;
79
+ }
80
+ }
81
81
} ;
82
82
let Morphism : {
83
- ( schema : any , items ?: any , type ?: any ) : any ;
84
- [ key : string ] : any ;
83
+ ( schema : any , items ?: any , type ?: any ) : any ;
84
+ [ key : string ] : any ;
85
85
} ;
86
86
/**
87
87
* Object Literals Mapper (Curried Function)
@@ -108,40 +108,40 @@ let Morphism: {
108
108
* const output = Morphism(schema, input);
109
109
*/
110
110
Morphism = ( schema : any , items : any , type : any ) => {
111
- let constructed : any = null ;
112
-
113
- if ( type ) {
114
- constructed = new type ( ) ;
115
- }
116
-
117
- const customizer = ( data : any ) => {
118
- const undefinedValueCheck = ( destination : any , source : any ) => {
119
- if ( isUndefined ( source ) ) return destination ;
120
- } ;
121
- return assignInWith ( constructed , data , undefinedValueCheck ) ;
122
- } ;
123
- if ( items === undefined && type === undefined ) {
124
- return transformItems ( schema , null , null ) ;
125
- } else if ( schema && items && type ) {
126
- return transformItems ( schema , customizer , constructed ) ( items ) ;
127
- } else if ( schema && items ) {
128
- return transformItems ( schema , null , null ) ( items ) ;
129
- } else if ( type && items ) {
130
- let finalSchema = getSchemaForType ( type , schema ) ;
131
- return transformItems ( finalSchema , customizer , constructed ) ( items ) ;
132
- } else if ( type ) {
133
- let finalSchema = getSchemaForType ( type , schema ) ;
134
- return ( futureInput : any ) => {
135
- return transformItems ( finalSchema , customizer , constructed ) ( futureInput ) ;
136
- } ;
137
- }
111
+ let constructed : any = null ;
112
+
113
+ if ( type ) {
114
+ constructed = new type ( ) ;
115
+ }
116
+
117
+ const customizer = ( data : any ) => {
118
+ const undefinedValueCheck = ( destination : any , source : any ) => {
119
+ if ( isUndefined ( source ) ) return destination ;
120
+ } ;
121
+ return assignInWith ( constructed , data , undefinedValueCheck ) ;
122
+ } ;
123
+ if ( items === undefined && type === undefined ) {
124
+ return transformItems ( schema , null , null ) ;
125
+ } else if ( schema && items && type ) {
126
+ return transformItems ( schema , customizer , constructed ) ( items ) ;
127
+ } else if ( schema && items ) {
128
+ return transformItems ( schema , null , null ) ( items ) ;
129
+ } else if ( type && items ) {
130
+ let finalSchema = getSchemaForType ( type , schema ) ;
131
+ return transformItems ( finalSchema , customizer , constructed ) ( items ) ;
132
+ } else if ( type ) {
133
+ let finalSchema = getSchemaForType ( type , schema ) ;
134
+ return ( futureInput : any ) => {
135
+ return transformItems ( finalSchema , customizer , constructed ) ( futureInput ) ;
136
+ } ;
137
+ }
138
138
} ;
139
139
140
140
const getSchemaForType = ( type : any , baseSchema : any ) => {
141
- let typeFields = Object . keys ( new type ( ) ) ;
142
- let defaultSchema = zipObject ( typeFields , typeFields ) ;
143
- let finalSchema = Object . assign ( defaultSchema , baseSchema ) ;
144
- return finalSchema ;
141
+ let typeFields = Object . keys ( new type ( ) ) ;
142
+ let defaultSchema = zipObject ( typeFields , typeFields ) ;
143
+ let finalSchema = Object . assign ( defaultSchema , baseSchema ) ;
144
+ return finalSchema ;
145
145
} ;
146
146
/**
147
147
* Type Mapper Factory
@@ -150,80 +150,80 @@ const getSchemaForType = (type: any, baseSchema: any) => {
150
150
* @param {Object | Array } items Object or Collection to be mapped
151
151
*/
152
152
function factory ( type : any , schema ?: any , items ?: any ) {
153
- let finalSchema = getSchemaForType ( type , schema ) ;
153
+ let finalSchema = getSchemaForType ( type , schema ) ;
154
154
155
- return Morphism ( finalSchema , items , type ) ;
155
+ return Morphism ( finalSchema , items , type ) ;
156
156
}
157
157
158
158
// memoize.Cache = WeakMap;
159
159
const _registry = memoize ( factory ) ;
160
160
161
161
class MorphismRegistry {
162
- /**
163
- * Register a mapping schema for a Type aimed to be used later
164
- *
165
- * @param {Type } type Class Type to be registered
166
- * @param {Object } schema Configuration of how properties are computed from the source
167
- * @param {Object | Array } items Object or Collection to be mapped
168
- * @returns {Function<T> } Mapper function to be used against a data source
169
- */
170
- static register ( type : any , schema ?: any ) {
171
- if ( ! type && ! schema ) {
172
- throw new Error ( 'type paramater is required when register a mapping' ) ;
173
- } else if ( MorphismRegistry . exists ( type ) ) {
174
- throw new Error ( `A mapper for ${ type . name } has already been registered` ) ;
175
- }
176
- /**
177
- * @param {Object | Array } items Object or Collection to be mapped
178
- */
179
- return _registry ( type , schema ) ; // Store the result of the executed function in a WeakMap cache object
180
- }
181
- /**
182
- *
183
- * @param {Type } type
184
- * @param {Array|Object } data
185
- * @returns {Array<type>|Object }
186
- * @example
187
- *
188
- * let collectionOfType = Morphism.map(Type, [object1, object2, object3]);
189
- */
190
- static map ( type : any , data : any ) {
191
- if ( ! MorphismRegistry . exists ( type ) ) {
192
- const mapper = MorphismRegistry . register ( type ) ;
193
- if ( data === undefined ) {
194
- return mapper ;
195
- }
196
- }
197
- return _registry ( type ) ( data ) ;
198
- }
199
-
200
- static getMapper ( type : any ) {
201
- return _registry . cache . get ( type ) ;
202
- }
203
-
204
- static get mappers ( ) {
205
- return _registry . cache ;
206
- }
207
-
208
- static exists ( type : any ) {
209
- return _registry . cache . has ( type ) ;
210
- }
211
-
212
- static setMapper ( type : any , schema : any ) {
213
- if ( ! schema ) {
214
- throw new Error ( `The schema must be an Object. Found ${ schema } ` ) ;
215
- } else if ( ! MorphismRegistry . exists ( type ) ) {
216
- throw new Error ( `The type ${ type . name } is not registered. Register it using \`Mophism.register(${ type . name } , schema)\`` ) ;
217
- } else {
218
- let fn = factory ( type , schema ) ;
219
- _registry . cache . set ( type , fn ) ;
220
- return _registry ( type ) ;
221
- }
222
- }
223
-
224
- static deleteMapper ( type : any ) {
225
- return _registry . cache . delete ( type ) ;
226
- }
162
+ /**
163
+ * Register a mapping schema for a Type aimed to be used later
164
+ *
165
+ * @param {Type } type Class Type to be registered
166
+ * @param {Object } schema Configuration of how properties are computed from the source
167
+ * @param {Object | Array } items Object or Collection to be mapped
168
+ * @returns {Function<T> } Mapper function to be used against a data source
169
+ */
170
+ static register ( type : any , schema ?: any ) {
171
+ if ( ! type && ! schema ) {
172
+ throw new Error ( 'type paramater is required when register a mapping' ) ;
173
+ } else if ( MorphismRegistry . exists ( type ) ) {
174
+ throw new Error ( `A mapper for ${ type . name } has already been registered` ) ;
175
+ }
176
+ /**
177
+ * @param {Object | Array } items Object or Collection to be mapped
178
+ */
179
+ return _registry ( type , schema ) ; // Store the result of the executed function in a WeakMap cache object
180
+ }
181
+ /**
182
+ *
183
+ * @param {Type } type
184
+ * @param {Array|Object } data
185
+ * @returns {Array<type>|Object }
186
+ * @example
187
+ *
188
+ * let collectionOfType = Morphism.map(Type, [object1, object2, object3]);
189
+ */
190
+ static map ( type : any , data : any ) {
191
+ if ( ! MorphismRegistry . exists ( type ) ) {
192
+ const mapper = MorphismRegistry . register ( type ) ;
193
+ if ( data === undefined ) {
194
+ return mapper ;
195
+ }
196
+ }
197
+ return _registry ( type ) ( data ) ;
198
+ }
199
+
200
+ static getMapper ( type : any ) {
201
+ return _registry . cache . get ( type ) ;
202
+ }
203
+
204
+ static get mappers ( ) {
205
+ return _registry . cache ;
206
+ }
207
+
208
+ static exists ( type : any ) {
209
+ return _registry . cache . has ( type ) ;
210
+ }
211
+
212
+ static setMapper ( type : any , schema : any ) {
213
+ if ( ! schema ) {
214
+ throw new Error ( `The schema must be an Object. Found ${ schema } ` ) ;
215
+ } else if ( ! MorphismRegistry . exists ( type ) ) {
216
+ throw new Error ( `The type ${ type . name } is not registered. Register it using \`Mophism.register(${ type . name } , schema)\`` ) ;
217
+ } else {
218
+ let fn = factory ( type , schema ) ;
219
+ _registry . cache . set ( type , fn ) ;
220
+ return _registry ( type ) ;
221
+ }
222
+ }
223
+
224
+ static deleteMapper ( type : any ) {
225
+ return _registry . cache . delete ( type ) ;
226
+ }
227
227
}
228
228
229
229
/** API */
0 commit comments