├── .gitignore ├── History.md ├── Makefile ├── Readme.md ├── bin └── ngen ├── package.json └── templates ├── default ├── content │ ├── .gitignore │ ├── .npmignore │ ├── History.md │ ├── Makefile │ ├── Readme.md │ ├── index.js │ ├── lib │ │ └── {{project}}.js │ ├── package.json │ └── test │ │ └── {{project}}.test.js └── index.js ├── git ├── content │ ├── .npmignore │ ├── History.md │ ├── Makefile │ ├── Readme.md │ ├── index.js │ ├── lib │ │ └── {{project}}.js │ ├── package.json │ └── test │ │ └── {{project}}.test.js └── index.js └── modular ├── content ├── .gitignore ├── .npmignore ├── config.json ├── config │ └── db.js ├── lib │ ├── helpers.js │ └── loader.js ├── modules │ ├── express │ │ ├── server.js │ │ └── static.js │ ├── utils.js │ └── your_site │ │ └── pages.js ├── package.json ├── run.js ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── main.js └── views │ ├── layout.ejs │ └── pages │ └── index.ejs └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.1.0 / 2012-06-27 3 | ================== 4 | 5 | * add mocha to default template 6 | 7 | 1.0.2 / 2012-06-25 8 | ================== 9 | 10 | * remove engine crap 11 | 12 | 1.0.1 / 2012-05-07 13 | ================== 14 | 15 | * Removing extra commas from git package.json template. 16 | 17 | 1.0.0 / 2011-12-19 18 | ================== 19 | 20 | * 0.4.x -> 0.6.x for generated template 21 | 22 | 0.0.5 / 2011-05-24 23 | ================== 24 | 25 | * Added a cli option to specify an alternate template directory [recursivevirus] 26 | * Added callback support for vars [Gozala] 27 | * Added "modular" template [donnerjack13589] 28 | 29 | 30 | 0.0.4 / 2011-04-06 31 | ================== 32 | 33 | * Added .gitignore to default template. Closes #3 34 | 35 | 0.0.3 / 2011-03-13 36 | ================== 37 | 38 | * Removed extra `package.json` commas. Closes #2 39 | 40 | 0.0.2 / 2011-03-07 41 | ================== 42 | 43 | * Fixed project test var 44 | 45 | 0.0.1 / 2010-01-03 46 | ================== 47 | 48 | * Initial release 49 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @./support/expresso/bin/expresso \ 4 | -I lib 5 | 6 | .PHONY: test -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # NGen 3 | 4 | NGen is a nodejs package generator, complete with best practices, package structure, package.json and more. 5 | 6 | ## Installation 7 | 8 | $ npm install ngen 9 | 10 | ## Usage 11 | 12 | 13 | Usage: ngen [options] [path] 14 | 15 | Options: 16 | 17 | -t, --template Use the template 18 | -d, --directory Use the template directory 19 | -V, --version Output the current version 20 | -h, --help Display help information 21 | 22 | 23 | ## Templates 24 | 25 | ### Default 26 | 27 | Currently the only available template, creating the following structure populated with content after the following questions are asked from the cli: 28 | 29 | Project name: foo 30 | Enter your name: TJ Holowaychuk 31 | Enter your email: tj@vision-media.ca 32 | Project description: awesome foo-ness 33 | 34 | structure: 35 | 36 | ./History.md 37 | ./Readme.md 38 | ./index.js 39 | ./lib/.js 40 | ./test/.test.js 41 | ./support 42 | ./Makefile 43 | ./package.json 44 | 45 | ## License 46 | 47 | (The MIT License) 48 | 49 | Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> 50 | 51 | Permission is hereby granted, free of charge, to any person obtaining 52 | a copy of this software and associated documentation files (the 53 | 'Software'), to deal in the Software without restriction, including 54 | without limitation the rights to use, copy, modify, merge, publish, 55 | distribute, sublicense, and/or sell copies of the Software, and to 56 | permit persons to whom the Software is furnished to do so, subject to 57 | the following conditions: 58 | 59 | The above copyright notice and this permission notice shall be 60 | included in all copies or substantial portions of the Software. 61 | 62 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 63 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 64 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 65 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 66 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 67 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 68 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /bin/ngen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // vim:ft=javascript: 3 | 4 | /** 5 | * Module dependencies. 6 | */ 7 | 8 | var fs = require('fs') 9 | , join = require('path').join; 10 | 11 | /** 12 | * Arguments. 13 | */ 14 | 15 | var args = process.argv.slice(2); 16 | 17 | /** 18 | * Executable version. 19 | */ 20 | 21 | var version = '1.1.0'; 22 | 23 | /** 24 | * Templates directory. 25 | */ 26 | 27 | var templates = __dirname + '/../templates'; 28 | 29 | /** 30 | * Template. 31 | */ 32 | 33 | var template = 'default'; 34 | 35 | /** 36 | * Destination path. 37 | */ 38 | 39 | var dest = process.cwd(); 40 | 41 | /** 42 | * Usage information. 43 | */ 44 | 45 | var usage = [ 46 | '' 47 | , ' Usage: ngen [options] [path]' 48 | , '' 49 | , ' Options:' 50 | , '' 51 | , ' -t, --template Use the template ' 52 | , ' -d, --directory Use the template directory ' 53 | , ' -V, --version Output the current version' 54 | , ' -h, --help Display help information' 55 | , '' 56 | ].join('\n'); 57 | 58 | /** 59 | * Initialize a new `Template` with the given `name`. 60 | * 61 | * @param {String} name 62 | * @api private 63 | */ 64 | 65 | function Template(name) { 66 | this.name = name; 67 | this.path = templates + '/' + name; 68 | this.contentPath = this.path + '/content'; 69 | this.mod = require(this.path); 70 | this.values = { 71 | year: new Date().getFullYear() 72 | }; 73 | this.directories = {}; 74 | } 75 | 76 | /** 77 | * Initialize template at `dest`. 78 | * 79 | * @param {String} dest 80 | * @api private 81 | */ 82 | 83 | Template.prototype.init = function(dest){ 84 | var self = this 85 | , vars = this.mod.variables 86 | , keys = Object.keys(vars); 87 | 88 | this.dest = dest; 89 | console.log(); 90 | 91 | function next() { 92 | var desc 93 | , key = keys.shift(); 94 | 95 | function done(value) { 96 | self.values[key] = String(value).trim(); 97 | next(); 98 | } 99 | 100 | if (key) { 101 | desc = vars[key]; 102 | if ('function' == typeof desc) { 103 | desc(self.values, done); 104 | } else { 105 | ask(desc, done); 106 | } 107 | } else { 108 | process.stdin.destroy(); 109 | self.create(); 110 | } 111 | } 112 | 113 | next(); 114 | }; 115 | 116 | /** 117 | * Return the files for this template. 118 | * 119 | * @return {Array} 120 | * @api private 121 | */ 122 | 123 | Template.prototype.__defineGetter__('files', function(){ 124 | var self = this 125 | , files = []; 126 | 127 | (function next(dir) { 128 | fs.readdirSync(dir).forEach(function(file){ 129 | files.push(file = dir + '/' + file); 130 | var stat = fs.statSync(file); 131 | if (stat.isDirectory()) { 132 | self.directories[file] = true; 133 | next(file); 134 | } 135 | }); 136 | })(this.contentPath); 137 | 138 | return files; 139 | }); 140 | 141 | /** 142 | * Create the template files. 143 | * 144 | * @api private 145 | */ 146 | 147 | Template.prototype.create = function(){ 148 | var self = this; 149 | console.log(); 150 | this.files.forEach(function(file){ 151 | var path = self.parse(file) 152 | , out = join(dest, path.replace(self.contentPath, '')); 153 | 154 | // directory 155 | if (self.directories[file]) { 156 | try { 157 | fs.mkdirSync(out, 0775); 158 | console.log(' \033[90mcreate :\033[0m \033[36m%s\033[0m', out); 159 | } catch (err) { 160 | // ignore 161 | } 162 | // file 163 | } else { 164 | var str = self.parse(fs.readFileSync(file, 'utf8')); 165 | fs.writeFileSync(out, str); 166 | console.log(' \033[90mcreate :\033[0m \033[36m%s\033[0m', out); 167 | } 168 | }); 169 | console.log(); 170 | }; 171 | 172 | /** 173 | * Parse `str`. 174 | * 175 | * @return {String} 176 | * @api private 177 | */ 178 | 179 | Template.prototype.parse = function(str){ 180 | var self = this; 181 | return str 182 | .replace(/\{\{([^}]+)\}\}/g, function(_, key){ 183 | return self.values[key]; 184 | }); 185 | }; 186 | 187 | /** 188 | * Require argument for `flag`. 189 | */ 190 | 191 | function requireArgument(flag) { 192 | if (args.length) { 193 | return args.shift(); 194 | } else { 195 | console.error(flag + ' requires an argument'); 196 | process.exit(1); 197 | } 198 | } 199 | 200 | /** 201 | * Ask for user input. 202 | */ 203 | 204 | function ask(desc, callback) { 205 | process.stdout.write(' \033[90m' + desc + '\033[0m'); 206 | process.stdin.setEncoding('utf8'); 207 | process.stdin.once('data', callback).resume(); 208 | } 209 | 210 | // parse arguments 211 | 212 | var arg; 213 | while (args.length) { 214 | switch (arg = args.shift()) { 215 | case '-h': 216 | case '--help': 217 | console.log(usage); 218 | process.exit(); 219 | break; 220 | case '-t': 221 | case '--template': 222 | template = requireArgument(arg); 223 | break; 224 | case '-d': 225 | case '--directory': 226 | templates = fs.realpathSync(requireArgument(arg)); 227 | break; 228 | default: 229 | dest = arg; 230 | } 231 | } 232 | 233 | // create template 234 | 235 | var tmpl = new Template(template); 236 | 237 | // dest 238 | 239 | try { 240 | fs.mkdirSync(dest, 0775); 241 | } catch (err) { 242 | // ignore 243 | } 244 | 245 | tmpl.init(dest); 246 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngen", 3 | "description": "Package generator (structure, changelogs, tests, package.json, etc)", 4 | "version": "1.1.1", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/visionmedia/ngen.git" 8 | }, 9 | "author": "TJ Holowaychuk ", 10 | "contributors": [ 11 | "Irakli Gozalishvili (http://jeditoolkit.com)" 12 | ], 13 | "bin": { "ngen": "./bin/ngen" } 14 | } 15 | -------------------------------------------------------------------------------- /templates/default/content/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.sock 4 | -------------------------------------------------------------------------------- /templates/default/content/.npmignore: -------------------------------------------------------------------------------- 1 | support 2 | test 3 | examples 4 | *.sock 5 | -------------------------------------------------------------------------------- /templates/default/content/History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.0.1 / 2010-01-03 3 | ================== 4 | 5 | * Initial release 6 | -------------------------------------------------------------------------------- /templates/default/content/Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @./node_modules/.bin/mocha \ 4 | --require should \ 5 | --reporter spec 6 | 7 | .PHONY: test -------------------------------------------------------------------------------- /templates/default/content/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # {{project}} 3 | 4 | {{description}} 5 | 6 | ## License 7 | 8 | (The MIT License) 9 | 10 | Copyright (c) {{year}} {{name}} <{{email}}> 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | 'Software'), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 27 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 28 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 29 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /templates/default/content/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./lib/{{project}}'); -------------------------------------------------------------------------------- /templates/default/content/lib/{{project}}.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj/ngen/4fb4ec3fd43ebc83796f972fa52d6ba14c08fbf3/templates/default/content/lib/{{project}}.js -------------------------------------------------------------------------------- /templates/default/content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{project}}", 3 | "version": "0.0.1", 4 | "description": "{{description}}", 5 | "keywords": [], 6 | "author": "{{name}} <{{email}}>", 7 | "repository": { "type": "git", "url": "git://github.com/{{username}}/{{project}}.git" }, 8 | "dependencies": {}, 9 | "devDependencies": { 10 | "mocha": "*", 11 | "should": "*" 12 | }, 13 | "main": "index" 14 | } 15 | -------------------------------------------------------------------------------- /templates/default/content/test/{{project}}.test.js: -------------------------------------------------------------------------------- 1 | 2 | var {{project}} = require('{{project}}'); 3 | 4 | describe('something', function(){ 5 | it('should work', function(){ 6 | 7 | }) 8 | }) -------------------------------------------------------------------------------- /templates/default/index.js: -------------------------------------------------------------------------------- 1 | 2 | exports.variables = { 3 | project: 'Project name: ' 4 | , username: 'Project username: ' 5 | , name: 'Enter your name: ' 6 | , email: 'Enter your email: ' 7 | , description: 'Project description: ' 8 | }; 9 | -------------------------------------------------------------------------------- /templates/git/content/.npmignore: -------------------------------------------------------------------------------- 1 | support 2 | test 3 | examples 4 | -------------------------------------------------------------------------------- /templates/git/content/History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.0.1 / 2010-01-03 3 | ================== 4 | 5 | * Initial release 6 | -------------------------------------------------------------------------------- /templates/git/content/Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @echo "populate me" 4 | 5 | .PHONY: test -------------------------------------------------------------------------------- /templates/git/content/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # {{project}} 3 | 4 | {{description}} 5 | 6 | ## License 7 | 8 | (The MIT License) 9 | 10 | Copyright (c) {{year}} {{name}} <{{email}}> 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | 'Software'), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 27 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 28 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 29 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /templates/git/content/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./lib/{{project}}'); -------------------------------------------------------------------------------- /templates/git/content/lib/{{project}}.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * {{project}} 4 | * Copyright(c) 2011 {{name}} <{{email}}> 5 | * MIT Licensed 6 | */ 7 | 8 | /** 9 | * Library version. 10 | */ 11 | 12 | exports.version = '0.0.1'; -------------------------------------------------------------------------------- /templates/git/content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{project}}" 3 | , "version": "0.0.1" 4 | , "description": "{{description}}" 5 | , "keywords": [] 6 | , "author": "{{name}} <{{email}}>" 7 | , "dependencies": {} 8 | , "main": "index" 9 | , "engines": { "node": "0.4.x" } 10 | , "repository": { "type": "git", "url": "git://github.com/{{username}}/{{project}}.git" } 11 | } 12 | -------------------------------------------------------------------------------- /templates/git/content/test/{{project}}.test.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var mini = require('{{project}}') 7 | , should = require('should'); 8 | 9 | module.exports = { 10 | 'test .version': function(){ 11 | {{project}}.version.should.match(/^\d+\.\d+\.\d+$/); 12 | } 13 | }; -------------------------------------------------------------------------------- /templates/git/index.js: -------------------------------------------------------------------------------- 1 | var spawn = require('child_process').spawn; 2 | 3 | exports.variables = { 4 | project: 'Project name: ', 5 | description: 'Project description: ', 6 | username: 'Project username: ', 7 | name: function(values, callback) { 8 | spawn('git', [ 9 | '--bare', 10 | 'config', 11 | '--global', 12 | 'user.name' 13 | ]).stdout.once('data', callback); 14 | }, 15 | email: function(values, callback) { 16 | spawn('git', [ 17 | '--bare', 18 | 'config', 19 | '--global', 20 | 'user.email' 21 | ]).stdout.once('data', callback); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /templates/modular/content/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.sock 4 | -------------------------------------------------------------------------------- /templates/modular/content/.npmignore: -------------------------------------------------------------------------------- 1 | support 2 | test 3 | examples 4 | *.sock 5 | -------------------------------------------------------------------------------- /templates/modular/content/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "host": "localhost", 4 | "port": 5984, 5 | "auth": { 6 | "username": "admin", 7 | "password": "admin" 8 | } 9 | }, 10 | "http": { 11 | "port": 8022 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /templates/modular/content/config/db.js: -------------------------------------------------------------------------------- 1 | // This file will create database connection 2 | // And call "fn" when connection is ready 3 | module.exports = function(config, fn) { 4 | var cradle = require('cradle'), 5 | db = new (cradle.Connection)({ 6 | host: config.db.host || 'localhost', 7 | port: config.db.port || 5984, 8 | auth: config.db.auth 9 | }).database(config.db.name); 10 | 11 | fn(db); 12 | }; 13 | -------------------------------------------------------------------------------- /templates/modular/content/lib/helpers.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | path = require('path'), 3 | Script = process.binding('evals').Script; 4 | 5 | /** 6 | * Check, whether dir is directory or not 7 | */ 8 | var isDirectory = exports.isDirectory = function(dir) { 9 | var stat; 10 | return fs.existsSync(dir) && (stat = fs.statSync(dir)) && 11 | stat.isDirectory(); 12 | } 13 | 14 | /** 15 | * is obj function? 16 | */ 17 | exports.isFunction = function(obj) { 18 | return typeof obj === 'function'; 19 | } 20 | 21 | /** 22 | * Copy own properties of b to a 23 | */ 24 | exports.extend = function(a, b) { 25 | if (!b) return a; 26 | 27 | for (var i in b) { 28 | if (b.hasOwnProperty(i)) a[i] = b[i]; 29 | } 30 | 31 | return a; 32 | }; 33 | 34 | /** 35 | * This function will be used to process files array 36 | */ 37 | exports.reduce = function(dir) { 38 | dir = path.normalize(dir); 39 | 40 | return function(accum, elem) { 41 | var filepath = elem.substr(dir.length); 42 | 43 | if (!filepath) return accum; 44 | 45 | // Process only files 46 | if (!isDirectory(elem)) { 47 | accum.push({ 48 | extension: path.extname(filepath), 49 | name: filepath.replace(/\.[^\.]+$/, ''), 50 | filepath: elem 51 | }); 52 | } 53 | 54 | return accum; 55 | } 56 | }; 57 | 58 | /** 59 | * Compile script in a new context 60 | * Very common to nodejs module system 61 | */ 62 | exports.require = function(file, context) { 63 | var content = fs.readFileSync(file.filepath); 64 | 65 | if (file.extension !== '.js') { 66 | return {exports: content}; 67 | } 68 | try { 69 | var fn = Script.runInNewContext('(function(require, __dirname, ' + 70 | '__filename, module, exports) {\n' + 71 | content + 72 | '\n;})', context, file.filepath), 73 | exports = {}, 74 | module = {exports: exports}, 75 | dirname = path.dirname(file.filepath); 76 | 77 | fn(require, dirname, file.filepath, module, exports); 78 | } catch (e) { 79 | console.log('Failed to load: ' + file.filepath, e); 80 | return {}; 81 | } 82 | return module; 83 | }; 84 | 85 | /** 86 | * Helps storing modules in javascript object 87 | * a.b.c = x => {a:{b:{c: x}}} 88 | */ 89 | exports.store = function(storage, key, val) { 90 | var previous; 91 | key.split(/\.|\//g).forEach(function(subkey) { 92 | subkey = subkey.trim(); 93 | 94 | previous = { 95 | storage: storage, 96 | subkey: subkey 97 | }; 98 | storage = storage[subkey] || (storage[subkey] = {}); 99 | }); 100 | 101 | if (!previous) return; 102 | previous.storage[previous.subkey] = val; 103 | 104 | return previous.storage; 105 | }; 106 | 107 | -------------------------------------------------------------------------------- /templates/modular/content/lib/loader.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | path = require('path'), 3 | util = require('util'), 4 | watch = require('watch'), 5 | helpers = require('./helpers'); 6 | 7 | 8 | /** 9 | * Loader - loads all js files from a directory root, 10 | * compiles them and puts them into objects variable 11 | */ 12 | var loader = module.exports = function(dir, context, callback) { 13 | if (!helpers.isDirectory(dir)) return; 14 | 15 | // Add trailing slash 16 | dir = dir.replace(/\/+$/, '') + '/'; 17 | 18 | // Context must be defined 19 | context = context || {}; 20 | 21 | var objects = {}, 22 | weighted = [], 23 | args = Array.prototype.slice.call(arguments, 1); 24 | 25 | addInvokeMethods(context, weighted); 26 | 27 | watch.walk(dir, function(err, files_obj) { 28 | if (err) { 29 | console.log(err); 30 | return; 31 | } 32 | 33 | var files = []; 34 | 35 | for (var file in files_obj) { 36 | if (!files_obj.hasOwnProperty(file)) continue; 37 | 38 | files.push(file); 39 | } 40 | 41 | // Replace kind of wildcard '?' with objects itself, 42 | // So objects can be passed to context on demand 43 | for (var i in context) if (context[i] === '?') context[i] = objects; 44 | 45 | files.reduce(helpers.reduce(dir), []).forEach(function(file) { 46 | var result = helpers.require(file, context); 47 | 48 | // If module is disabled - do not load it 49 | if (!result.exports || result.exports.enabled === false) return; 50 | 51 | // Add to modules object 52 | var object = result.exports; 53 | 54 | // module.folder will points to object in "modules" global variable 55 | // which holds this module 56 | // 57 | // so if we have module with path: /my_app/some_module/abc.js 58 | // module.folder will be equal to modules.my_app.some_module 59 | // inside this module's context 60 | result.folder = helpers.store(objects, file.name, object); 61 | 62 | // Add to weighted collection 63 | weighted.push({ 64 | weight: parseInt(object.weight) || 0, 65 | name: file.name, 66 | value: object 67 | }); 68 | }); 69 | 70 | // Sort objects in collection by weight 71 | weighted.sort(function(a, b) { 72 | return a.weight > b.weight; 73 | }); 74 | 75 | // All objects are in place 76 | // Invoke init 77 | process.nextTick(function() { 78 | context.invoke('init'); 79 | }); 80 | 81 | callback && callback(null, context.invoke.emitter); 82 | }); 83 | } 84 | 85 | /** 86 | * Adds invoke methods to execution context 87 | * 88 | * Provides cool syntax 89 | * invoke('init', arg1, arg2, arg3).array 90 | */ 91 | function addInvokeMethods(context, weighted) { 92 | var len; 93 | 94 | context.invoke = function(callbackName) { 95 | var args = Array.prototype.slice.call(arguments, 1); 96 | 97 | // Calculate length only once 98 | len = len || weighted.length; 99 | 100 | var array = [], object = {}; 101 | 102 | for (var i = 0; i < len; i++) { 103 | var elem = weighted[i], 104 | callback = elem.value[callbackName]; 105 | 106 | if (!elem.value.hasOwnProperty(callbackName) || 107 | !helpers.isFunction(callback)) continue; 108 | 109 | try { 110 | var result = callback.apply(elem, args); 111 | array.push(result); 112 | helpers.store(object, elem.name, result); 113 | } catch (e) { 114 | util.puts(e); 115 | } 116 | } 117 | 118 | // Invoke EventEmitter (for debug purposes) 119 | context.invoke.emitter.emit.apply( 120 | context.invoke.emitter, 121 | arguments 122 | ); 123 | 124 | return { 125 | object: object, 126 | array: array 127 | }; 128 | }; 129 | 130 | context.invoke.emitter = new process.EventEmitter; 131 | } 132 | -------------------------------------------------------------------------------- /templates/modular/content/modules/express/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Express.js: HTTP Server 3 | * 4 | * Adds .middleware(express) and .routes(app) callbacks 5 | */ 6 | 7 | /** 8 | * .init() callback 9 | */ 10 | exports.init = function() { 11 | var express = require('express'), 12 | middleware = invoke('middleware', express).array; 13 | 14 | middleware.unshift(express.errorHandler()); 15 | 16 | var server = express.createServer.apply(express, middleware); 17 | 18 | // Decode body and cookies 19 | server.use(express.bodyParser()); 20 | server.use(express.cookieParser()); 21 | 22 | // Configure views 23 | server.set('views', rootdir + '/views'); 24 | server.set('view engine', 'ejs'); 25 | 26 | // Apply routes 27 | invoke('routes', server); 28 | 29 | server.listen(config.http.port, function() { 30 | console.log('Server has started listening on port ' + config.http.port); 31 | invoke('http-listening'); 32 | }); 33 | } 34 | 35 | /** 36 | * Module's weight 37 | */ 38 | exports.weight = -1E6; 39 | -------------------------------------------------------------------------------- /templates/modular/content/modules/express/static.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Express.js : Static provider 3 | * 4 | * Servers static content 5 | */ 6 | 7 | /** 8 | * Export static content middleware 9 | */ 10 | exports.middleware = function(express) { 11 | return express.static(rootdir + '/static/'); 12 | } 13 | 14 | exports.weight = 6; 15 | -------------------------------------------------------------------------------- /templates/modular/content/modules/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Adds middleware, that adds methods: 3 | * # json 4 | */ 5 | 6 | var Buffer = require('buffer').Buffer; 7 | 8 | /** 9 | * Exports middleware 10 | */ 11 | exports.middleware = function adds_json_method(express) { 12 | return function(req, res, next) { 13 | var jsonp = req.query && req.query.callback; 14 | 15 | res.json = function(data, code) { 16 | data = jsonp ? jsonp + '(' + JSON.stringify(data) + ')' : 17 | JSON.stringify(data); 18 | 19 | var headers = { 20 | 'Content-Type': jsonp ? 'text/javascript' : 'application/json', 21 | 'Content-Length': Buffer.byteLength(data) 22 | }; 23 | 24 | if (res.header('Set-Cookie')) { 25 | headers['Set-Cookie'] = res.header('Set-Cookie'); 26 | } 27 | 28 | res.writeHead(code || 200, headers); 29 | res.end(data); 30 | }; 31 | 32 | next(); 33 | } 34 | } 35 | 36 | /** 37 | * Try to be first 38 | */ 39 | exports.weight = -1E9; 40 | -------------------------------------------------------------------------------- /templates/modular/content/modules/your_site/pages.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This should be your site's pages module 3 | */ 4 | 5 | exports.routes = function(app) { 6 | function index_page(req, res) { 7 | res.render('pages/index', { 8 | locals: { 9 | title: 'My node.modular site', 10 | req: req 11 | } 12 | }); 13 | } 14 | 15 | app.get('/', index_page); 16 | app.get('/index', index_page); 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /templates/modular/content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{project}}", 3 | "version": "0.0.1", 4 | "description": "{{description}}", 5 | "author": "{{name}} <{{email}}>", 6 | "keywords": [], 7 | "private": true, 8 | "dependencies": { 9 | "optimist": ">= 0.0.3", 10 | "cradle": ">= 0.3.1", 11 | "ejs": ">= 0.2.1", 12 | "express": ">= 1.0.1", 13 | "connect":" >= 1.4.1", 14 | "request": ">= 0.10.0", 15 | "step": ">= 0.0.3", 16 | "watch": ">= 0.3.0" 17 | }, 18 | "engines": { "node": ">= 0.4.x" }, 19 | "scripts": { 20 | "start": "node run.js" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/modular/content/run.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | watch = require('watch'), 3 | connect = require('connect'), 4 | argv = require('optimist').argv; 5 | 6 | var config = JSON.parse(fs.readFileSync(argv.config || './config.json')), 7 | db = require('./config/db'), 8 | loader = require('./lib/loader'); 9 | 10 | function init(db) { 11 | loader(__dirname + '/modules', { 12 | rootdir: __dirname, 13 | console: console, 14 | process: process, 15 | config: config, 16 | setTimeout: setTimeout, 17 | setInterval: setInterval, 18 | clearTimeout: clearTimeout, 19 | clearIntevral: clearInterval, 20 | db: db, 21 | modules: '?' 22 | }); 23 | } 24 | 25 | db(config, init); 26 | 27 | -------------------------------------------------------------------------------- /templates/modular/content/static/css/style.css: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------- */ 2 | /* Reset */ 3 | 4 | html, body, div, span, applet, object, iframe, 5 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 6 | a, abbr, acronym, address, big, cite, code, 7 | del, dfn, em, font, img, ins, kbd, q, s, samp, 8 | small, strike, strong, sub, sup, tt, var, 9 | b, u, i, center, 10 | dl, dt, dd, ol, ul, li, 11 | fieldset, form, label, legend, 12 | table, caption, tbody, tfoot, thead, tr, th, td { 13 | margin: 0; 14 | padding: 0; 15 | border: 0; 16 | outline: 0; 17 | font-size: 100%; 18 | vertical-align: baseline; 19 | background: transparent; 20 | } 21 | ol, ul { 22 | list-style: none; 23 | } 24 | blockquote, q { 25 | quotes: none; 26 | } 27 | 28 | 29 | /* base */ 30 | 31 | body, input, select, option, textarea { 32 | font-size: 13px; 33 | font-family: "Lucida Grande", "Lucida Sans Unicode", sans-serif; 34 | line-height: 20px; 35 | } 36 | a:link, a:visited, a:active { 37 | color: #1c9fec; 38 | text-decoration: none; 39 | } 40 | a:hover, a:focus { 41 | text-decoration: underline; 42 | } 43 | .wrapper { 44 | width: 960px; 45 | margin: 0 auto; 46 | position: relative; 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /templates/modular/content/static/js/main.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('body').hide().fadeIn(); 3 | }); 4 | 5 | -------------------------------------------------------------------------------- /templates/modular/content/views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= title %> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | <%- body %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/modular/content/views/pages/index.ejs: -------------------------------------------------------------------------------- 1 | Hello from node.modular! 2 | 3 | -------------------------------------------------------------------------------- /templates/modular/index.js: -------------------------------------------------------------------------------- 1 | 2 | exports.variables = { 3 | project: 'Project name: ' 4 | , name: 'Enter your name: ' 5 | , email: 'Enter your email: ' 6 | , description: 'Project description: ' 7 | }; --------------------------------------------------------------------------------