UNPKG

5.47 kBJavaScriptView Raw
1'use strict';
2
3var PLUGIN_NAME = 'gulp-nunjucks-api';
4
5var glob = require('glob');
6var gutil = require('gulp-util');
7var lodash = require('lodash');
8var nunjucks = require('nunjucks');
9var path = require('path');
10var requireNew = require('require-new');
11var through = require('through2');
12
13// #region Configuration
14
15function configure(options) {
16 var config = {
17 context: {},
18 extension: '.html',
19 verbose: false
20 };
21 if (options === undefined || options === null)
22 options = {};
23 else
24 options = lodash.cloneDeep(options);
25
26 configureErrors(config, options);
27 configureVerbosity(config, options);
28 configureGlobals(config, options);
29 configureLocals(config, options);
30 configureContext(config, options);
31 configureFiles(config, options);
32 configureNunjucks(config, options);
33
34 return config;
35}
36
37function configureContext(config, options) {
38 var g = config.g;
39 lodash.assign(config.context, g.data);
40 lodash.assign(config.context, g.functions);
41}
42
43function configureErrors(config, options) {
44 if ('errors' in options)
45 config.errors = options.errors;
46 else
47 config.errors = true;
48 delete options.errors;
49}
50
51function configureFiles(config, options) {
52 if (options.extension)
53 config.extension = options.extension;
54 if (options.src)
55 config.src = options.src;
56 delete options.extension;
57 delete options.src;
58}
59
60function configureGlobals(config, options) {
61 var g = {};
62 var og = options.globals || {};
63 g.data = lodash.merge({}, og.data, options.data);
64 g.extensions = lodash.merge({}, og.extensions, options.extensions);
65 g.filters = lodash.merge({}, og.filters, options.filters);
66 g.functions = lodash.merge({}, og.functions, options.functions);
67 config.g = g;
68 delete options.data;
69 delete options.extensions;
70 delete options.filters;
71 delete options.functions;
72 delete options.globals;
73}
74
75function configureLocals(config, options) {
76 if (options.locals === true)
77 config.locals = '<filename>.+(js|json)';
78 else
79 config.locals = options.locals;
80 delete options.locals;
81}
82
83function configureNunjucks(config, options) {
84 var env;
85 var g = config.g;
86 var filters = g.filters;
87 var extensions = g.extensions;
88 var name;
89 // At this point, options should only contain fields which are relevant to
90 // the nunjucks.configure api.
91
92 // Disable watch by default for the gulp system, since gulp will not exit
93 // while files are being watched.
94 if (options.watch === undefined)
95 options.watch = false;
96
97 config.env = nunjucks.configure(config.src, options);
98
99 env = config.env;
100 for (name in filters)
101 env.addFilter(name, filters[name]);
102 for (name in extensions)
103 env.addExtension(name, extensions[name]);
104}
105
106function configureVerbosity(config, options) {
107 config.verbose = options.verbose || config.verbose;
108 config.vlog = config.verbose ? log : returnGulpUtil;
109 delete options.verbose;
110}
111
112// #endregion
113
114// #region Helpers
115
116function createError(message, opt) {
117 return new gutil.PluginError(PLUGIN_NAME, message, opt);
118}
119
120function handleError(config, sender, err, cb, opt) {
121 config.vlog('Handling error: ' + err);
122 var pluginErr = createError(err, opt);
123 if (config.errors)
124 sender.emit('error', pluginErr);
125 return cb(pluginErr);
126}
127
128function log(message) {
129 return gutil.log.apply(gutil, arguments);
130}
131
132function requireFile(config, filepath, result) {
133 if (filepath === undefined || filepath === null)
134 return false;
135 try {
136 result.obj = requireNew(filepath);
137 return true;
138 }
139 catch (err) {
140 config.vlog('File not found: ' + filepath);
141 }
142 return false;
143}
144
145// #endregion
146
147function assignLocals(context, config, file) {
148 var searchpath = path.dirname(file.path);
149 var pfile = path.parse(file.path);
150 var locals = String.prototype.replace.apply(config.locals, [
151 '<filename>', pfile.base]);
152 locals = String.prototype.replace.apply(locals, [
153 '<filename_noext>', pfile.name]);
154 var pattern = locals;
155 config.vlog('Searching for locals with pattern:', pattern, 'in:', searchpath);
156 var options = {
157 cwd: searchpath,
158 nodir: true
159 };
160 var found = glob.sync(pattern, options);
161 var i, fullpath, result;
162 config.vlog('Found:', found.length, 'locals files.');
163 for (i = 0; i < found.length; i++) {
164 fullpath = path.resolve(searchpath, found[i]);
165 config.vlog('Using locals file:', found[i], 'fullpath:', fullpath);
166 result = {};
167 if (requireFile(config, fullpath, result))
168 lodash.assign(context, result.obj);
169 }
170}
171
172function plugin(options) {
173 var config = configure(options);
174
175 function render(file, enc, cb) {
176 var context = lodash.cloneDeep(config.context);
177 var env = config.env;
178 var _this = this;
179
180 if (file.isNull()) {
181 this.push(file);
182 return cb();
183 }
184 if (file.isStream())
185 return handleError(config, _this, 'Streaming not supported', cb);
186 if (file.data)
187 lodash.assign(context, file.data);
188 if (config.locals)
189 assignLocals(context, config, file);
190 config.vlog('Rendering nunjucks file.path:', file.path);
191 env.render(file.path, context, function (err, result) {
192 if (err)
193 return handleError(config, _this, err, cb);
194 file.contents = new Buffer(result);
195 file.path = gutil.replaceExtension(file.path, config.extension);
196 _this.push(file);
197 cb();
198 });
199 }
200 return through.obj(render);
201}
202module.exports = plugin;
203plugin.nunjucks = nunjucks;
204
205function returnGulpUtil() {
206 return gutil;
207}