UNPKG

10.7 kBJavaScriptView Raw
1import * as _ from 'lodash';
2import { CLASSNAME } from 'typescript-class-helpers/browser/classname';
3import { SYMBOL } from 'typescript-class-helpers/browser/symbols';
4import { Helpers } from './helpers';
5import { walk } from 'lodash-walk-object/browser';
6import { CLASS } from 'typescript-class-helpers/browser';
7import { Helpers as HelpersLog } from 'ng2-logger/browser';
8export var Mapping;
9(function (Mapping) {
10 function decode(json, autodetect = false) {
11 HelpersLog.simulateBrowser = true;
12 // console.log('DECODE isBrowser', HelpersLog.isBrowser)
13 if (_.isUndefined(json)) {
14 return undefined;
15 }
16 let mapping = decodeFromDecorator(_.isArray(json) ? _.first(json) : json, !autodetect);
17 if (autodetect) {
18 mapping = _.merge(getMappingNaive(json), mapping);
19 }
20 HelpersLog.simulateBrowser = false;
21 return mapping;
22 }
23 Mapping.decode = decode;
24 function encode(json, mapping, circular = []) {
25 if (_.isString(json) || _.isBoolean(json) || _.isNumber(json)) {
26 return json;
27 }
28 if (mapping['']) {
29 const decoratorMapping = getModelsMapping(CLASSNAME.getClassBy(mapping['']));
30 mapping = _.merge(mapping, decoratorMapping);
31 }
32 let res;
33 if (_.isArray(circular) && circular.length > 0) {
34 res = setMappingCirc(json, mapping, circular);
35 }
36 else {
37 res = setMapping(json, mapping);
38 }
39 return res;
40 }
41 Mapping.encode = encode;
42 function decodeFromDecorator(json, production = false) {
43 const entityClass = CLASS.getFromObject(json);
44 const mappings = getModelsMapping(entityClass);
45 return mappings;
46 }
47 function getModelsMapping(entity) {
48 if (!_.isFunction(entity) || entity === Object) {
49 return {};
50 }
51 const className = CLASSNAME.getClassName(entity);
52 // console.log(`getMaping for: '${className}' `)
53 let enityOWnMapping = _.isArray(entity[SYMBOL.MODELS_MAPPING]) ?
54 entity[SYMBOL.MODELS_MAPPING] : [{ '': className }];
55 let res = {};
56 let parents = enityOWnMapping
57 .filter(m => !_.isUndefined(m['']) && m[''] !== className)
58 .map(m => m['']);
59 enityOWnMapping.reverse().forEach(m => {
60 m = _.cloneDeep(m);
61 // console.log(`'${className}' m:`, m)
62 Object.keys(m).forEach(key => {
63 const v = m[key];
64 const isArr = _.isArray(v);
65 const model = isArr ? _.first(v) : v;
66 if (parents.includes(model)) {
67 m[key] = isArr ? [className] : className;
68 }
69 });
70 res = _.merge(res, m);
71 });
72 res[''] = className;
73 // console.log(`mapping for ${className} : ${JSON.stringify(res)}`)
74 return res;
75 }
76 Mapping.getModelsMapping = getModelsMapping;
77 function add(o, path, mapping = {}) {
78 if (!o || Array.isArray(o) || typeof o !== 'object')
79 return;
80 const objectClassName = CLASSNAME.getClassName(Object.getPrototypeOf(o).constructor);
81 const resolveClass = CLASSNAME.getClassBy(objectClassName);
82 if (!resolveClass) {
83 if (objectClassName !== 'Object') {
84 if (Helpers.isBrowser) {
85 console.error(`Cannot resolve class: ${objectClassName} while mapping.`);
86 }
87 }
88 return;
89 }
90 if (!mapping[path])
91 mapping[path] = CLASSNAME.getClassName(resolveClass);
92 ;
93 }
94 /**
95 * USE ONLY IN DEVELOPMENT
96 * @param c
97 * @param path
98 * @param mapping
99 * @param level
100 */
101 function getMappingNaive(c, path = '', mapping = {}, level = 0) {
102 if (Array.isArray(c)) {
103 c.forEach(c => getMappingNaive(c, path, mapping, level));
104 return mapping;
105 }
106 if (++level === 16)
107 return;
108 add(c, path, mapping);
109 for (var p in c) {
110 if (c.hasOwnProperty(p)) {
111 const v = c[p];
112 if (Array.isArray(v) && v.length > 0) { // reducer as impovement
113 v.forEach((elem, i) => {
114 // const currentPaht = [`path[${i}]`, p].filter(c => c.trim() != '').join('.');
115 const currentPaht = [path, p].filter(c => c.trim() != '').join('.');
116 getMappingNaive(elem, currentPaht, mapping, level);
117 });
118 }
119 else if (typeof v === 'object') {
120 const currentPaht = [path, p].filter(c => c.trim() != '').join('.');
121 add(v, currentPaht, mapping);
122 getMappingNaive(v, currentPaht, mapping, level);
123 }
124 }
125 }
126 return mapping;
127 }
128 function getMappingPathFrom(pathLodhas) {
129 if (!_.isString(pathLodhas)) {
130 return void 0;
131 }
132 const regex = /\[([0-9a-zA-Z]|\'|\")*\]/g;
133 pathLodhas = pathLodhas
134 .replace(regex, '')
135 .replace('..', '.');
136 if (pathLodhas.startsWith('.')) {
137 pathLodhas = pathLodhas.slice(1);
138 }
139 return pathLodhas;
140 }
141 function setMappingCirc(json, mapping = {}, circular = []) {
142 const mainClassFn = !_.isArray(json) && CLASS.getBy(mapping['']);
143 // console.log(mapping)
144 walk.Object(json, (v, lodashPath, changeValue) => {
145 if (!_.isUndefined(v) && !_.isNull(v)) {
146 const mappingPath = getMappingPathFrom(lodashPath);
147 if (!_.isUndefined(mapping[mappingPath])) {
148 const isArray = _.isArray(mapping[mappingPath]);
149 if (!isArray) {
150 const className = isArray ? _.first(mapping[mappingPath]) : mapping[mappingPath];
151 const classFN = CLASS.getBy(className);
152 if (_.isFunction(classFN)) {
153 // console.log(`mapping: '${mappingPath}', lp: '${lodashPath}' class: '${className}' , set `, v.location)
154 changeValue(_.merge(new classFN(), v));
155 }
156 }
157 }
158 }
159 });
160 circular.forEach(c => {
161 const ref = _.get(json, c.circuralTargetPath);
162 _.set(json, c.pathToObj, ref);
163 });
164 if (_.isFunction(mainClassFn)) {
165 json = _.merge(new mainClassFn(), json);
166 }
167 return json;
168 }
169 function setMapping(json, mapping = {}) {
170 // console.log('mapping', mapping)
171 if (Array.isArray(json)) {
172 return json.map(j => {
173 return setMapping(j, mapping);
174 });
175 }
176 const mainClassFn = CLASS.getBy(mapping['']);
177 for (const key in json) {
178 if (json.hasOwnProperty(key)) {
179 // if (mainClassFn && mainClassFn.name === 'Project') {
180 // // console.log(`OWn property: "${key}"`)
181 // }
182 if (_.isArray(json[key])) {
183 json[key] = json[key].map(arrObj => {
184 const objMapping = getModelsMapping(CLASS.getBy(mapping[key]));
185 return setMapping(arrObj, objMapping);
186 });
187 }
188 else if (_.isObject(json[key])) {
189 const objMapping = getModelsMapping(CLASS.getBy(mapping[key]));
190 json[key] = setMapping(json[key], objMapping);
191 }
192 }
193 // else {
194 // if (mainClassFn && mainClassFn.name === 'Project') {
195 // // console.log(`Not own property: "${key}"`)
196 // }
197 // }
198 }
199 Object
200 .keys(mapping)
201 .filter(key => key !== '' && key.split('.').length >= 2)
202 .forEach(lodasPath => {
203 // console.log(`Loadsh path: ${lodasPath}`)
204 const objMapping = getModelsMapping(CLASS.getBy(mapping[lodasPath]));
205 const input = _.get(json, lodasPath);
206 if (!_.isUndefined(input)) {
207 const res = setMapping(input, objMapping);
208 _.set(json, lodasPath, res);
209 }
210 });
211 if (!mainClassFn) {
212 return json;
213 }
214 return _.merge(new mainClassFn(), json);
215 }
216 function DefaultModelWithMapping(defaultModelValues, mapping) {
217 return function (target) {
218 if (!_.isArray(target[SYMBOL.MODELS_MAPPING])) {
219 target[SYMBOL.MODELS_MAPPING] = [];
220 }
221 target[SYMBOL.MODELS_MAPPING].push({ '': CLASSNAME.getClassName(target) });
222 if (_.isObject(mapping)) {
223 target[SYMBOL.MODELS_MAPPING] = target[SYMBOL.MODELS_MAPPING].concat(mapping);
224 Object.keys(mapping)
225 .forEach(key => {
226 const v = mapping;
227 if (_.isUndefined(v) || _.isFunction(v)) {
228 throw `
229
230
231 Class: '${target.name}'
232[ng2rest] Bad mapping value for path: ${key} , please use type: <string> or [<string>]
233`;
234 }
235 });
236 }
237 if (_.isObject(defaultModelValues)) {
238 const toMerge = {};
239 const describedTarget = CLASS.describeProperites(target);
240 // console.log(`describedTarget: ${describedTarget} for ${target.name}`)
241 describedTarget.forEach(propDefInConstr => {
242 if (defaultModelValues[propDefInConstr]) {
243 console.warn(`
244
245 CONFLICT: default value for property: "${propDefInConstr}"
246 in class "${target.name}" already defined as typescript
247 default class proprty value.
248
249 `);
250 }
251 else {
252 toMerge[propDefInConstr] = null; // TODO from toString I can't know that
253 }
254 });
255 // console.log(`merge "${JSON.stringify(target.prototype)}" with "${JSON.stringify(defaultModelValues)}"`)
256 target[SYMBOL.DEFAULT_MODEL] = _.merge(toMerge, defaultModelValues);
257 _.merge(target.prototype, target[SYMBOL.DEFAULT_MODEL]);
258 // console.log(`DEFAULT VALUE MERGE for ${target.name}`)
259 }
260 };
261 }
262 Mapping.DefaultModelWithMapping = DefaultModelWithMapping;
263})(Mapping || (Mapping = {}));
264//# sourceMappingURL=mapping.js.map
\No newline at end of file