# coding=utf-8 from __future__ import print_function import os, subprocess from webassets.filter import Filter, register_filter from webassets.exceptions import FilterError class Jade(Filter): """Converts `Jade `_ templates to client-side JavaScript functions. Requires the Jade executable to be available externally. You can install it using the `Node Package Manager `_:: $ npm install jade Jade templates are compiled and stored in a window-level JavaScript object under a key corresponding to the template file's basename. For example, ``keyboardcat.jade`` compiles into: window.templates['keyboardcat'] = function() { ... }; Supported configuration options: JADE_BIN The system path to the Jade binary. If not set assumes ``jade`` is in the system path. JADE_RUNTIME The system path to the Jade runtime, ``runtime.js`` which ships with Jade. If you installed Jade locally it can be found in: node_modules/jade/runtime.js Globally, on Ubuntu it's typically located in: /usr/lib/node_modules/jade/runtime.js Or sometimes: /usr/local/lib/node_modules/jade/runtime.js If, for some reason you can't find your Jade runtime you can download it from the `Jade Repository `_:: but do take care to download the runtime version which matches the version of your installed Jade. JADE_NO_DEBUG Omits debugging information to output shorter functions. JADE_TEMPLATE_VAR The window-level JavaScript object where the compiled Jade objects will be stored. By default this defaults to ``templates`` as such: window['templates'] """ name = 'jade' max_debug_level = None options = { 'jade': 'JADE_BIN', 'jade_runtime': 'JADE_RUNTIME', 'jade_no_debug': 'JADE_NO_DEBUG', 'js_var': 'JADE_TEMPLATE_VAR' } argv = [] def setup(self): """ Check options and apply defaults if necessary """ super(Jade, self).setup() self.argv = [self.jade or 'jade'] self.argv.append('--client') if self.jade_no_debug: self.argv.append('--no-debug') if not self.js_var: self.js_var = 'templates' def input(self, _in, out, **kwargs): """ Compile individual Jade templates """ proc = subprocess.Popen(self.argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=(os.name == 'nt')) stdout, stderr = proc.communicate(_in.read()) if proc.returncode != 0: raise FilterError(('jade: subprocess returned a non-success ' + 'result code: %s, stdout=%s, stderr=%s') % (proc.returncode, stdout, stderr)) elif stderr: print('jade filter has warnings:', stderr) # Add a bit of JavaScript that will place our compiled Jade function # into an object on the `window` object. Jade files are keyed by their # basename. key = os.path.splitext(os.path.basename(kwargs['source_path']))[0] preamble = "window['%s']['%s'] = " % (self.js_var, key) out.write('%s%s' % (preamble, stdout.strip())) def output(self, _in, out, **kwargs): """ Prepend Jade runtime and initialize template variable. """ if self.jade_runtime: with open(self.jade_runtime) as file: runtime = ''.join(file.readlines()) else: runtime = '' # JavaScript code to initialize the window-level object that will hold # our compiled Jade templates as functions init = "if(!window['%s']) { window['%s'] = {}; }" % (self.js_var, self.js_var) out.write('%s\n%s\n%s' % (runtime, init, _in.read())) register_filter(Jade)