Skip to content

Commit

Permalink
feat(build): add Jade support
Browse files Browse the repository at this point in the history
Added new --jade option to generator that will create Jade templates (http://jade-lang.com/)
  • Loading branch information
Gonzalo Ruiz de Villa committed Nov 7, 2013
1 parent 48eaaa2 commit 38e1290
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 24 deletions.
146 changes: 130 additions & 16 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ var Generator = module.exports = function Generator(args, options) {
this.env.options.coffee = this.options.coffee;
}

if (typeof this.env.options.jade === 'undefined') {
this.option('jade', {
desc: 'Generate Jade templates instead of HTML'
});

// attempt to detect if user is using jade or not
// if cml arg provided, use that; else look for the existence of cs
if (!this.options.jade &&
this.expandFiles(path.join(this.appPath, '/**/*.jade'), {}).length > 0) {
this.options.jade = true;
}

this.env.options.jade = this.options.jade;
}

if (typeof this.env.options.minsafe === 'undefined') {
this.option('minsafe', {
desc: 'Generate AngularJS minification safe code'
Expand Down Expand Up @@ -174,11 +189,72 @@ Generator.prototype.askForModules = function askForModules() {
};

Generator.prototype.readIndex = function readIndex() {
this.indexFile = this.engine(this.read('../../templates/common/index.html'), this);
var extension = this.env.options.jade ? "jade" : "html";
this.indexFile = this.engine(this.read('../../templates/common/index.' + extension), this);
};

function spacePrefix(jade, block){
var prefix;
jade.split('\n').forEach( function (line) { if( line.indexOf(block)> -1 ) {
prefix = line.split("/")[0];
}});
return prefix;
}

function generateJadeBlock(blockType, optimizedPath, filesBlock, searchPath, prefix) {
var blockStart, blockEnd;
var blockSearchPath = '';

if (searchPath !== undefined) {
if (util.isArray(searchPath)) {
searchPath = '{' + searchPath.join(',') + '}';
}
blockSearchPath = '(' + searchPath + ')';
}

blockStart = '\n' + prefix + '// build:' + blockType + blockSearchPath + ' ' + optimizedPath + ' \n';
blockEnd = prefix + '// endbuild\n' + prefix;
return blockStart + filesBlock + blockEnd;
}

function appendJade(jade, tag, blocks){
var mark = "//- build:" + tag,
position = jade.indexOf(mark);
return [jade.slice(0, position), blocks, jade.slice(position)].join('');
}

function appendFilesToJade(jadeOrOptions, fileType, optimizedPath, sourceFileList, attrs, searchPath) {
var blocks, updatedContent, prefix, jade, files = '';
jade = jadeOrOptions;
if (typeof jadeOrOptions === 'object') {
jade = jadeOrOptions.html;
fileType = jadeOrOptions.fileType;
optimizedPath = jadeOrOptions.optimizedPath;
sourceFileList = jadeOrOptions.sourceFileList;
attrs = jadeOrOptions.attrs;
searchPath = jadeOrOptions.searchPath;
}
if (fileType === 'js') {
prefix = spacePrefix(jade, "build:body");
sourceFileList.forEach(function (el) {
files += prefix + 'script(' + (attrs||'') + 'src="' + el + '")\n';
});
blocks = generateJadeBlock('js', optimizedPath, files, searchPath, prefix);
updatedContent = appendJade(jade, 'body', blocks);
} else if (fileType === 'css') {
prefix = spacePrefix(jade, "build:head");
sourceFileList.forEach(function (el) {
files += prefix + 'link(' + (attrs||'') + 'rel="stylesheet", href="' + el + '")\n';
});
blocks = generateJadeBlock('css', optimizedPath, files, searchPath, prefix);
updatedContent = appendJade(jade, 'head', blocks);
}
return updatedContent;
}

// Waiting a more flexible solution for #138
Generator.prototype.bootstrapFiles = function bootstrapFiles() {
var filesToAppend;
var sass = this.compassBootstrap;
var files = [];
var source = 'styles/' + ( sass ? 's' : '' ) + 'css/';
Expand All @@ -197,24 +273,36 @@ Generator.prototype.bootstrapFiles = function bootstrapFiles() {
this.copy(source + file, 'app/styles/' + file);
}.bind(this));

this.indexFile = this.appendFiles({
filesToAppend = {
html: this.indexFile,
fileType: 'css',
optimizedPath: 'styles/main.css',
sourceFileList: files.map(function (file) {
return 'styles/' + file.replace('.scss', '.css');
}),
searchPath: '.tmp'
});
};

if (this.env.options.jade) {
this.indexFile = appendFilesToJade(filesToAppend);
} else {
this.indexFile = this.appendFiles(filesToAppend);
}
};


function appendScriptsJade(jade, optimizedPath, sourceFileList, attrs) {
return appendFilesToJade(jade, 'js', optimizedPath, sourceFileList, attrs);
}

Generator.prototype.bootstrapJS = function bootstrapJS() {
var list;
if (!this.bootstrap) {
return; // Skip if disabled.
}

// Wire Twitter Bootstrap plugins
this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', [
list = [
'bower_components/sass-bootstrap/js/affix.js',
'bower_components/sass-bootstrap/js/alert.js',
'bower_components/sass-bootstrap/js/button.js',
Expand All @@ -226,8 +314,15 @@ Generator.prototype.bootstrapJS = function bootstrapJS() {
'bower_components/sass-bootstrap/js/scrollspy.js',
'bower_components/sass-bootstrap/js/tab.js',
'bower_components/sass-bootstrap/js/tooltip.js',
'bower_components/sass-bootstrap/js/transition.js',
]);
'bower_components/sass-bootstrap/js/transition.js'
];

if (this.env.options.jade) {
this.indexFile = appendScriptsJade(this.indexFile, 'scripts/plugins.js', list);
} else {
this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', list);
}

};

Generator.prototype.extraModules = function extraModules() {
Expand All @@ -245,27 +340,46 @@ Generator.prototype.extraModules = function extraModules() {
}

if (modules.length) {
this.indexFile = this.appendScripts(this.indexFile, 'scripts/modules.js',
modules);
if (this.env.options.jade) {
this.indexFile = appendScriptsJade(this.indexFile, 'scripts/plugins.js', modules);
} else {
this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', modules);
}
}
};

Generator.prototype.appJs = function appJs() {
this.indexFile = this.appendFiles({
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/scripts.js',
sourceFileList: ['scripts/app.js', 'scripts/controllers/main.js'],
searchPath: ['.tmp', 'app']
});
if (this.env.options.jade) {
this.indexFile = appendFilesToJade({
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/scripts.js',
sourceFileList: ['scripts/app.js'],
searchPath: ['.tmp', 'app']
});
} else {
this.indexFile = this.appendFiles({
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/scripts.js',
sourceFileList: ['scripts/app.js', 'scripts/controllers/main.js'],
searchPath: ['.tmp', 'app']
});
}
};

Generator.prototype.createIndexHtml = function createIndexHtml() {
this.write(path.join(this.appPath, 'index.html'), this.indexFile);
var indexFile = 'index.' + (this.env.options.jade ? 'jade' : 'html');
this.write(path.join(this.appPath, indexFile), this.indexFile);
};

Generator.prototype.packageFiles = function () {
this.template('../../templates/common/_bower.json', 'bower.json');
this.template('../../templates/common/_package.json', 'package.json');
this.template('../../templates/common/Gruntfile.js', 'Gruntfile.js');
};

Generator.prototype.addMainView = function addMainView() {
var mainFile = 'main.' + (this.env.options.jade ? 'jade' : 'html');
this.copy('../../templates/common/' + mainFile, 'app/views/' + mainFile);
};
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ angular.module('myMod').config(function ($provide) {
## Options
In general, these options can be applied to any generator, though they only affect generators that produce scripts.

### Jade
For generators that output html, the `--jade` option will output Jade instead of html files.

For example:
```bash
yo angular:view user --jade

Produces `app/scripts/views/user.jade`:
```jade
p This is the user view.
```

### CoffeeScript
For generators that output scripts, the `--coffee` option will output CoffeeScript instead of JavaScript.

Expand Down
44 changes: 41 additions & 3 deletions script-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ var Generator = module.exports = function Generator() {
this.env.options.coffee = this.options.coffee;
}

this.env.options.jade = this.options.jade;
if (typeof this.env.options.jade === 'undefined') {
this.option('jade');

// attempt to detect if user is using jade or not
// if cml arg provided, use that; else look for the existence of cs
if (!this.options.jade &&
this.expandFiles(path.join(this.env.options.appPath, '/**/*.jade'), {}).length > 0) {
this.options.jade = true;
}

this.env.options.jade = this.options.jade;
}

if (typeof this.env.options.minsafe === 'undefined') {
this.option('minsafe');
this.env.options.minsafe = this.options.minsafe;
Expand Down Expand Up @@ -89,9 +103,25 @@ Generator.prototype.htmlTemplate = function (src, dest) {
]);
};

Generator.prototype.addScriptToIndex = function (script) {
function addScriptToIndexJade(script, env) {
try {
var appPath = this.env.options.appPath;
var appPath = env.options.appPath;
var fullPath = path.join(appPath, 'index.jade');
angularUtils.rewriteFile({
file: fullPath,
needle: '// endbuild',
splicable: [
'script(src="scripts/' + script + '.js")'
]
});
} catch (e) {
console.log('\nUnable to find '.yellow + fullPath + '. Reference to '.yellow + script + '.js ' + 'not added.\n'.yellow);
}
}

function addScriptToIndexHtml(script, env) {
try {
var appPath = env.options.appPath;
var fullPath = path.join(appPath, 'index.html');
angularUtils.rewriteFile({
file: fullPath,
Expand All @@ -103,6 +133,14 @@ Generator.prototype.addScriptToIndex = function (script) {
} catch (e) {
console.log('\nUnable to find '.yellow + fullPath + '. Reference to '.yellow + script + '.js ' + 'not added.\n'.yellow);
}
}

Generator.prototype.addScriptToIndex = function (script) {
if (this.env.options.jade) {
addScriptToIndexJade(script, this.env);
} else {
addScriptToIndexHtml(script, this.env);
}
};

Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, targetDirectory, skipAdd) {
Expand All @@ -111,4 +149,4 @@ Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate,
if (!skipAdd) {
this.addScriptToIndex(path.join(targetDirectory, this.name));
}
};
};
29 changes: 29 additions & 0 deletions templates/common/Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ module.exports = function (grunt) {
files: ['<%%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},<% } %>
jade: {
files: ['<%%= yeoman.app %>/**/*.jade'],
tasks: ['jade']
},
styles: {
files: ['<%%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['copy:styles', 'autoprefixer']
Expand Down Expand Up @@ -174,6 +178,28 @@ module.exports = function (grunt) {
}
}
},
jade: {
index: {
files: {
'<%%= yeoman.app %>/': ['<%%= yeoman.app %>/index.jade']
},
options: {
basePath: '<%%= yeoman.app %>/',
client: false,
pretty: true
}
},
views: {
files: {
'<%%= yeoman.app %>/views/': ['<%%= yeoman.app %>/views/**/*.jade']
},
options: {
basePath: '<%%= yeoman.app %>/views',
client: false,
pretty: true
}
}
},
useminPrepare: {
html: '<%%= yeoman.app %>/index.html',
options: {
Expand Down Expand Up @@ -274,16 +300,19 @@ module.exports = function (grunt) {
},
concurrent: {
server: [
'jade',
'coffee:dist',<% if (compassBootstrap) { %>
'compass:server',<% } %>
'copy:styles'
],
test: [
'jade',
'coffee',<% if (compassBootstrap) { %>
'compass',<% } %>
'copy:styles'
],
dist: [
'jade',
'coffee',<% if (compassBootstrap) { %>
'compass:dist',<% } %>
'copy:styles',
Expand Down
1 change: 1 addition & 0 deletions templates/common/_package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"grunt-google-cdn": "~0.2.0",
"grunt-ngmin": "~0.0.2",
"time-grunt": "~0.1.0",
"grunt-jade": "~0.4.0",
"jshint-stylish": "~0.1.3"
},
"engines": {
Expand Down
Loading

0 comments on commit 38e1290

Please sign in to comment.