├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── build.bat ├── build.sh ├── lib └── index.js ├── package.json ├── setup.js ├── src └── index.coffee └── test ├── JadeAngularJsCompiler.coffee ├── common.js └── folder ├── folder ├── index.jade ├── partial1.jade └── partial2.jade ├── index.jade ├── partial1.jade └── partial2.jade /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .lock-wscript 2 | .svn/ 3 | .hg/ 4 | .git/ 5 | CVS/ 6 | *~ 7 | *.bak 8 | .DS_Store 9 | npm-debug.log 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jade-angularjs-brunch [![Build Status](https://travis-ci.org/GulinSS/jade-angularjs-brunch.png?branch=master)](https://travis-ci.org/GulinSS/jade-angularjs-brunch) 2 | ===================== 3 | 4 | Compiler Jade templates to AngularJS modules for Brunch.IO with automatic section detection based on location of index.jade's. 5 | 6 | ## Step by step using guide 7 | 8 | For example you have a directory structure of your project such as: 9 | 10 | ``` 11 | app/ 12 | index.jade 13 | application.coffee 14 | welcome/ 15 | page.jade 16 | page.less 17 | controllers.coffee 18 | directives.coffee 19 | otherStuff.coffee 20 | access/ 21 | index.jade 22 | application.coffee 23 | register/ 24 | page.jade 25 | page.less 26 | controllers.coffee 27 | directives.coffee 28 | otherStuff.coffee 29 | login/ 30 | ... 31 | admin/ 32 | index.jade 33 | application.coffee 34 | users/ 35 | ... 36 | records/ 37 | ... 38 | landing/ 39 | index.jade 40 | ... 41 | 42 | ``` 43 | 44 | The key note of example above is location of index.jade's. Them will be compile as usual jade files into index.html's. Your public folder will have such structure: 45 | 46 | ``` 47 | _public/ 48 | index.html 49 | access/ 50 | index.html 51 | admin/ 52 | index.html 53 | landing/ 54 | index.html 55 | 56 | ``` 57 | 58 | And as addition it will group "partials" (files like page.jade in example) of this section into javascript files: 59 | 60 | ``` 61 | _public/ 62 | js/ 63 | app.templates.js # it will contains compiled content of 64 | # app/welcome/page.jade and any jades in subdirectories 65 | 66 | app.access.templates.js # it will contains compiled content of 67 | # app/access/register/page.jade and 68 | # app/access/login/page.jade 69 | # and any jades in subdirectories 70 | 71 | app.admin.templates.js # ... 72 | ... 73 | ``` 74 | 75 | Any file in example above will contains declaration of Angular.js module with same name: 76 | 77 | ``` 78 | app.templates.js -> app.templates 79 | app.access.templates.js -> app.access.templates 80 | ... 81 | ``` 82 | 83 | Modules must be registered in application.coffee's files such as: 84 | 85 | ``` 86 | App = angular.module('app', [ 87 | ... 88 | 89 | 'app.templates' 90 | ]) 91 | ``` 92 | 93 | After action above you can use your template in your code like this: 94 | 95 | ``` 96 | $routeProvider 97 | .when('/welcome', {templateUrl: 'app/welcome/page.jade'}) 98 | ``` 99 | 100 | or in directive's templateUrl. 101 | 102 | This magic helps you split your large application on small SPA sections for improving performance and control complexity. 103 | 104 | ## Sample of settings (DEPRECATED) 105 | 106 | ### Add to dependencies section in package.json of your project: 107 | 108 | `` "jade-angularjs-brunch" : ">= 0.0.1 < 1.5" `` 109 | 110 | ### Add to paths section in config.coffee: 111 | 112 | ```coffee 113 | jadeCompileTrigger: '.compile-jade' # Defaults to 'js/dontUseMe'. 114 | ``` 115 | 116 | ### Add to templates section in config.coffee: 117 | 118 | ```coffee 119 | joinTo: 120 | '.compile-jade': /^app/ # Hack for auto-compiling Jade templates. 121 | ``` 122 | 123 | ### Add to plugin section in config.coffee: 124 | 125 | ```coffee 126 | plugins: 127 | jade: 128 | pretty: yes # Adds pretty-indentation whitespaces to output (false by default). 129 | doctype: "xml" # Specify doctype ("5" by default). 130 | jade_angular: 131 | modules_folder: 'templates' 132 | locals: {} 133 | ``` 134 | 135 | * modules_folder: folder with your template 136 | * locals: context for jade compiler 137 | 138 | ### Now you can get angular.js modules: 139 | 140 | _public/js/login.template.js: 141 | 142 | ```js 143 | angular.module('login.templates', []) 144 | .run(['$templateCache', function($templateCache) { 145 | return $templateCache.put('/login/modal.page.html', [ 146 | 'This is content of your jade-file',''].join("\n")); 147 | }]) 148 | ``` 149 | 150 | # Single-File Mode 151 | 152 | If you want a single file instead of a file per module, you can use the `single_file` option in `jade_angular`. 153 | 154 | ```coffee 155 | plugins: 156 | jade_angular: 157 | single_file: true 158 | # if you want to change the file name (defaults to js/templates.js and is in your public directory) 159 | single_file_name: 'js/angular_templates.js' 160 | ``` 161 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | rd /s /q lib 2 | coffee -wo lib/ src/ 3 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/bash 2 | rm -rf lib 3 | coffee -wo lib/ src/ 4 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.6.3 2 | (function() { 3 | var JadeAngularJsCompiler, fileWriter, fs, jade, mkdirp, sysPath, _; 4 | 5 | jade = require('jade'); 6 | 7 | sysPath = require('path'); 8 | 9 | mkdirp = require('mkdirp'); 10 | 11 | fs = require('fs'); 12 | 13 | _ = require('lodash'); 14 | 15 | fileWriter = function(newFilePath) { 16 | return function(err, content) { 17 | var dirname; 18 | if (err != null) { 19 | throw err; 20 | } 21 | if (content == null) { 22 | return; 23 | } 24 | dirname = sysPath.dirname(newFilePath); 25 | return mkdirp(dirname, '0775', function(err) { 26 | if (err != null) { 27 | throw err; 28 | } 29 | return fs.writeFile(newFilePath, content, function(err) { 30 | if (err != null) { 31 | throw err; 32 | } 33 | }); 34 | }); 35 | }; 36 | }; 37 | 38 | module.exports = JadeAngularJsCompiler = (function() { 39 | JadeAngularJsCompiler.prototype.brunchPlugin = true; 40 | 41 | JadeAngularJsCompiler.prototype.type = 'template'; 42 | 43 | JadeAngularJsCompiler.prototype.extension = 'jade'; 44 | 45 | function JadeAngularJsCompiler(config) { 46 | var _ref, _ref1, _ref10, _ref11, _ref12, _ref13, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9; 47 | this["public"] = ((_ref = config.paths) != null ? _ref["public"] : void 0) || "_public"; 48 | this.pretty = !!((_ref1 = config.plugins) != null ? (_ref2 = _ref1.jade) != null ? _ref2.pretty : void 0 : void 0); 49 | this.doctype = ((_ref3 = config.plugins) != null ? (_ref4 = _ref3.jade) != null ? _ref4.doctype : void 0 : void 0) || "5"; 50 | this.locals = ((_ref5 = config.plugins) != null ? (_ref6 = _ref5.jade_angular) != null ? _ref6.locals : void 0 : void 0) || {}; 51 | this.staticMask = ((_ref7 = config.plugins) != null ? (_ref8 = _ref7.jade_angular) != null ? _ref8.static_mask : void 0 : void 0) || /index.jade/; 52 | this.compileTrigger = sysPath.normalize(this["public"] + sysPath.sep + (((_ref9 = config.paths) != null ? _ref9.jadeCompileTrigger : void 0) || 'js/dontUseMe')); 53 | this.singleFile = !!((_ref10 = config.plugins) != null ? (_ref11 = _ref10.jade_angular) != null ? _ref11.single_file : void 0 : void 0); 54 | this.singleFileName = sysPath.join(this["public"], (config != null ? (_ref12 = config.plugins) != null ? (_ref13 = _ref12.jade_angular) != null ? _ref13.single_file_name : void 0 : void 0 : void 0) || "js/angular_templates.js"); 55 | } 56 | 57 | JadeAngularJsCompiler.prototype.compile = function(data, path, callback) { 58 | var content, err, error; 59 | try { 60 | return data; 61 | } catch (_error) { 62 | err = _error; 63 | return error = err; 64 | } finally { 65 | callback(error, ""); 66 | } 67 | }; 68 | 69 | JadeAngularJsCompiler.prototype.preparePairStatic = function(pair) { 70 | pair.path.push(pair.path.pop().slice(0, -this.extension.length) + 'html'); 71 | return pair.path.splice(0, 1, this["public"]); 72 | }; 73 | 74 | JadeAngularJsCompiler.prototype.writeStatic = function(pairs) { 75 | var _this = this; 76 | return _.each(pairs, function(pair) { 77 | var writer; 78 | _this.preparePairStatic(pair); 79 | writer = fileWriter(sysPath.join.apply(_this, pair.path)); 80 | return writer(null, pair.result); 81 | }); 82 | }; 83 | 84 | JadeAngularJsCompiler.prototype.parsePairsIntoAssetsTree = function(pairs) { 85 | var assets, root, 86 | _this = this; 87 | assets = _.map(pairs, function(v) { 88 | return _this.removeFileNameFromPath(v.path); 89 | }); 90 | root = []; 91 | _.each(assets, function(path) { 92 | var node; 93 | node = root; 94 | return _.each(path, function(v) { 95 | var child; 96 | child = _.find(node, function(vv) { 97 | return vv.name === v; 98 | }); 99 | if (child === void 0) { 100 | child = { 101 | name: v, 102 | children: [] 103 | }; 104 | node.push(child); 105 | } 106 | return node = child.children; 107 | }); 108 | }); 109 | return root; 110 | }; 111 | 112 | JadeAngularJsCompiler.prototype.attachModuleNameToTemplate = function(pair, assetsTree) { 113 | var findedPath, node, path; 114 | path = this.removeFileNameFromPath(pair.path); 115 | if (assetsTree.length === 0) { 116 | pair.module = "" + path[0] + ".templates"; 117 | return; 118 | } 119 | findedPath = []; 120 | node = assetsTree; 121 | _.each(path, function(v) { 122 | var child; 123 | child = _.find(node, function(vv) { 124 | return vv.name === v; 125 | }); 126 | if (child === void 0) { 127 | return; 128 | } 129 | findedPath.push(child.name); 130 | return node = child.children; 131 | }); 132 | findedPath.push("templates"); 133 | return pair.module = findedPath.join('.'); 134 | }; 135 | 136 | JadeAngularJsCompiler.prototype.removeFileNameFromPath = function(path) { 137 | return path.slice(0, -1); 138 | }; 139 | 140 | JadeAngularJsCompiler.prototype.generateModuleFileName = function(module) { 141 | return module.filename = sysPath.join.apply(this, [this["public"], 'js', module.name + ".js"]); 142 | }; 143 | 144 | JadeAngularJsCompiler.prototype.writeModules = function(modules) { 145 | var buildModule, content, writer, 146 | _this = this; 147 | buildModule = function(module) { 148 | var addEndOfModule, content, moduleHeader, templateRecord; 149 | moduleHeader = function(name) { 150 | return "angular.module('" + name + "', [])"; 151 | }; 152 | templateRecord = function(result, path) { 153 | var parseStringToJSArray; 154 | parseStringToJSArray = function(str) { 155 | var stringArray; 156 | stringArray = '['; 157 | str.split('\n').map(function(e, i) { 158 | return stringArray += "\n'" + e.replace(/'/g, "\\'") + "',"; 159 | }); 160 | return stringArray += "''" + '].join("\\n")'; 161 | }; 162 | return "\n.run(['$templateCache', function($templateCache) {\n return $templateCache.put('" + path + "', " + (parseStringToJSArray(result)) + ");\n}])"; 163 | }; 164 | addEndOfModule = function() { 165 | return ";\n"; 166 | }; 167 | content = moduleHeader(module.name); 168 | _.each(module.templates, function(template) { 169 | return content += templateRecord(template.result, template.path); 170 | }); 171 | return content += addEndOfModule(); 172 | }; 173 | content = ""; 174 | _.each(modules, function(module) { 175 | var moduleContent, writer; 176 | moduleContent = buildModule(module); 177 | if (_this.singleFile) { 178 | return content += "\n" + moduleContent; 179 | } else { 180 | writer = fileWriter(module.filename); 181 | return writer(null, moduleContent); 182 | } 183 | }); 184 | if (this.singleFile) { 185 | writer = fileWriter(this.singleFileName); 186 | return writer(null, content); 187 | } 188 | }; 189 | 190 | JadeAngularJsCompiler.prototype.prepareResult = function(compiled) { 191 | var pathes, 192 | _this = this; 193 | pathes = _.find(compiled, function(v) { 194 | return v.path === _this.compileTrigger; 195 | }); 196 | if (pathes === void 0) { 197 | return []; 198 | } 199 | return pathes.sourceFiles.map(function(e, i) { 200 | var content, data; 201 | data = fs.readFileSync(e.path, 'utf8'); 202 | content = jade.compile(data, { 203 | compileDebug: false, 204 | client: false, 205 | filename: e.path, 206 | doctype: _this.doctype, 207 | pretty: _this.pretty 208 | }); 209 | return { 210 | path: e.path.split(sysPath.sep), 211 | result: content(_this.locals) 212 | }; 213 | }); 214 | }; 215 | 216 | JadeAngularJsCompiler.prototype.onCompile = function(compiled) { 217 | var assets, assetsTree, preResult, 218 | _this = this; 219 | preResult = this.prepareResult(compiled); 220 | if (preResult.length === 0) { 221 | return; 222 | } 223 | assets = _.filter(preResult, function(v) { 224 | return _this.staticMask.test(v.path); 225 | }); 226 | assetsTree = this.parsePairsIntoAssetsTree(assets); 227 | this.writeStatic(assets); 228 | return this.writeModules(_.chain(preResult).difference(assets).each(function(v) { 229 | return _this.attachModuleNameToTemplate(v, assetsTree); 230 | }).each(function(v) { 231 | return v.path = v.path.join('/'); 232 | }).groupBy(function(v) { 233 | return v.module; 234 | }).map(function(v, k) { 235 | return { 236 | name: k, 237 | templates: v 238 | }; 239 | }).each(function(v) { 240 | return _this.generateModuleFileName(v); 241 | }).value()); 242 | }; 243 | 244 | return JadeAngularJsCompiler; 245 | 246 | })(); 247 | 248 | }).call(this); 249 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jade-angularjs-brunch", 3 | "version": "1.1.1", 4 | "description": "Adds Jade support to brunch with angularjs template cache modules.", 5 | "author": { 6 | "name": "Gulin Serge", 7 | "url": "http://gulin.pro/" 8 | }, 9 | "homepage": "https://github.com/GulinSS/jade-angularjs-brunch", 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:GulinSS/jade-angularjs-brunch.git" 13 | }, 14 | "main": "./lib/index", 15 | "scripts": { 16 | "postinstall": "node setup.js postinstall", 17 | "test": "node setup.js test" 18 | }, 19 | "engines": { 20 | "node": "~0.6.10 || 0.8 || 0.9 || 0.10" 21 | }, 22 | "dependencies": { 23 | "coffee-script": "1.3.3", 24 | "jade": "~1.3.0", 25 | "mkdirp": "*", 26 | "lodash": "~0.9.0" 27 | }, 28 | "devDependencies": { 29 | "mocha": "*", 30 | "chai": "*", 31 | "sinon": "~1.7.3", 32 | "sinon-chai": "~2.4.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | var exec = require('child_process').exec; 2 | var sysPath = require('path'); 3 | var fs = require('fs'); 4 | 5 | var mode = process.argv[2]; 6 | 7 | var fsExists = fs.exists || sysPath.exists; 8 | 9 | var execute = function(pathParts, params, callback) { 10 | if (callback == null) callback = function() {}; 11 | var path = sysPath.join.apply(null, pathParts); 12 | var command = 'node ' + path + ' ' + params; 13 | console.log('Executing', command); 14 | exec(command, function(error, stdout, stderr) { 15 | if (error != null) return process.stderr.write(stderr.toString()); 16 | console.log(stdout.toString()); 17 | }); 18 | }; 19 | 20 | if (mode === 'postinstall') { 21 | fsExists(sysPath.join(__dirname, 'lib'), function(exists) { 22 | if (exists) return; 23 | execute(['node_modules', 'coffee-script', 'bin', 'coffee'], '-o lib/ src/'); 24 | }); 25 | } else if (mode === 'test') { 26 | execute(['node_modules', 'coffee-script', 'bin', 'coffee'], '-o lib/ src/'); 27 | execute(['node_modules', 'mocha', 'bin', 'mocha'], 28 | '--require test/common.js --require coffee-script --compilers coffee:coffee-script --colors -R \'spec\' --ui \'bdd\''); 29 | } 30 | -------------------------------------------------------------------------------- /src/index.coffee: -------------------------------------------------------------------------------- 1 | jade = require 'jade' 2 | sysPath = require 'path' 3 | mkdirp = require 'mkdirp' 4 | fs = require 'fs' 5 | _ = require 'lodash' 6 | 7 | fileWriter = (newFilePath) -> (err, content) -> 8 | throw err if err? 9 | return if not content? 10 | dirname = sysPath.dirname newFilePath 11 | mkdirp dirname, '0775', (err) -> 12 | throw err if err? 13 | fs.writeFile newFilePath, content, (err) -> throw err if err? 14 | 15 | module.exports = class JadeAngularJsCompiler 16 | brunchPlugin: yes 17 | type: 'template' 18 | extension: 'jade' 19 | 20 | # TODO: group parameters 21 | constructor: (config) -> 22 | @public = config.paths?.public or "_public" 23 | @pretty = !!config.plugins?.jade?.pretty 24 | @doctype = config.plugins?.jade?.doctype or "5" 25 | @locals = config.plugins?.jade_angular?.locals or {} 26 | @staticMask = config.plugins?.jade_angular?.static_mask or /index.jade/ 27 | @compileTrigger = sysPath.normalize @public + sysPath.sep + (config.paths?.jadeCompileTrigger or 'js/dontUseMe') 28 | @singleFile = !!config.plugins?.jade_angular?.single_file 29 | @singleFileName = sysPath.join @public, (config?.plugins?.jade_angular?.single_file_name or "js/angular_templates.js") 30 | 31 | preparePairStatic: (pair) -> 32 | pair.path.push(pair.path.pop()[...-@extension.length] + 'html') 33 | pair.path.splice 0, 1, @public 34 | 35 | writeStatic: (pairs) -> 36 | _.each pairs, (pair) => 37 | @preparePairStatic pair 38 | writer = fileWriter sysPath.join.apply(this, pair.path) 39 | writer null, pair.result 40 | 41 | parsePairsIntoAssetsTree: (pairs) -> 42 | assets = _.map(pairs, (v) => @removeFileNameFromPath v.path) 43 | root = [] 44 | 45 | _.each assets, (path) -> 46 | node = root 47 | _.each path, (v) -> 48 | child = _.find node, (vv) -> vv.name is v 49 | 50 | if child is undefined 51 | child = 52 | name: v 53 | children: [] 54 | 55 | node.push child 56 | 57 | node = child.children 58 | 59 | return root 60 | 61 | attachModuleNameToTemplate: (pair, assetsTree) -> 62 | path = @removeFileNameFromPath pair.path 63 | 64 | if assetsTree.length is 0 65 | pair.module = "#{path[0]}.templates" 66 | return 67 | 68 | findedPath = [] 69 | node = assetsTree 70 | _.each path, (v) -> 71 | child = _.find node, (vv) -> vv.name is v 72 | return if child is undefined 73 | 74 | findedPath.push child.name 75 | node = child.children 76 | 77 | findedPath.push "templates" 78 | 79 | pair.module = findedPath.join '.' 80 | 81 | removeFileNameFromPath: (path) -> path[0..-2] 82 | 83 | generateModuleFileName: (module) -> 84 | module.filename = sysPath.join.apply(this, [@public, 'js', module.name+".js"]) 85 | 86 | writeModules: (modules) -> 87 | 88 | buildModule = (module) -> 89 | moduleHeader = (name) -> 90 | """ 91 | angular.module('#{name}', []) 92 | """ 93 | 94 | templateRecord = (result, path) -> 95 | parseStringToJSArray = (str) -> 96 | stringArray = '[' 97 | str.split('\n').map (e, i) -> 98 | stringArray += "\n'" + e.replace(/'/g, "\\'") + "'," 99 | stringArray += "''" + '].join("\\n")' 100 | 101 | """ 102 | \n.run(['$templateCache', function($templateCache) { 103 | return $templateCache.put('#{path}', #{parseStringToJSArray(result)}); 104 | }]) 105 | """ 106 | 107 | addEndOfModule = -> ";\n" 108 | 109 | content = moduleHeader module.name 110 | 111 | _.each module.templates, (template) -> 112 | content += templateRecord template.result, template.path 113 | 114 | content += addEndOfModule() 115 | 116 | content = "" 117 | 118 | _.each modules, (module) => 119 | moduleContent = buildModule module 120 | 121 | if @singleFile 122 | content += "\n#{moduleContent}" 123 | else 124 | writer = fileWriter module.filename 125 | writer null, moduleContent 126 | 127 | if @singleFile 128 | writer = fileWriter @singleFileName 129 | writer null, content 130 | 131 | prepareResult: (compiled) -> 132 | pathes = _.find compiled, (v) => v.path is @compileTrigger 133 | 134 | return [] if pathes is undefined 135 | 136 | pathes.sourceFiles.map (e, i) => 137 | data = fs.readFileSync e.path, 'utf8' 138 | content = jade.compile data, 139 | compileDebug: no, 140 | client: no, 141 | filename: e.path, 142 | doctype: @doctype 143 | pretty: @pretty 144 | 145 | path: e.path.split sysPath.sep 146 | result: content @locals 147 | 148 | onCompile: (compiled) -> 149 | preResult = @prepareResult compiled 150 | 151 | # Need to stop processing if there's nothing to process 152 | return if preResult.length is 0 153 | 154 | assets = _.filter preResult, (v) => @staticMask.test v.path 155 | assetsTree = @parsePairsIntoAssetsTree assets 156 | 157 | @writeStatic assets 158 | 159 | @writeModules _.chain(preResult) 160 | .difference(assets) 161 | .each((v) => @attachModuleNameToTemplate v, assetsTree) 162 | .each((v) -> v.path = v.path.join('/')) # concat items to virtual url 163 | .groupBy((v) -> v.module) 164 | .map((v, k) -> name: k, templates: v) 165 | .each((v) => @generateModuleFileName v) 166 | .value() 167 | -------------------------------------------------------------------------------- /test/JadeAngularJsCompiler.coffee: -------------------------------------------------------------------------------- 1 | describe "JadeAngularJsCompiler", -> 2 | describe "Public surface", -> 3 | it "Should exists", -> 4 | Plugin.should.exist 5 | Plugin.name.should.equal "JadeAngularJsCompiler" 6 | 7 | it "Accept contract of Brunch plugin", -> 8 | Plugin.prototype.should.contain.keys [ 9 | "compile" 10 | "onCompile" 11 | "brunchPlugin" 12 | "type" 13 | "extension" 14 | ] 15 | 16 | describe "In action", -> 17 | plugin = null 18 | _public = "_public" 19 | compileTrigger = "#{_public}/js/dontUseMe" 20 | fileHtmlContent = "" 21 | 22 | beforeEach -> 23 | plugin = new Plugin({}) 24 | 25 | it "Constructor's parameters defaults", -> 26 | _public = "_public" 27 | 28 | defaults = 29 | public: _public 30 | pretty: false 31 | doctype: "5" 32 | staticMask: /index.jade/ 33 | compileTrigger: compileTrigger 34 | singleFile: false 35 | singleFileName: "#{_public}/js/angular_templates.js" 36 | 37 | for k, v of defaults 38 | plugin[k].should.deep.equal v 39 | 40 | Object.keys(plugin.locals).should.have.length 0 41 | 42 | describe "Standart compile hook", -> 43 | it "Pass errors of Jade's content compilation", -> 44 | plugin.compile "mixin asd", "index.jade", (error, content) -> 45 | error.should.instanceOf TypeError 46 | content.should.equal "" 47 | 48 | it "Returns empty string to callack everytime", -> 49 | plugin.compile "!!!", "index.jade", (error, content) -> 50 | expect(error).to.equal undefined 51 | content.should.equal "" 52 | 53 | describe "Parts of main function", -> 54 | describe "prepareResult", -> 55 | it "Must return empty array if input don't have compileTrigger's path", -> 56 | result = plugin.prepareResult([ 57 | sourceFiles: [] 58 | path: "" 59 | ]) 60 | 61 | result.should.have.length 0 62 | 63 | it "Must return pairs with path and result on correct compileTrigger", -> 64 | result = plugin.prepareResult([ 65 | sourceFiles: [ 66 | path: "test/folder/partial1.jade" 67 | , 68 | path: "test/folder/partial2.jade" 69 | ] 70 | path: compileTrigger 71 | ]) 72 | 73 | result.should.be.an('array') 74 | 75 | for v, i in ['partial1.jade', 'partial2.jade'] 76 | r = result[i] 77 | r.should.contain.keys(['path', 'result']) 78 | r.path.should.be.an('array') 79 | r.path.should.be.deep.equal(['test', 'folder', v]) 80 | r.result.should.be.an('string') 81 | r.result.should.be.equal fileHtmlContent 82 | 83 | describe "writeModules", -> 84 | it "Must write templates into root module", (done) -> 85 | tempFileName = "temp.tmp" 86 | 87 | plugin.writeModules([ 88 | name: "myModule" 89 | filename: tempFileName 90 | templates: [ 91 | path: "hello.tmp" 92 | result: "Hello!" 93 | , 94 | path: "hello2.tmp" 95 | result: "Hello!2" 96 | ] 97 | , 98 | name: "myModule2" 99 | filename: tempFileName+1 100 | templates: [ 101 | path: "hello3.tmp" 102 | result: "Hello!2-1" 103 | ] 104 | ]) 105 | 106 | setTimeout -> 107 | 108 | contentFirst = fs.readFileSync tempFileName, encoding: "utf8" 109 | contentFirst.should.equal(""" 110 | angular.module('myModule', []) 111 | .run(['$templateCache', function($templateCache) { 112 | return $templateCache.put('hello.tmp', [ 113 | 'Hello!',''].join("\\n")); 114 | }]) 115 | .run(['$templateCache', function($templateCache) { 116 | return $templateCache.put('hello2.tmp', [ 117 | 'Hello!2',''].join("\\n")); 118 | }]);\n 119 | """) 120 | 121 | contentSecond = fs.readFileSync tempFileName+1, encoding: "utf8" 122 | contentSecond.should.equal(""" 123 | angular.module('myModule2', []) 124 | .run(['$templateCache', function($templateCache) { 125 | return $templateCache.put('hello3.tmp', [ 126 | 'Hello!2-1',''].join("\\n")); 127 | }]);\n 128 | """) 129 | 130 | fs.unlinkSync tempFileName 131 | fs.unlinkSync tempFileName+1 132 | done() 133 | , 250 134 | 135 | xit "TODO: test for singleFile", -> 136 | true.should.be.equal true 137 | 138 | xit "TODO: parse string to JSArray", -> 139 | true.should.be.equal true 140 | 141 | describe "writeStatic", -> 142 | xit "TODO: write content to file", -> 143 | 144 | describe "preparePairStatic", -> 145 | it "Change file extension from jade to html, add result public folder as first and remove second folder like \'app\'. Used only by writeStatic.", -> 146 | path = ['folder', 'file', 'jade'] 147 | 148 | plugin.preparePairStatic 149 | path: path 150 | 151 | path.should.be.deep.equal ['_public', 'file', 'html'] 152 | 153 | describe "parsePairsIntoAssetsTree", -> 154 | it "Translate paths of pairs into assets tree", -> 155 | pairs = [ 156 | path: ["app", "folder", "file.name"] 157 | , 158 | path: ["app", "folder", "file2.name"] 159 | , 160 | path: ["app", "folder", "folder", "file.name"] 161 | , 162 | path: ["app", "folder2", "file.name"] 163 | ] 164 | 165 | result = plugin.parsePairsIntoAssetsTree pairs 166 | 167 | result.should.deep.equal [ 168 | name: "app" 169 | children: [ 170 | name: "folder" 171 | children: [ 172 | name: "folder" 173 | children: [] 174 | ] 175 | , 176 | name: "folder2" 177 | children: [] 178 | ] 179 | ] 180 | 181 | describe "attachModuleNameToTemplate", -> 182 | assetsTree = [ 183 | name: "app" 184 | children: [ 185 | name: "folder" 186 | children: [] 187 | ] 188 | ] 189 | 190 | it "Pair in a folder with static page should be placed in one module", -> 191 | pair = 192 | path: ['app', 'file.jade'] 193 | content: "" 194 | 195 | plugin.attachModuleNameToTemplate pair, assetsTree 196 | 197 | pair.should.contain.keys ['module'] 198 | pair.module.should.equal "app.templates" 199 | 200 | it "Pair should be placed in child module in a case when a folder with index.jade has child folder with own index.jade", -> 201 | pair = 202 | path: ['app', 'folder', 'file.jade'] 203 | content: "" 204 | 205 | plugin.attachModuleNameToTemplate pair, assetsTree 206 | 207 | pair.should.contain.keys ['module'] 208 | pair.module.should.equal "app.folder.templates" 209 | 210 | it "Pair in deeper path of the last folder with index.jade should be placed in last parent", -> 211 | pair = 212 | path: ['app', 'folder', 'folder', 'file.jade'] 213 | content: "" 214 | 215 | plugin.attachModuleNameToTemplate pair, assetsTree 216 | 217 | pair.should.contain.keys ['module'] 218 | pair.module.should.equal "app.folder.templates" 219 | 220 | it "If application don't have any static assets all jade files will be stored in top module", -> 221 | pair = 222 | path: ['app', 'folder', 'file.jade'] 223 | content: "" 224 | 225 | plugin.attachModuleNameToTemplate pair, [] 226 | 227 | pair.should.contain.keys ['module'] 228 | pair.module.should.equal "app.templates" 229 | 230 | describe "generateModuleFileName", -> 231 | it "Generate module file name for writting", -> 232 | module = 233 | name: "filename" 234 | 235 | plugin.generateModuleFileName module 236 | 237 | module.should.contain.keys ['filename'] 238 | module.filename.should.equal "#{plugin.public}/js/filename.js" 239 | 240 | describe "Post-compile hook", -> 241 | data = [ 242 | sourceFiles: [ 243 | path: "test/folder/index.jade" 244 | , 245 | path: "test/folder/partial1.jade" 246 | , 247 | path: "test/folder/partial2.jade" 248 | , 249 | path: "test/folder/folder/index.jade" 250 | , 251 | path: "test/folder/folder/partial1.jade" 252 | , 253 | path: "test/folder/folder/partial2.jade" 254 | ] 255 | path: compileTrigger 256 | ] 257 | 258 | beforeEach -> 259 | sinon.stub(plugin, "writeModules") 260 | sinon.stub(plugin, "writeStatic") 261 | 262 | afterEach -> 263 | plugin.writeModules.restore() 264 | plugin.writeStatic.restore() 265 | 266 | it "Anyway on test data it should call write methods for modules and assets", -> 267 | plugin.onCompile data 268 | plugin.writeStatic.should.have.been.calledOnce 269 | plugin.writeModules.should.have.been.calledOnce 270 | 271 | it "For static jade files (valid for staticMask) it should write them \'as is\'", -> 272 | expect = [ 273 | path: [ 'test', 'folder', 'index.jade' ] 274 | result: '' 275 | , 276 | path: [ 'test', 'folder', 'folder', 'index.jade' ] 277 | result: '' 278 | ] 279 | 280 | plugin.onCompile data 281 | 282 | plugin.writeStatic.args[0].should.length 1 283 | plugin.writeStatic.args[0][0].should.deep.equal expect 284 | 285 | it "For modules it should filtered and grouped them correct", -> 286 | expect = [ 287 | name: 'test.folder.templates' 288 | templates: [ 289 | path: 'test/folder/partial1.jade' 290 | result: '' 291 | module: 'test.folder.templates' 292 | , 293 | path: 'test/folder/partial2.jade' 294 | result: '' 295 | module: 'test.folder.templates' 296 | ] 297 | filename: '_public/js/test.folder.templates.js' 298 | , 299 | name: 'test.folder.folder.templates', 300 | templates: [ 301 | path: 'test/folder/folder/partial1.jade' 302 | result: '' 303 | module: 'test.folder.folder.templates' 304 | , 305 | path: 'test/folder/folder/partial2.jade' 306 | result: '' 307 | module: 'test.folder.folder.templates' 308 | ], 309 | filename: '_public/js/test.folder.folder.templates.js' 310 | ] 311 | 312 | plugin.onCompile data 313 | 314 | plugin.writeModules.args[0].should.length 1 315 | plugin.writeModules.args[0][0].should.deep.equal expect -------------------------------------------------------------------------------- /test/common.js: -------------------------------------------------------------------------------- 1 | global.Plugin = require('../lib'); 2 | global.fs = require('fs'); 3 | global.sinon = require('sinon'); 4 | 5 | chai = require('chai'); 6 | chai.use(require('sinon-chai')); 7 | chai.should(); 8 | 9 | global.expect = chai.expect; 10 | 11 | -------------------------------------------------------------------------------- /test/folder/folder/index.jade: -------------------------------------------------------------------------------- 1 | !!! -------------------------------------------------------------------------------- /test/folder/folder/partial1.jade: -------------------------------------------------------------------------------- 1 | !!! -------------------------------------------------------------------------------- /test/folder/folder/partial2.jade: -------------------------------------------------------------------------------- 1 | !!! 2 | -------------------------------------------------------------------------------- /test/folder/index.jade: -------------------------------------------------------------------------------- 1 | !!! -------------------------------------------------------------------------------- /test/folder/partial1.jade: -------------------------------------------------------------------------------- 1 | !!! -------------------------------------------------------------------------------- /test/folder/partial2.jade: -------------------------------------------------------------------------------- 1 | !!! 2 | --------------------------------------------------------------------------------