1 | ;
|
2 |
|
3 | const _ = require('lodash'),
|
4 | utils = require('clayutils'),
|
5 | refProp = '_ref';
|
6 |
|
7 | /**
|
8 | * normalize a potential component list
|
9 | * @param {array} arr which may be component list or just data
|
10 | * @return {array}
|
11 | */
|
12 | function normalizeComponentList(arr) {
|
13 | if (_.has(_.head(arr), refProp)) {
|
14 | // it's a component list! only return the references
|
15 | return _.map(arr, (item) => _.pick(item, refProp));
|
16 | } else {
|
17 | // just component data, move along
|
18 | return arr;
|
19 | }
|
20 | }
|
21 |
|
22 | /**
|
23 | * normalize a potential component property
|
24 | * @param {object} obj which may be a component prop or just data
|
25 | * @return {object}
|
26 | */
|
27 | function normalizeComponentProp(obj) {
|
28 | if (_.has(obj, refProp)) {
|
29 | // it's a component prop! only return the reference
|
30 | return { [refProp]: obj[refProp] };
|
31 | } else {
|
32 | // just component data, move along
|
33 | return obj;
|
34 | }
|
35 | }
|
36 |
|
37 | /**
|
38 | * remove child component data, leaving only their references
|
39 | * note: this removes _ref from the root of component data
|
40 | * @param {object} data for a component
|
41 | * @return {object}
|
42 | */
|
43 | function normalize(data) {
|
44 | let cleanData = {};
|
45 |
|
46 | _.forOwn(data, (val, key) => {
|
47 | if (_.isArray(val)) {
|
48 | // possibly a component list
|
49 | cleanData[key] = normalizeComponentList(val);
|
50 | } else if (_.isObject(val)) {
|
51 | // possibly a component prop
|
52 | cleanData[key] = normalizeComponentProp(val);
|
53 | } else if (key !== refProp) {
|
54 | // add any other bits of component data
|
55 | cleanData[key] = val;
|
56 | }
|
57 | });
|
58 |
|
59 | return cleanData;
|
60 | }
|
61 |
|
62 | function addComponent(item, bootstrap, added) {
|
63 | const uri = item[refProp],
|
64 | name = utils.getComponentName(uri),
|
65 | instance = utils.getComponentInstance(uri),
|
66 | data = instance ? _.get(bootstrap, `_components.${name}.instances.${instance}`) : _.omit(_.get(bootstrap, `_components.${name}`), 'instances');
|
67 |
|
68 | if (!data || !_.size(data)) {
|
69 | return item; // just return the _ref, since it doesn't point to any data we currently have
|
70 | // note: there might already be data in the database, or elsewhere
|
71 | } else {
|
72 | // if we've found the component, add its data and mark it as added
|
73 | _.set(added, `asChild['${uri}']`, true);
|
74 | added[uri] = true;
|
75 | return _.assign(item, denormalize(data, bootstrap, added)); // recursion excursion!
|
76 | }
|
77 | }
|
78 |
|
79 | /**
|
80 | * denormalize a potential component list
|
81 | * @param {array} arr which may be component list or just data
|
82 | * @param {object} bootstrap containing all components
|
83 | * @param {object} added
|
84 | * @return {array}
|
85 | */
|
86 | function denormalizeComponentList(arr, bootstrap, added) {
|
87 | if (_.has(_.head(arr), refProp)) {
|
88 | // it's a component list! grab the data from the bootstrap
|
89 | return _.map(arr, (item) => addComponent(item, bootstrap, added));
|
90 | } else {
|
91 | // just component data, move along
|
92 | return arr;
|
93 | }
|
94 | }
|
95 |
|
96 | /**
|
97 | * denormalize a potential component prop
|
98 | * @param {object} obj which may be component prop or just data
|
99 | * @param {object} bootstrap containing all components
|
100 | * @param {object} added
|
101 | * @return {array}
|
102 | */
|
103 | function denormalizeComponentProp(obj, bootstrap, added) {
|
104 | if (_.has(obj, refProp)) {
|
105 | // it's a component prop! grab the data from the bootstrap
|
106 | return addComponent(obj, bootstrap, added);
|
107 | } else {
|
108 | // just component data, move along
|
109 | return obj;
|
110 | }
|
111 | }
|
112 |
|
113 | /**
|
114 | * add child component data to their references,
|
115 | * and update a list of added components
|
116 | * note: this is similar to how amphora composes json
|
117 | * @param {object} data for a component
|
118 | * @param {object} bootstrap containing all components
|
119 | * @param {object} added
|
120 | * @return {object}
|
121 | */
|
122 | function denormalize(data, bootstrap, added) {
|
123 | _.forOwn(data, (val, key) => {
|
124 | if (_.isArray(val)) {
|
125 | // possibly a component list
|
126 | data[key] = denormalizeComponentList(val, bootstrap, added);
|
127 | } else if (_.isObject(val)) {
|
128 | // possibly a component prop
|
129 | data[key] = denormalizeComponentProp(val, bootstrap, added);
|
130 | } else {
|
131 | // add any other bits of component data
|
132 | data[key] = val;
|
133 | }
|
134 | });
|
135 |
|
136 | return data;
|
137 | }
|
138 |
|
139 | module.exports.normalize = normalize;
|
140 | module.exports.denormalize = denormalize;
|