This repository has been archived by the owner on Mar 25, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
157 lines (129 loc) · 4.63 KB
/
index.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict';
var assert = require('assert');
var path = require('path');
var _eval = require('node-eval');
var bemxjst = require('bem-xjst');
var through = require('through2');
var PluginError = require('plugin-error');
var File = require('vinyl');
var isStream = require('is-stream');
var toArray = require('stream-to-array');
var formatError = require('./error');
var pluginName = path.basename(__dirname);
/**
* bem-xjst templates compiler.
*
* @param {{extension: string}} options - Options for generator.
* @param {String|Function} engine - 'bemhtml' either 'bemtree' or any xjst-like engine function.
* @returns {Stream}
*/
module.exports = function(options, engine) {
options = options || {};
assert(typeof engine === 'string' || typeof (engine && engine.generate) === 'function', 'Invalid engine');
var engineName;
if (typeof engine === 'string') {
engineName = engine;
engine = bemxjst[engine];
} else {
engineName = (engine.engineName || engine.name || Object(engine.runtime).name).toLowerCase() || 'xjst';
}
return through.obj(function(file, encoding, callback) {
if (file.isNull()) {
return callback(null, file);
}
if (file.isStream()) {
return callback(new PluginError(pluginName, 'Streaming not supported'));
}
var code = file.contents.toString();
var res = tryCatch(function() {
return engine.generate(code, options);
}, function(e) {
return new PluginError(pluginName, formatError(e, code, file.path), {
fileName: file.path
});
});
if (res instanceof PluginError) {
return callback(res);
}
file.contents = new Buffer(res);
file.path = path.basename(file.path).split('.')[0] +
'.' + (options.extension || (engineName + '.js')).replace(/^\./, '');
callback(null, file);
});
};
module.exports.bemhtml = function(options) {
return module.exports(options, 'bemhtml');
};
module.exports.bemtree = function(options) {
return module.exports(options, 'bemtree');
};
/**
* Wrapper for anything.apply with bemjson.
*
* @param {Stream<Vinyl>} templatesStream - Stream with bemhtmls
* @returns {TransformStream<Vinyl>} - transform stream that applies templates to each incoming bemjson vinyl
*/
module.exports.toHtml = function(templatesStream) {
if (!isStream(templatesStream)) {
throw new PluginError(pluginName, 'Parameter should be a Stream');
}
var templatesPromise = toArray(templatesStream);
return through.obj(function(bemjsonFile, _, callback) {
if (bemjsonFile.isNull()) {
return callback(null, bemjsonFile);
}
if (bemjsonFile.isStream()) {
return callback(new PluginError(pluginName, 'Streaming not supported'));
}
tryCatch(function () {
return bemjsonFile.data || (bemjsonFile.data = _eval(String(bemjsonFile.contents), bemjsonFile.path));
}, function (err) {
callback(new PluginError(pluginName, 'Error at evaluating bemjson: ' + err));
});
if (!bemjsonFile.data) {
callback();
return;
}
var _this = this;
templatesPromise
.then(function (templatesVinyls) {
// Handle multiple templates case
var n = 0;
templatesVinyls.forEach(function(file) {
file.data || (file.data = _eval(String(file.contents)));
var html = tryCatch(function () {
return file.data.apply(bemjsonFile.data);
}, function (err) {
throw new Error('BEMHTML error: ' + err);
});
if (typeof html !== 'string') {
throw new Error('Incorrect html result.');
}
var name = path.basename(bemjsonFile.path).split('.')[0];
var newFile = new File({
path: name + (n-- || '') + '.html',
contents: new Buffer(html)
});
_this.push(newFile);
});
callback();
})
.catch(function (err) {
callback(new PluginError(pluginName, err));
});
});
};
/**
* Try to run function and call handler if it throws.
*
* @param {Function} fn - Unsafe function body
* @param {Function} cb - Error handler
* @returns {*}
*/
function tryCatch(fn, cb) {
try {
return fn();
} catch (e) {
return cb(e);
}
}