forked from carbon-design-system/carbon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
templates.js
114 lines (104 loc) · 4 KB
/
templates.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
'use strict';
const globby = require('globby');
const { promisify } = require('bluebird');
const fs = require('fs');
const path = require('path');
const expressHandlebars = require('express-handlebars');
const helpers = require('handlebars-helpers');
const Fractal = require('@frctl/fractal');
const handlebars = expressHandlebars.create({
defaultLayout: 'demo-nav',
layoutsDir: path.resolve(__dirname, '../demo/views/layouts'),
extname: '.hbs',
});
const Handlebars = handlebars.handlebars;
helpers();
const readFile = promisify(fs.readFile);
/**
* @param {string} glob A glob.
* @returns {Set<string, string>} A set of file contents matching the given glob, keyed by the basename of the file.
*/
const getContents = glob =>
globby(glob).then(filePaths => {
if (filePaths.length === 0) {
return undefined;
}
const contents = new Map();
return Promise.all(
filePaths.map(filePath =>
readFile(filePath, { encoding: 'utf8' }).then(content => {
contents.set(path.basename(filePath, '.hbs'), content);
})
)
).then(() => contents);
});
/**
* Loads Handlebars templates and compiles them.
* @param {string} glob A glob.
* @returns {Set<string, string>} A set of file contents matching the given glob, keyed by the basename of the file.
*/
const loadContents = glob =>
getContents(glob).then(contents => {
contents.forEach((content, templateName) => {
Handlebars.registerPartial(templateName, content);
contents.set(templateName, Handlebars.compile(content));
});
return contents;
});
const fractal = Fractal.create();
fractal.components.set('path', path.join(__dirname, '../src/components'));
fractal.components.set('ext', '.hbs');
fractal.docs.set('path', path.join(__dirname, '../docs'));
const promiseCache = Promise.all([fractal.load(), loadContents(path.resolve(__dirname, '../{demo,src}/**/*.hbs'))]).then(
([sources, contents]) => {
const [componentSource, docSource] = sources;
return {
componentSource,
docSource,
contents,
};
}
);
/**
* @param {Object} [options] The options.
* @param {string} [options.preview] The preview Handlebars template name to force. Useful to force an empty preview.
* @param {string} [options.defaultPreview] The preview Handlebars template name working as the default one.
* @param {boolean} [options.concat] Setting `true` here returns rendered contents all concatenated, instead of returning a map.
* @param {string} [handle]
* The internal component name seen in Fractal.
* Can be of a component or of a variant, or left empty.
* Leaving `handle` empty renders all components.
* @returns {string|Map<Variant, string>} The list of rendered template, keyed by Fractal `Variant` object.
*/
const renderComponent = ({ preview, defaultPreview, concat } = {}, handle) =>
promiseCache.then(({ componentSource, contents }) => {
const renderedItems = new Map();
componentSource.forEach(metadata => {
const items = metadata.isCollection ? metadata : !metadata.isCollated && metadata.variants && metadata.variants();
if (items) {
const filteredItems = !handle || handle === metadata.handle ? items : items.filter(item => handle === item.handle);
filteredItems.forEach(item => {
const { handle: itemHandle, baseHandle, context } = item;
const template = contents.get(itemHandle) || contents.get(baseHandle);
if (template) {
const body = template(context);
const layoutTemplate = contents.get(preview || item.preview || defaultPreview);
renderedItems.set(item, !layoutTemplate ? body : layoutTemplate(Object.assign({ body }, context)));
}
});
}
});
if (!concat) {
return renderedItems;
}
const accumulated = [];
renderedItems.forEach(rendered => {
accumulated.push(rendered);
});
return accumulated.length > 0 ? accumulated.join('\n') : undefined;
});
module.exports = {
promiseCache,
render: renderComponent,
handlebars,
};