├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── index.js ├── package.json └── test.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es6": true 5 | }, 6 | "rules": { 7 | "block-spacing": [2, "always"], 8 | "brace-style": [2, "1tbs", {"allowSingleLine": true}], 9 | "comma-style": [2, "last"], 10 | "func-style": [2, "expression"], 11 | "semi": [2, "always"], 12 | "quotes": [2, "single", "avoid-escape"], 13 | "indent": [2, 2, {"SwitchCase": 1}], 14 | "dot-location": [2, "property"], 15 | "camelcase": [1, {"properties": "always"}], 16 | "comma-spacing": [2, {"before": false, "after": true}], 17 | "comma-dangle": [2, "never"], 18 | "semi-spacing": [2, {"before": false, "after": true}], 19 | "curly": [2, "multi-line", "consistent"], 20 | "no-debugger": 2, 21 | "no-dupe-args": 2, 22 | "no-dupe-keys": 2, 23 | "no-duplicate-case": 2, 24 | "no-empty": 2, 25 | "no-ex-assign": 2, 26 | "no-extra-semi": 2, 27 | "no-func-assign": 2, 28 | "no-irregular-whitespace": 2, 29 | "no-sparse-arrays": 2, 30 | "no-unexpected-multiline": 2, 31 | "no-unreachable": 2, 32 | "no-unused-vars": [2, {"varsIgnorePattern": "ignored"}], 33 | "valid-typeof": 2, 34 | "eqeqeq": [2, "allow-null"], 35 | "no-array-constructor": 2, 36 | "no-caller": 2, 37 | "no-eval": 2, 38 | "no-extend-native": 2, 39 | "no-extra-bind": 2, 40 | "no-fallthrough": 2, 41 | "no-labels": 2, 42 | "no-iterator": 2, 43 | "no-magic-numbers": [1, {"ignore": [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]}], 44 | "no-multi-spaces": 2, 45 | "no-native-reassign": 2, 46 | "no-new-func": 2, 47 | "no-new-wrappers": 2, 48 | "no-new": 2, 49 | "no-octal-escape": 2, 50 | "no-octal": 2, 51 | "no-redeclare": 2, 52 | "no-self-compare": 2, 53 | "no-sequences": 2, 54 | "no-unused-expressions": 2, 55 | "no-useless-call": 2, 56 | "no-warning-comments": [1, {"terms": ["todo", "fixme", "xxx"], "location": "start"}], 57 | "no-with": 2, 58 | "new-parens": 2, 59 | "wrap-iife": [2, "inside"], 60 | "no-catch-shadow": 2, 61 | "no-delete-var": 2, 62 | "no-shadow-restricted-names": 2, 63 | "no-undef": 2, 64 | "callback-return": 2, 65 | "handle-callback-err": 2, 66 | "no-path-concat": 2, 67 | "array-bracket-spacing": 2, 68 | "eol-last": 2, 69 | "no-multiple-empty-lines": [2, {"max": 2}], 70 | "no-spaced-func": 2, 71 | "no-trailing-spaces": 2, 72 | "no-unneeded-ternary": 2, 73 | "keyword-spacing": 2, 74 | "space-before-blocks": 2, 75 | "space-before-function-paren": [2, "never"], 76 | "space-in-parens": 2, 77 | "space-unary-ops": [2, {"words": true, "nonwords": false}], 78 | "arrow-spacing": [2, {"before": true, "after": true}], 79 | "prefer-arrow-callback": 2, 80 | "prefer-template": 0, 81 | "prefer-const": 2 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.bak 3 | .DS_Store 4 | npm-debug.log 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .lock-wscript 2 | .svn/ 3 | .hg/ 4 | .git/ 5 | CVS/ 6 | *~ 7 | *.bak 8 | .DS_Store 9 | npm-debug.log 10 | test.js 11 | CHANGELOG.md 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '5' 4 | - '4' 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # jade-brunch 2.0.0 (Jan 29, 2016) 2 | * Updated source code & API. The plugin would now only work with Brunch 2.2 and higher. 3 | 4 | # jade-brunch 1.8.2 (18 November 2015) 5 | * npm@3 compatibility for including jade runtime file in build 6 | * Bumped jade dep to ^1.11.0 7 | 8 | # jade-brunch 1.8.1 (26 February 2014) 9 | * Allowed disabling `compileClient` option. 10 | * All options can be now passed to jade. 11 | * Bumped jade to 1.2 12 | 13 | # jade-brunch 1.8.0 (16 December 2013) 14 | * Updated jade to 1.0.x 15 | 16 | # jade-brunch 1.7.5 (16 December 2013) 17 | * Fixed runtime inclusion. 18 | 19 | # jade-brunch 1.7.4 (16 december 2013) 20 | * New runtime. 21 | 22 | # jade-brunch 1.7.3 (20 November 2013) 23 | * Support watching of plain-html partials referenced in jade source files. 24 | 25 | # jade-brunch 1.7.2 (28 August 2013) 26 | * New way of parsing dependent files. 27 | 28 | # jade-brunch 1.7.1 (15 July 2013) 29 | * Added UMD support. 30 | 31 | # jade-brunch 1.7.0 (15 July 2013) 32 | * Added support for non-common.js wrappers. 33 | 34 | # jade-brunch 1.6.0 (22 June 2013) 35 | * Updated jade to 0.31. 36 | 37 | # jade-brunch 1.5.1 (19 March 2013) 38 | * Added node 0.10 support, removed coffee-script dependency. 39 | 40 | # jade-brunch 1.5.0 (13 January 2013) 41 | * Improved installation process. 42 | 43 | # jade-brunch 1.4.1 (2 December 2012) 44 | * Jade runtime is now saved locally to prevent npm conflicts. 45 | 46 | # jade-brunch 1.4.0 (26 November 2012) 47 | * Updated jade to latest 0.27.x release. 48 | 49 | # jade-brunch 1.3.0 (29 June 2012) 50 | * Updated jade to 0.26.3. 51 | * Added node.js 0.8 and 0.9 support. 52 | * Package is now precompiled before every publishing to npm. 53 | 54 | # jade-brunch 1.1.1 (15 April 2012) 55 | * Fixed error reporting when installing the package. 56 | 57 | # jade-brunch 1.1.0 (9 April 2012) 58 | * Added windows support. 59 | 60 | # jade-brunch 1.0.1 (23 March 2012) 61 | * Added support for prettified compilation. To use it, you need to 62 | set config.plugins.jade.pretty to true. 63 | 64 | # jade-brunch 1.0.0 (8 March 2012) 65 | * Initial release 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## jade-brunch 2 | Adds [Jade](http://jade-lang.com) support to [brunch](http://brunch.io), by 3 | compiling templates into dynamic javascript modules and `.jade` assets into plain HTML. 4 | 5 | ## Usage 6 | Install the plugin via npm with `npm install --save-dev jade-brunch`. 7 | 8 | Or, do manual install: 9 | 10 | * Add `"jade-brunch": "x.y.z"` to `package.json` of your brunch app. 11 | Pick a plugin version that corresponds to your minor (y) brunch version. 12 | * If you want to use git version of plugin, add 13 | `"jade-brunch": "git+ssh://git@github.com:brunch/jade-brunch.git"`. 14 | 15 | You can also use `jade-brunch` to compile jade into html. Just place your jade files into `app/assets`. 16 | 17 | ## Assumptions 18 | 19 | When using Jade's basedir relative `include` and `extend`, the basedir will be assumed to be 'app' within the Brunch root. See [#989](https://github.com/visionmedia/jade/pull/989) 20 | 21 | For jade files in `app/assets`, the basedir will be assumed to be `app/assets`. 22 | 23 | ## License 24 | 25 | The MIT License (MIT) 26 | 27 | Copyright (c) 2012-2014 Paul Miller (http://paulmillr.com) 28 | 29 | Permission is hereby granted, free of charge, to any person obtaining a copy 30 | of this software and associated documentation files (the "Software"), to deal 31 | in the Software without restriction, including without limitation the rights 32 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 | copies of the Software, and to permit persons to whom the Software is 34 | furnished to do so, subject to the following conditions: 35 | 36 | The above copyright notice and this permission notice shall be included in 37 | all copies or substantial portions of the Software. 38 | 39 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 40 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 41 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 43 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 44 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 45 | THE SOFTWARE. 46 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const jade = require('jade'); 4 | const sysPath = require('path'); 5 | const umd = require('umd-wrapper'); 6 | const progeny = require('progeny'); 7 | 8 | // perform a deep cloning of an object 9 | const clone = (obj) => { 10 | if (null == obj || 'object' !== typeof obj) return obj; 11 | const copy = obj.constructor(); 12 | for (const attr in obj) { 13 | if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); 14 | } 15 | return copy; 16 | }; 17 | 18 | class JadeCompiler { 19 | constructor(cfg) { 20 | if (cfg == null) cfg = {}; 21 | const defaultBaseDir = sysPath.join(cfg.paths.root, 'app'); 22 | const defaultStaticBaseDir = sysPath.join(defaultBaseDir, 'assets'); 23 | const jade = cfg.plugins && cfg.plugins.jade; 24 | const config = (jade && jade.options) || jade; 25 | 26 | // Allow runtime to be excluded 27 | if (config && config.noRuntime) { 28 | this.include = []; 29 | } 30 | 31 | // cloning is mandatory because config is not mutable 32 | this.locals = jade && jade.locals || {}; 33 | this.options = clone(config) || {}; 34 | this.options.compileDebug = false; 35 | this.options.client = true; 36 | this.options.basedir = (config && config.basedir) || defaultBaseDir; 37 | this.options.staticBasedir = (config && config.staticBasedir) || defaultStaticBaseDir; 38 | 39 | const getDependencies = progeny({ 40 | rootPath: this.options.basedir, 41 | reverseArgs: true 42 | }); 43 | 44 | const getDependenciesStatic = progeny({ 45 | rootPath: this.options.staticBasedir, 46 | reverseArgs: true 47 | }); 48 | 49 | this.getDependencies = (data, path, cb) => { 50 | if (sysPath.resolve(path).indexOf(sysPath.resolve(this.options.staticBasedir)) === 0) { 51 | return getDependenciesStatic(data, path, cb); 52 | } else { 53 | return getDependencies(data, path, cb); 54 | } 55 | }; 56 | } 57 | 58 | compile(params) { 59 | const data = params.data; 60 | const path = params.path; 61 | 62 | const options = clone(this.options); 63 | options.filename = path; 64 | 65 | return new Promise((resolve, reject) => { 66 | let result, error; 67 | try { 68 | let compiled; 69 | // cloning is mandatory because Jade changes it 70 | if (options.preCompile === true) { 71 | const precompiled = jade.compile(data, options)(); 72 | compiled = JSON.stringify(precompiled); 73 | } else { 74 | compiled = jade.compileClient(data, options); 75 | } 76 | result = umd(compiled); 77 | } catch (_error) { 78 | error = _error; 79 | } finally { 80 | if (error) return reject(error); 81 | resolve(result); 82 | } 83 | }); 84 | } 85 | 86 | compileStatic(params) { 87 | const data = params.data; 88 | const path = params.path; 89 | 90 | const options = Object.assign({}, this.options); 91 | const locals = Object.assign({}, this.locals); 92 | try { 93 | options.filename = path; 94 | options.basedir = options.staticBasedir; 95 | locals.filename = path.replace(new RegExp('^' + options.basedir + '/'), ''); 96 | const fn = jade.compile(data, options); 97 | const compiled = fn(locals); 98 | return Promise.resolve(compiled); 99 | } catch (error) { 100 | return Promise.reject(error); 101 | } 102 | } 103 | } 104 | 105 | let jadePath = require.resolve('jade'); 106 | 107 | while (sysPath.basename(jadePath) !== 'jade') { 108 | jadePath = sysPath.dirname(jadePath); 109 | } 110 | 111 | JadeCompiler.prototype.include = [ 112 | sysPath.join(jadePath, 'runtime.js') 113 | ]; 114 | 115 | JadeCompiler.prototype.brunchPlugin = true; 116 | JadeCompiler.prototype.type = 'template'; 117 | JadeCompiler.prototype.extension = 'jade'; 118 | JadeCompiler.prototype.staticTargetExtension = 'html'; 119 | 120 | module.exports = JadeCompiler; 121 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jade-brunch", 3 | "version": "2.8.0", 4 | "description": "Adds Jade support to brunch.", 5 | "author": "Paul Miller (http://paulmillr.com/)", 6 | "homepage": "https://github.com/brunch/jade-brunch", 7 | "keywords": [ 8 | "brunchplugin", 9 | "jade", 10 | "template" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git@github.com:brunch/jade-brunch.git" 15 | }, 16 | "scripts": { 17 | "test": "eslint index.js && mocha" 18 | }, 19 | "dependencies": { 20 | "jade": "~1.11.0", 21 | "progeny": "~0.5.2", 22 | "umd-wrapper": "~0.1.0" 23 | }, 24 | "devDependencies": { 25 | "chai": "^3", 26 | "mocha": "^3", 27 | "eslint": "^3.12.2", 28 | "eslint-config-brunch": "brunch/eslint-config-brunch" 29 | }, 30 | "eslintConfig": { 31 | "extends": "brunch" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect; 4 | const Plugin = require('./'); 5 | const jade = require('jade'); 6 | const sysPath = require('path'); 7 | const fs = require('fs'); 8 | 9 | describe('Plugin', () => { 10 | let plugin; 11 | 12 | beforeEach(() => { 13 | plugin = new Plugin({paths: {root: '.'}}); 14 | }); 15 | 16 | it('should be an object', () => { 17 | expect(plugin).to.be.ok; 18 | }); 19 | 20 | it('should has #compile method', () => { 21 | expect(plugin.compile).to.be.an.instanceof(Function); 22 | }); 23 | 24 | it('should compile and produce valid result', () => { 25 | const content = 'doctype html'; 26 | const expected = ''; 27 | 28 | return plugin.compile({data: content, path: 'template.jade'}).then(data => { 29 | expect(eval(data)()).to.equal(expected); 30 | }, error => expect(error).not.to.be.ok); 31 | }); 32 | 33 | it('should compile template string with data', () => { 34 | const expected = '' + 35 | '' + 36 | '