|
1 |
| -import { assignInWith, set, memoize } from 'lodash'; |
| 1 | +import { set } from 'lodash'; |
2 | 2 |
|
3 | 3 | const aggregator = (paths: any, object: any) => {
|
4 | 4 | return paths.reduce((delta: any, path: any) => {
|
5 | 5 | return set(delta, path, get(object, path));
|
6 | 6 | }, {});
|
7 | 7 | };
|
8 | 8 |
|
9 |
| -// function memoize(a: any): any { |
10 |
| -// const f: { [k: string]: any } = () => {}; |
11 |
| -// f.cache = {}; |
12 |
| -// return f; |
13 |
| -// } |
14 |
| -// function assignInWith(a: any, b: any, c?: any) {} |
| 9 | +const memoize = (func: any, resolver?: any) => { |
| 10 | + if (typeof func !== 'function' || (resolver != null && typeof resolver !== 'function')) { |
| 11 | + throw new TypeError('Expected a function'); |
| 12 | + } |
| 13 | + const memoized: any = function(...args: any[]) { |
| 14 | + const key = resolver ? resolver.apply(this, args) : args[0]; |
| 15 | + const cache = memoized.cache; |
| 16 | + |
| 17 | + if (cache.has(key)) { |
| 18 | + return cache.get(key); |
| 19 | + } |
| 20 | + const result = func.apply(this, args); |
| 21 | + memoized.cache = cache.set(key, result) || cache; |
| 22 | + return result; |
| 23 | + }; |
| 24 | + memoized.cache = new Map(); |
| 25 | + return memoized; |
| 26 | +}; |
| 27 | + |
| 28 | +function assignInWith(target: any, source: any, customizer: (targetValue: any, sourceValue: any) => any) { |
| 29 | + Object.entries(source).forEach(([field, value]) => { |
| 30 | + target[field] = customizer(target[field], value); |
| 31 | + }); |
| 32 | + return target; |
| 33 | +} |
15 | 34 | // // function set(a: any, b: any, c?: any) {}
|
16 | 35 |
|
17 | 36 | function isUndefined(value: any) {
|
@@ -83,14 +102,14 @@ function transformValuesFromObject(object: any, schema: Schema, items: any[], co
|
83 | 102 | return { [targetProperty]: aggregator(action, object) };
|
84 | 103 | } else if (isObject(action)) {
|
85 | 104 | // Action<Object>: a path and a function: [ destination : { path: 'source', fn:(fieldValue, items) }]
|
86 |
| - let value; |
87 |
| - if (Array.isArray(action.path)) { |
88 |
| - value = aggregator(action.path, object); |
89 |
| - } else if (isString(action.path)) { |
90 |
| - value = get(object, action.path); |
91 |
| - } |
92 | 105 | let result;
|
93 | 106 | try {
|
| 107 | + let value; |
| 108 | + if (Array.isArray(action.path)) { |
| 109 | + value = aggregator(action.path, object); |
| 110 | + } else if (isString(action.path)) { |
| 111 | + value = get(object, action.path); |
| 112 | + } |
94 | 113 | result = action.fn.call(undefined, value, object, items, constructed);
|
95 | 114 | } catch (e) {
|
96 | 115 | e.message = `Unable to set target property [${targetProperty}].
|
@@ -168,7 +187,16 @@ Morphism = (schema: Schema, items?: any, type?: any): typeof type => {
|
168 | 187 |
|
169 | 188 | const customizer = (data: any) => {
|
170 | 189 | const undefinedValueCheck = (destination: any, source: any) => {
|
171 |
| - if (isUndefined(source)) return destination; |
| 190 | + // Take the Object class value property if the incoming property is undefined |
| 191 | + if (isUndefined(source)) { |
| 192 | + if (!isUndefined(destination)) { |
| 193 | + return destination; |
| 194 | + } else { |
| 195 | + return; // No Black Magic Fuckery here, if the source and the destination are undefined, we don't do anything |
| 196 | + } |
| 197 | + } else { |
| 198 | + return source; |
| 199 | + } |
172 | 200 | };
|
173 | 201 | return assignInWith(constructed, data, undefinedValueCheck);
|
174 | 202 | };
|
@@ -288,3 +316,10 @@ Morphism.mappers = MorphismRegistry.mappers;
|
288 | 316 | /** API */
|
289 | 317 |
|
290 | 318 | export default Morphism;
|
| 319 | + |
| 320 | +class UndefinedFinalValue extends Error { |
| 321 | + constructor(message?: string) { |
| 322 | + super(message); // 'Error' breaks prototype chain here |
| 323 | + Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain |
| 324 | + } |
| 325 | +} |
0 commit comments