1 | 'use strict';
|
2 | const h = require('highland'),
|
3 | _ = require('lodash'),
|
4 | b64 = require('base-64'),
|
5 | utils = require('clayutils'),
|
6 | composer = require('./composer'),
|
7 | deepReduce = require('./deep-reduce'),
|
8 | types = require('./types');
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | function getDispatchURI(dispatch) {
|
16 | return Object.keys(dispatch)[0];
|
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 | function parseComponentBootstrap(dispatches, components, { bootstrap, added }) {
|
45 | return _.reduce(components, (dispatches, data, name) => {
|
46 | const defaultData = _.omit(data, 'instances'),
|
47 | defaultURI = `/_components/${name}`;
|
48 |
|
49 |
|
50 | if (_.size(defaultData) && !added[defaultURI]) {
|
51 | dispatches.push({ [defaultURI]: composer.denormalize(defaultData, bootstrap, added) });
|
52 | added[defaultURI] = true;
|
53 | }
|
54 |
|
55 |
|
56 | if (data.instances && _.size(data.instances)) {
|
57 | _.forOwn(data.instances, (instanceData, instance) => {
|
58 | const instanceURI = `/_components/${name}/instances/${instance}`;
|
59 |
|
60 | if (!added[instanceURI]) {
|
61 | dispatches.push({ [instanceURI]: composer.denormalize(instanceData, bootstrap, added) });
|
62 | added[instanceURI] = true;
|
63 | }
|
64 | });
|
65 | }
|
66 |
|
67 |
|
68 | return _.filter(dispatches, (dispatch) => !_.get(added, `asChild[${getDispatchURI(dispatch)}]`));
|
69 | }, dispatches);
|
70 | }
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | function parseLayoutBootstrap(dispatches, layouts, { bootstrap, added }) {
|
81 | return _.reduce(layouts, (dispatches, data, name) => {
|
82 | const defaultData = _.omit(data, 'instances'),
|
83 | defaultURI = `/_layouts/${name}`;
|
84 |
|
85 |
|
86 | if (_.size(defaultData)) {
|
87 | dispatches.push({ [defaultURI]: composer.denormalize(defaultData, bootstrap, added) });
|
88 | }
|
89 |
|
90 |
|
91 | if (data.instances && _.size(data.instances)) {
|
92 | _.forOwn(data.instances, (instanceData, instance) => {
|
93 | const instanceURI = `/_layouts/${name}/instances/${instance}`;
|
94 |
|
95 | let meta;
|
96 |
|
97 |
|
98 | if (instanceData.meta) {
|
99 | meta = instanceData.meta;
|
100 | delete instanceData.meta;
|
101 | }
|
102 |
|
103 | dispatches.push({ [instanceURI]: composer.denormalize(instanceData, bootstrap, added) });
|
104 | if (meta) {
|
105 | dispatches.push({ [`${instanceURI}/meta`]: meta });
|
106 | }
|
107 | });
|
108 | }
|
109 |
|
110 | return dispatches;
|
111 | }, dispatches);
|
112 | }
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | function parsePageBootstrap(dispatches, pages) {
|
122 | return _.reduce(pages, (dispatches, page, id) => {
|
123 | let meta;
|
124 |
|
125 | if (id[0] === '/') {
|
126 |
|
127 | id = id.slice(1);
|
128 | }
|
129 |
|
130 |
|
131 | if (page.url && !page.customUrl) {
|
132 | page.customUrl = page.url;
|
133 | delete page.url;
|
134 | }
|
135 |
|
136 |
|
137 | if (page.meta) {
|
138 | meta = page.meta;
|
139 | delete page.meta;
|
140 | }
|
141 |
|
142 | dispatches.push({ [`/_pages/${id}`]: page });
|
143 |
|
144 | if (meta) {
|
145 | dispatches.push({ [`/_pages/${id}/meta`]: meta });
|
146 | }
|
147 | return dispatches;
|
148 | }, dispatches);
|
149 | }
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 | function parseUsersBootstrap(dispatches, users) {
|
158 |
|
159 | return _.reduce(users, (dispatches, user) => {
|
160 | if (!user.username || !user.provider || !user.auth) {
|
161 | throw new Error('Cannot bootstrap users without username, provider, and auth level');
|
162 | } else {
|
163 | dispatches.push({ [`/_users/${b64.encode(user.username.toLowerCase() + '@' + user.provider)}`]: user });
|
164 | }
|
165 | return dispatches;
|
166 | }, dispatches);
|
167 | }
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 | function parseArbitraryBootstrapData(dispatches, items, type) {
|
177 | return _.reduce(items, (dispatches, item, key) => {
|
178 | if (key[0] === '/') {
|
179 |
|
180 | key = key.slice(1);
|
181 | }
|
182 | dispatches.push({ [`/${type}/${key}`]: item });
|
183 | return dispatches;
|
184 | }, dispatches);
|
185 | }
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 | function parseBootstrap(bootstrap) {
|
193 | let added = { asChild: {} },
|
194 | dispatches = _.reduce(bootstrap, (dispatches, items, type) => {
|
195 | switch (type) {
|
196 | case '_components': return parseComponentBootstrap(dispatches, items, { bootstrap, added });
|
197 | case '_layouts': return parseLayoutBootstrap(dispatches, items, { bootstrap, added });
|
198 | case '_pages': return parsePageBootstrap(dispatches, items);
|
199 | case '_users': return parseUsersBootstrap(dispatches, items);
|
200 | default: return parseArbitraryBootstrapData(dispatches, items, type);
|
201 | }
|
202 | }, []);
|
203 |
|
204 | return h(dispatches);
|
205 | }
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | function toDispatch(stream) {
|
213 | return stream.flatMap(parseBootstrap);
|
214 | }
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 | function parseComponentDispatch(uri, dispatch, bootstrap) {
|
224 | const deepData = dispatch[uri],
|
225 | name = utils.getComponentName(uri),
|
226 | instance = utils.getComponentInstance(uri),
|
227 | path = instance ? `_components['${name}'].instances['${instance}']` : `_components['${name}']`;
|
228 |
|
229 | _.set(bootstrap, path, composer.normalize(deepData));
|
230 |
|
231 | return deepReduce(bootstrap, deepData, (ref, val) => {
|
232 | const deepName = utils.getComponentName(ref),
|
233 | deepInstance = utils.getComponentInstance(ref),
|
234 | deepPath = deepInstance ? `_components['${deepName}'].instances['${deepInstance}']` : `_components['${deepName}']`;
|
235 |
|
236 | _.set(bootstrap, deepPath, composer.normalize(val));
|
237 | });
|
238 | }
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 | function parseLayoutDispatch(uri, dispatch, bootstrap) {
|
248 | const deepData = dispatch[uri],
|
249 | name = utils.getLayoutName(uri),
|
250 | instance = utils.getLayoutInstance(uri),
|
251 | path = instance ? `_layouts['${name}'].instances['${instance}']` : `_layouts['${name}']`;
|
252 |
|
253 | if (utils.isLayoutMeta(uri)) {
|
254 |
|
255 |
|
256 | _.set(bootstrap, `_layouts['${name}'].instances['${instance}'].meta`, deepData);
|
257 | return bootstrap;
|
258 | }
|
259 |
|
260 | _.set(bootstrap, path, _.assign({}, _.get(bootstrap, path, {}), composer.normalize(deepData)));
|
261 |
|
262 | return deepReduce(bootstrap, deepData, (ref, val) => {
|
263 |
|
264 | const deepName = utils.getComponentName(ref),
|
265 | deepInstance = utils.getComponentInstance(ref),
|
266 | deepPath = deepInstance ? `_components['${deepName}'].instances['${deepInstance}']` : `_components['${deepName}']`;
|
267 |
|
268 | _.set(bootstrap, deepPath, _.assign({}, _.get(bootstrap, deepPath, {}), composer.normalize(val)));
|
269 | });
|
270 | }
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 | function parsePageDispatch(uri, dispatch, bootstrap) {
|
280 | let id = utils.getPageInstance(uri),
|
281 | page = dispatch[uri];
|
282 |
|
283 | if (utils.isPageMeta(uri)) {
|
284 |
|
285 | _.set(bootstrap, `_pages['${id}'].meta`, page);
|
286 | return bootstrap;
|
287 | }
|
288 |
|
289 |
|
290 | if (page.url && !page.customUrl) {
|
291 | page.customUrl = page.url;
|
292 | delete page.url;
|
293 | }
|
294 |
|
295 | _.set(bootstrap, `_pages['${id}']`, _.assign({}, _.get(bootstrap, `_pages['${id}']`, {}), page));
|
296 | return bootstrap;
|
297 | }
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 | function parseUsersDispatch(uri, dispatch, bootstrap) {
|
307 | if (!bootstrap._users) {
|
308 | bootstrap._users = [];
|
309 | }
|
310 |
|
311 | bootstrap._users.push(dispatch[uri]);
|
312 | return bootstrap;
|
313 | }
|
314 |
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 | function parseArbitraryDispatchData(uri, dispatch, bootstrap) {
|
323 | let type = _.find(types, (t) => _.includes(uri, t)),
|
324 | name = uri.split(`${type}/`)[1];
|
325 |
|
326 | type = type.slice(1);
|
327 | if (type === '_uris' && name[0] !== '/') {
|
328 |
|
329 | name = `/${name}`;
|
330 | }
|
331 |
|
332 | _.set(bootstrap, `${type}['${name}']`, dispatch[uri]);
|
333 | return bootstrap;
|
334 | }
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 | function generateBootstrap(bootstrap, dispatch) {
|
343 | const uri = getDispatchURI(dispatch),
|
344 | type = _.find(types, (t) => _.includes(uri, t));
|
345 |
|
346 | switch (type) {
|
347 | case '/_components': return parseComponentDispatch(uri, dispatch, bootstrap);
|
348 | case '/_layouts': return parseLayoutDispatch(uri, dispatch, bootstrap);
|
349 | case '/_pages': return parsePageDispatch(uri, dispatch, bootstrap);
|
350 | case '/_users': return parseUsersDispatch(uri, dispatch, bootstrap);
|
351 | default: return parseArbitraryDispatchData(uri, dispatch, bootstrap);
|
352 | }
|
353 | }
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 | function toBootstrap(stream) {
|
361 | return stream.reduce({}, generateBootstrap);
|
362 | }
|
363 |
|
364 | module.exports.toDispatch = toDispatch;
|
365 | module.exports.toBootstrap = toBootstrap;
|