├── .editorconfig ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── bin ├── clever ├── clever-build ├── clever-downgrade ├── clever-g ├── clever-generate ├── clever-help ├── clever-init ├── clever-install ├── clever-list ├── clever-new ├── clever-remove ├── clever-repl ├── clever-routes ├── clever-s ├── clever-scaffold ├── clever-search ├── clever-serve ├── clever-server ├── clever-setup ├── clever-test ├── clever-tests └── clever-upgrade ├── index.js ├── lib ├── boot.js ├── colors.js ├── command.js ├── generate │ ├── fs.js │ ├── index.js │ ├── paths.js │ └── render.js ├── generator.js ├── index.js ├── install.js ├── packages.js ├── program.js ├── project.js ├── repl.js ├── repl │ └── commands │ │ ├── commands.js │ │ ├── exit.js │ │ ├── history.js │ │ ├── models.js │ │ ├── modules.js │ │ └── services.js ├── repos.js ├── routes.js ├── search.js ├── util │ ├── bower.js │ ├── dependencies.js │ ├── grunt.js │ ├── index.js │ ├── locations.js │ └── module.js └── utils.js ├── package.json ├── templates ├── backend │ ├── config │ │ └── default.json │ ├── controllers │ │ └── templateController.js │ ├── models │ │ └── templateModel.js │ ├── module.js │ ├── package.json │ ├── routes.js │ ├── schema │ │ └── seedData.json │ ├── services │ │ └── templateService.js │ ├── tasks │ │ └── templateTask.js │ └── tests │ │ ├── integration │ │ └── templateTest.js │ │ └── unit │ │ └── templateTest.js └── frontend │ ├── bower.json │ ├── controllers │ └── TemplateController.js │ ├── directives │ └── TemplateDirective.js │ ├── factories │ └── TemplateFactory.js │ ├── main.js │ ├── models │ └── TemplateModel.js │ ├── module.js │ ├── services │ └── TemplateService.js │ ├── styles │ └── Template.css │ └── views │ └── Template-view.html └── tests ├── assets └── .gitkeep ├── downgrade.test.js ├── generate ├── backend │ ├── controllers.test.js │ ├── models.test.js │ ├── services.test.js │ ├── tasks.test.js │ └── tests.test.js └── frontend │ ├── controllers.js │ ├── directives.js │ ├── factories.js │ ├── index.test.js │ ├── services.js │ └── views.js ├── help ├── build.js ├── downgrade.js ├── generate.js ├── help.js ├── index.test.js ├── init.js ├── install.js ├── list.js ├── new.js ├── remove.js ├── scaffold.js ├── search.js ├── server.js ├── setup.js ├── test.js └── upgrade.js ├── init.test.js ├── install ├── backend.test.js ├── frontend.test.js └── install.test.js ├── list.test.js ├── new ├── backend.test.js └── frontend.test.js ├── remove.test.js ├── repl.test.js ├── scaffold ├── backend.test.js └── frontend.test.js ├── search.test.js ├── setup.test.js └── upgrade.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .nbrun 3 | .DS_Store 4 | npm-debug.log 5 | .netbeans.xml 6 | node_modules 7 | .idea 8 | config/local.json 9 | test-results.xml 10 | !.gitignore 11 | .*.swp 12 | docs 13 | nohup.out 14 | cache.json 15 | tests/assets/* 16 | !.gitkeep 17 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node" : true, 3 | "maxerr" : 100, 4 | "passfail" : false, 5 | "smarttabs" : false, 6 | "globals": { 7 | "console" : true, 8 | "process" : true, 9 | "spyOn" : false, 10 | "it" : false, 11 | "describe" : false, 12 | "beforeEach": false, 13 | "afterEach" : false, 14 | "before" : false, 15 | "after" : false, 16 | "waits" : false, 17 | "waitsFor" : false, 18 | "runs" : false, 19 | "lib" : true, 20 | "program" : true 21 | }, 22 | "predef": [ 23 | "-Promise" 24 | ], 25 | "debug" : false, 26 | "devel" : false, 27 | "esnext" : true, 28 | "strict" : false, 29 | "globalstrict": true, 30 | "asi" : false, 31 | "laxbreak" : false, 32 | "laxcomma" : true, 33 | "bitwise" : true, 34 | "boss" : false, 35 | "curly" : true, 36 | "eqeqeq" : true, 37 | "eqnull" : false, 38 | "evil" : false, 39 | "expr" : true, 40 | "forin" : false, 41 | "immed" : true, 42 | "latedef" : true, 43 | "loopfunc" : false, 44 | "maxdepth" : 5, 45 | "maxparams" : false, 46 | "multistr" : false, 47 | "noarg" : true, 48 | "regexp" : true, 49 | "shadow" : false, 50 | "supernew" : false, 51 | "undef" : true, 52 | "unused" : true, 53 | "validthis" : true, 54 | "quotmark" : "single", 55 | "camelcase" : true, 56 | "indent" : 2, 57 | "newcap" : true, 58 | "noempty" : false, 59 | "nonew" : true, 60 | "nomen" : false, 61 | "onevar" : false, 62 | "plusplus" : false, 63 | "sub" : false, 64 | "trailing" : true, 65 | "white" : false 66 | } 67 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | examples 3 | tests 4 | .watchr.js 5 | changelog.md 6 | Makefile 7 | coverage* 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '0.10' 5 | - '0.11' 6 | - '0.12' 7 | - '5.0' 8 | - '6.0' 9 | 10 | before_install: 11 | - 'npm install -g grunt-cli' 12 | - 'npm install -g bower' 13 | 14 | script: 15 | - "travis_wait make tests" 16 | 17 | cache: 18 | directories: 19 | - node_modules 20 | 21 | notifications: 22 | webhooks: 23 | urls: 24 | - https://webhooks.gitter.im/e/515d4eb7d44adbed410b 25 | on_success: change # options: [always|never|change] default: always 26 | on_failure: always # options: [always|never|change] default: always 27 | on_start: false # default: false 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # A Word on Contributing 2 | 3 | Contributing to a project is not only adding slabs of code, fixing bugs, or creating optimizations, but it is also contributing to programmers, CTOs, fathers, mothers, sons and daughters. This project isn't about a team of developers or a "we the programmers" yacht club. It's really about "us" and helpings others climb that same mountain. Whether the top of the mountain is making more money, improving your developing skills, or spending more time with your family we're all climbing the same rocks. 4 | 5 | > CleverStack aims to not be a framework or a stack, but an ecosystem. ([An ecosystem is a community of living organisms (plants, animals and microbes) in conjunction with the nonliving components of their environment (things like air, water and mineral soil), interacting as a system](http://en.wikipedia.org/wiki/Ecosystem).) 6 | 7 | > The vision for CleverStack is not to be the best performance framework (although, there is certainly concern for that), to include and support for all of the gadgets and gizmos (this too, is welcomed), or to be the next buzzword like mean (it would be cool to see others talking about it though) it's more about shifting a developer into a different mindset. A mindset in which not only takes the [modularization principles](http://en.wikipedia.org/wiki/Modular_programming) on a vertical scale (e.g. reducing developing time), but a horizontal scale too (e.g. not needing to focus on every single detail, but being able to take a step back and look at your environment across the horizon). 8 | 9 | > I just wanted to thank you for not only looking into contributing towards CleverStack, but for even taking your time to considering it. I'm personally always available to lend out a hand, and I hope you never feel as if you can't reach out to me. I always look forward to discussing ideas, solving problems, and colloborating with others. 10 | 11 | > - Richard Gustin 12 | 13 | ## Submitting bug reports, issues, or enhancement requests. 14 | 15 | There are currently a few resources available to reach out to us: 16 | 17 | 1. [GitHub Issues](https://github.com/CleverStack/cleverstack-cli/issues) 18 | 2. [Stack Overflow](http://stackoverflow.com/questions/tagged/cleverstack) 19 | 3. [Google Groups/Mailing list](https://groups.google.com/forum/#!forum/clever-stack) 20 | 4. [Gitter](https://gitter.im/CleverStack/cleverstack-cli) 21 | 22 | ## Submitting Pull Requests 23 | 24 | 1. Fork the repo 25 | 2. Create a new branch following the [Gitflow](https://www.atlassian.com/git/workflows#!workflow-gitflow) structure. 26 | 3. Refactors and documentation changes do not require a test, but if you're adding a new function please write a tests for that feature. 27 | 4. Please follow the [coding guidelines](https://github.com/CleverStack/cleverstack-cli/blob/master/.jshintrc) 28 | 5. Push your changes and submit a [pull request](https://github.com/CleverStack/cleverstack-cli/compare/) to the master branch. 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2015 CleverStack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REPORTER ?= spec 2 | 3 | # Specify a specific order for test files.. 4 | TESTS = ./tests/help/index.test.js \ 5 | ./tests/list.test.js \ 6 | ./tests/search.test.js \ 7 | ./tests/init.test.js \ 8 | ./tests/install/install.test.js \ 9 | ./tests/install/backend.test.js \ 10 | ./tests/install/frontend.test.js \ 11 | ./tests/remove.test.js \ 12 | ./tests/generate/backend/controllers.test.js \ 13 | ./tests/generate/backend/models.test.js \ 14 | ./tests/generate/backend/services.test.js \ 15 | ./tests/generate/backend/tasks.test.js \ 16 | ./tests/generate/backend/tests.test.js \ 17 | ./tests/generate/frontend/index.test.js \ 18 | ./tests/scaffold/backend.test.js \ 19 | ./tests/scaffold/frontend.test.js \ 20 | ./tests/new/backend.test.js \ 21 | ./tests/new/frontend.test.js \ 22 | ./tests/repl.test.js \ 23 | ./tests/downgrade.test.js \ 24 | ./tests/upgrade.test.js \ 25 | ./tests/setup.test.js 26 | 27 | tests: 28 | @export NO_UPDATE_NOTIFIER=true 29 | @bower cache clean 30 | @npm cache clean 31 | @rm -rf ~/.config/configstore/update-notifier-cleverstack-cli.yml 32 | @./node_modules/mocha/bin/mocha --no-timeouts --globals setImmediate,clearImmediate --check-leaks --colors -t 0 -b --reporter ${REPORTER} ${TESTS} 33 | 34 | test: tests 35 | 36 | .PHONY: test tests 37 | -------------------------------------------------------------------------------- /bin/clever: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , shell = require('shelljs') 5 | , async = require('async') 6 | , configStore = require('configstore') 7 | , rootDir = path.resolve(path.join(__dirname, '..')) 8 | , libDir = path.join(rootDir, 'lib') 9 | , lib = require(path.join(libDir, 'index')) 10 | , updateNotifier = require('update-notifier') 11 | , checkUpdatesEvery = 1000 * 60 * 60 * 24 // once every day 12 | , packageJson = require(path.join(rootDir, 'package.json')) 13 | , notifier; 14 | 15 | async.waterfall( 16 | [ 17 | function checkDependencies(checksDone) { 18 | async.each( 19 | [ 20 | { cmd: 'npm', name: 'NPM', install: '.Please install Node.JS before proceeding.' }, 21 | { cmd: 'bower', name: 'Bower', install: ' please type: npm install -g bower' }, 22 | { cmd: 'grunt', name: 'Grunt-CLI', install: ' please type: npm install -g grunt-cli' } 23 | ], 24 | function checkDependencies(check, checkDone) { 25 | checkDone(!!shell.which(check.cmd) ? null : check.name + ' is required before using CleverStack-CLI' + check.install); 26 | }, 27 | checksDone 28 | ); 29 | }, 30 | 31 | function checkForUpdates(checkDone) { 32 | var updateConfig = new configStore('update-notifier-cleverstack-cli', { 33 | optOut : false, 34 | lastUpdateCheck : Date.now() 35 | }); 36 | 37 | // Only check for updates on a set interval 38 | if (!process.env.HTTP_PROXY && !process.env.HTTPS_PROXY && Date.now() - updateConfig.get('lastUpdateCheck') > checkUpdatesEvery) { 39 | notifier = updateNotifier({ pkg: packageJson, callback: checkDone }); 40 | } else { 41 | checkDone(null); 42 | } 43 | } 44 | ], 45 | function runCommand(err, update) { 46 | var hasErrored = err !== undefined && err !== null; 47 | if (!!hasErrored && !update && err.code !== 'ENOTFOUND') { 48 | lib.utils.error(err); 49 | } else { 50 | if (!!hasErrored && !!update && update.type !== 'latest') { 51 | notifier.update = update; 52 | notifier.notify({ defer: true }); 53 | } 54 | 55 | // avoid the command within process.argv 56 | lib.command(__dirname, process.argv[ 2 ], process.argv.slice(3)); 57 | } 58 | } 59 | ); 60 | -------------------------------------------------------------------------------- /bin/clever-build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , fs = require('fs') 5 | , spawn = require('child_process').spawn 6 | , readline = require('readline') 7 | , async = require('async') 8 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 9 | , program = GLOBAL.program = require('commander'); 10 | 11 | 12 | /** Define CLI Options 13 | ================================*/ 14 | program 15 | .option('-v, --verbose', 'verbose output useful for debugging') 16 | .version(lib.pkg.version); 17 | 18 | 19 | /** Define CLI Help 20 | ================================*/ 21 | program.on('--help', function() { 22 | console.log(' Example:'); 23 | console.log(' clever build'); 24 | console.log(''); 25 | }); 26 | 27 | 28 | /** Parse CLI Arguments 29 | ================================*/ 30 | program.parse(process.argv); 31 | 32 | 33 | /** Find Buildable Projects 34 | ================================*/ 35 | var currentDir = path.resolve(process.cwd()) 36 | , files = fs.readdirSync(currentDir) 37 | , folders = []; 38 | 39 | files 40 | .filter(function findBuildableProjects(d) { 41 | return d === 'package.json' || fs.statSync(path.resolve(path.join(currentDir, d))).isDirectory(); 42 | }) 43 | .forEach(function buildCompatibleProjects(d) { 44 | var isProject = d.indexOf('package.json') === -1 45 | , pkg = path.resolve(path.join(currentDir, d, isProject ? 'package.json' : '')); 46 | 47 | if (fs.existsSync(pkg)) { 48 | var readPkg = require(pkg) 49 | , hasPkgName = readPkg.hasOwnProperty('name'); 50 | 51 | if (hasPkgName && readPkg.name.indexOf('package.json') === -1 && readPkg.name.indexOf('node-seed') === -1) { 52 | folders.push({ 53 | path: path.resolve(path.join(pkg, '..')) 54 | }); 55 | } 56 | } 57 | }); 58 | 59 | if (folders.length < 1) { 60 | lib.utils.fail('CleverStack couldn\'t find the frontend seed directory within ' + process.cwd()); 61 | } 62 | 63 | /** Start Building 64 | ================================*/ 65 | async.each( 66 | folders, 67 | function run(folder, next) { 68 | lib 69 | .util 70 | .grunt 71 | .runTask( 72 | folder.path, 'build', 73 | '--base', folder.path, 74 | '--gruntfile', path.resolve(path.join(folder.path, 'Gruntfile.js')) 75 | ) 76 | .then(function() { 77 | lib.utils.success('Build for ' + folder.path + ' was successful'); 78 | next(null); 79 | }) 80 | .catch(next); 81 | }, 82 | function handleErr(err) { 83 | if (!!err) { 84 | lib.utils.fail(err); 85 | } 86 | 87 | process.exit(0); 88 | } 89 | ); 90 | -------------------------------------------------------------------------------- /bin/clever-downgrade: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , Promise = require('bluebird') 5 | , async = require('async') 6 | , _ = require('lodash') 7 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 8 | , program = GLOBAL.program = require('commander'); 9 | 10 | /** Define CLI Usage 11 | ================================*/ 12 | program 13 | .option('-v, --verbose', 'verbose output useful for debugging') 14 | .version(lib.pkg.version); 15 | 16 | /** Define CLI Help 17 | ================================*/ 18 | program.on('--help', function() { 19 | console.log(' Examples:'); 20 | console.log(''); 21 | console.log(' clever downgrade clever-orm'); 22 | console.log(' clever downgrade clever-orm@0.0.1 clever-datatables@0.0.1'); 23 | console.log(' clever downgrade backend'); 24 | console.log(' clever downgrade frontend'); 25 | console.log(''); 26 | }); 27 | 28 | /** Parse CLI Arguments 29 | ================================*/ 30 | program.parse(process.argv); 31 | var args = []; 32 | process.argv.slice(2).forEach(function(arg) { 33 | if (arg !== '-v' && arg !== '--verbose') { 34 | args.push(arg); 35 | } 36 | }); 37 | 38 | /** Start Downgrading 39 | ================================*/ 40 | // We don't need version numbers when we're checking for backend or frontend... 41 | var _args = args.map(function(a) { 42 | return a.split('@')[0]; 43 | }); 44 | 45 | // Figure out what we're trying to upgrade... 46 | var findBackend = _args.indexOf('backend'); 47 | if (findBackend > -1) { 48 | var backendVersion = args[findBackend].split('@')[1]; 49 | args[findBackend] = 'node-seed' + (typeof backendVersion !== 'undefined' ? '@' + backendVersion : ''); 50 | } 51 | 52 | var findFrontend = _args.indexOf('frontend'); 53 | if (findFrontend > -1) { 54 | var frontendVersion = args[findFrontend].split('@')[1]; 55 | args[findFrontend] = 'angular-seed' + (typeof frontendVersion !== 'undefined' ? '@' + frontendVersion : ''); 56 | } 57 | 58 | var modules = []; 59 | if (args.length < 1) { 60 | modules.push('node-seed'); 61 | modules.push('angular-seed'); 62 | } else { 63 | modules = args; 64 | } 65 | 66 | lib.util.locations.get() 67 | .then (function (locations) { 68 | // Filter for module's existence 69 | async.map(modules, function (module, filter) { 70 | var moduleSplit = module.split('@') 71 | , moduleName = moduleSplit[0] 72 | , moduleVersion = '*'; 73 | 74 | if (typeof moduleSplit[1] !== 'undefined') { 75 | moduleVersion = moduleSplit[1]; 76 | } 77 | 78 | lib 79 | .util.module 80 | .findConfigAndVersionForModule(locations, moduleName, moduleVersion, 'lt') 81 | .then(function (m) { 82 | filter(null, m); 83 | }, function(err) { 84 | filter(err); 85 | }); 86 | }, 87 | function(err, modulesToInstall) { 88 | var modulesInstall = modulesToInstall.filter(function(m) { 89 | return typeof m === 'object' && m !== null; 90 | }); 91 | 92 | if (!modulesInstall.length) { 93 | return lib.utils.fail('There are no modules to downgrade.'); 94 | } 95 | 96 | var backendModules = modulesInstall.filter(function(m) { 97 | return m.type === 'backend'; 98 | }) 99 | .map(function(m) { 100 | return m.name; 101 | }); 102 | 103 | var frontendModules = modulesInstall.filter(function(m) { 104 | return m.type === 'frontend'; 105 | }) 106 | .map(function(m) { 107 | return m.name; 108 | }); 109 | 110 | var actions = [] 111 | , backendLoc = _.find(locations, function(loc) { return loc.name === 'backend'; }) 112 | , frontendLoc = _.find(locations, function(loc) { return loc.name === 'frontend'; }); 113 | 114 | if (backendModules.length && !!backendLoc) { 115 | actions.push(lib.project.setupModules(backendLoc, backendModules)); 116 | } 117 | 118 | if (frontendModules.length && !!frontendLoc) { 119 | actions.push(lib.project.setupModules(frontendLoc, frontendModules)); 120 | } 121 | 122 | Promise 123 | .all(actions) 124 | .then(function() { 125 | lib.utils.success('Downgrade process has been completed.'); 126 | process.exit(0); 127 | }) 128 | .catch(function(err) { 129 | lib.utils.fail(err); 130 | }); 131 | }); 132 | }) 133 | .catch(function(err) { 134 | lib.utils.fail(err); 135 | }); 136 | -------------------------------------------------------------------------------- /bin/clever-g: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | 5 | require(path.join(__dirname, 'clever-generate')); 6 | -------------------------------------------------------------------------------- /bin/clever-generate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , generate = lib.generator.generate; 7 | 8 | /** Define CLI Options 9 | ================================*/ 10 | program 11 | .option('-v, --verbose', 'verbose output useful for debugging') 12 | .version(lib.pkg.version); 13 | 14 | /** Main Generators 15 | ================================*/ 16 | ['service', 'controller', 'model', 'task', 'view', 'factory', 'service', 'directive'].forEach(function(tmpl) { 17 | var tmpl2 = (tmpl === 'factory' ? 'factories' : tmpl + 's'); 18 | 19 | /** Singular 20 | ================================*/ 21 | program 22 | .command(tmpl + ' ') 23 | .usage(tmpl + ' ') 24 | .option('-v, --verbose', 'verbose output useful for debugging') 25 | .description('Generates a ' + tmpl + ' as within ' + path.sep + tmpl2) 26 | .action(function(name) { 27 | generate(tmpl2, name, function() { 28 | lib.utils.success(tmpl + ' generated within ' + path.sep + tmpl); 29 | }); 30 | }); 31 | 32 | /** Plural 33 | ================================*/ 34 | program 35 | .command(tmpl2 + ' ') 36 | .usage(tmpl2 + ' ') 37 | .option('-v, --verbose', 'verbose output useful for debugging') 38 | .description('Generates ' + tmpl2 + ' specified with within ' + path.sep + tmpl2) 39 | .action(function(name, program) { 40 | generate(tmpl2, program.parent.rawArgs.splice(3), function() { 41 | lib.utils.success(tmpl + ' generated within ' + path.sep + tmpl); 42 | }); 43 | }); 44 | }); 45 | 46 | /** Singular Tests Generator 47 | ================================*/ 48 | program 49 | .command('test ') 50 | .usage('test [options] ') 51 | .option('-i, --integration', 'Generate integration tests', true) 52 | .option('-u, --unit', 'Generate unit tests.', true) 53 | // .option('-e, --e2e', 'Generate e2e tests.', true) 54 | // .option('-m, --mocks', 'Generate mock tests.', true) 55 | .option('-v, --verbose', 'verbose output useful for debugging') 56 | .description('Generates a test t as within ' + path.sep + 'tests') 57 | .action(function (name) { 58 | generate('tests', name, function () { 59 | lib.utils.success('test generated within ' + path.sep + 'tests'); 60 | }); 61 | }); 62 | 63 | /** Plural Tests Generator 64 | ================================*/ 65 | program 66 | .command('tests ') 67 | .usage('tests [options] ') 68 | .option('-i, --integration', 'Generate integration tests', true) 69 | .option('-u, --unit', 'Generate unit tests.', true) 70 | // .option('-e, --e2e', 'Generate e2e tests.', true) 71 | // .option('-m, --mocks', 'Generate mock tests.', true) 72 | .option('-v, --verbose', 'verbose output useful for debugging') 73 | .description('Generates test specified with within ' + path.sep + 'tests') 74 | .action(function() { 75 | generate('tests', program.parent.rawArgs.splice(3), function () { 76 | lib.utils.success('tests generated within ' + path.sep + 'tests'); 77 | }); 78 | }); 79 | 80 | /** Define CLI Help 81 | ================================*/ 82 | program.on('--help', function() { 83 | console.log(' Example:'); 84 | console.log(''); 85 | console.log(' clever generate model users'); 86 | console.log(' clever generate controller users'); 87 | console.log(' clever g controller users'); 88 | console.log(' clever g controllers users auth email'); 89 | console.log(''); 90 | }); 91 | 92 | /** Parse CLI Arguments 93 | ================================*/ 94 | program.parse(process.argv); 95 | if (!program.args.length) { 96 | program.help(); 97 | } 98 | -------------------------------------------------------------------------------- /bin/clever-help: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , program = require(path.join(__dirname, '..', 'lib', 'program')); 5 | 6 | program.help(); 7 | -------------------------------------------------------------------------------- /bin/clever-install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , Promise = require('bluebird'); 7 | 8 | /** Define CLI Usage 9 | ================================*/ 10 | program.version(lib.pkg.version) 11 | .usage('[options] [modules ...]') 12 | .option('-v, --verbose', 'verbose output useful for debugging'); 13 | 14 | /** Define CLI Help 15 | ================================*/ 16 | program.on('--help', function () { 17 | console.log(' Examples:'); 18 | console.log(' clever install clever-background-tasks'); 19 | console.log(' clever install clever-background-tasks@0.0.1'); 20 | console.log(''); 21 | }); 22 | 23 | /** Parse CLI Arguments 24 | ================================*/ 25 | program.parse(process.argv); 26 | if (program.args.length < 1) { 27 | program.help(); 28 | } 29 | 30 | // Tell promise we want long stack traces for easier debugging 31 | Promise.longStackTraces(); 32 | 33 | /** Start Installation 34 | ================================*/ 35 | lib.utils.info('Attempting to install ' + program.args + '...'); 36 | lib 37 | .install 38 | .run(program.args) 39 | .then(function() { 40 | lib.utils.success('Successfully installed.'); 41 | process.exit(0); 42 | }) 43 | .catch(function(err) { 44 | lib.utils.fail(err); 45 | process.exit(1); 46 | }); 47 | -------------------------------------------------------------------------------- /bin/clever-list: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = require('commander'); 6 | 7 | program.version(lib.pkg.version); 8 | 9 | program.on('--help', function() { 10 | console.log(' Example:'); 11 | console.log(' clever list'); 12 | console.log(''); 13 | }); 14 | 15 | program.parse(process.argv); 16 | 17 | process.argv = process.argv.splice(0, 2); 18 | 19 | require(path.join(__dirname, 'clever-search')); 20 | -------------------------------------------------------------------------------- /bin/clever-new: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , fs = require('fs') 7 | , scaffold = lib.generator.newModule 8 | , paths = require(path.join(__dirname, '..', 'lib', 'generate', 'paths')); 9 | 10 | /** Define CLI Usage 11 | ================================*/ 12 | program.version(lib.pkg.version); 13 | program 14 | .usage('[options] ') 15 | .option('-v, --verbose', 'verbose output useful for debugging') 16 | .option('--no-service', 'Disables generating a service.') 17 | .option('--no-controller', 'Disables generating a controller.') 18 | .option('--no-model', 'Disables generating a model.') 19 | .option('--no-task', 'Disables generating a task.') 20 | .option('--no-test', 'Disables generating a test.'); 21 | 22 | /** Define CLI Help 23 | ================================*/ 24 | program.on('--help', function() { 25 | console.log(' Example:'); 26 | console.log(' clever new my_module'); 27 | console.log(' clever new myModule'); 28 | console.log(''); 29 | }); 30 | 31 | /** Parse CLI Arguments 32 | ================================*/ 33 | program.parse(process.argv); 34 | if (program.rawArgs.length < 3) { 35 | program.help(); 36 | } 37 | 38 | /** Start generating 39 | ================================*/ 40 | var filterOut = [] 41 | , filters = [ 'service', 'controller', 'model', 'task', 'test', 'script', 'view' ] 42 | , args = program.rawArgs.splice(2); 43 | 44 | filters.forEach(function(filter) { 45 | if (program[ filter ] === false) { 46 | filterOut.push(filter); 47 | } 48 | }); 49 | 50 | if (filterOut.length === filters.length) { 51 | program.help(); 52 | } 53 | 54 | lib.util 55 | .locations 56 | .get() 57 | .then(function(projects) { 58 | var folders = [] 59 | , name = args[ 0 ]; 60 | 61 | projects.forEach(function(project) { 62 | var folder = paths.getModulePath(project, name); 63 | 64 | if (fs.existsSync(folder)) { 65 | lib.utils.fail('Module already exists within ' + folder); 66 | } 67 | 68 | if (program.verbose) { 69 | lib.utils.info('Module path is ' + folder); 70 | } 71 | 72 | folders.push(folder); 73 | }); 74 | 75 | lib.utils.info('Setting up new module... '); 76 | 77 | scaffold( 78 | projects, 79 | name, 80 | filterOut, 81 | function() { 82 | folders.forEach(function(folder) { 83 | lib.utils.success('Module has been created successfully within ' + folder); 84 | }); 85 | 86 | process.exit(0); 87 | } 88 | ); 89 | }) 90 | .error(lib.utils.error); 91 | -------------------------------------------------------------------------------- /bin/clever-remove: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , Promise = require('bluebird') 7 | , rimraf = require('rimraf') 8 | , fs = require('fs') 9 | , async = require('async'); 10 | 11 | /** Define CLI Usage 12 | ================================*/ 13 | program.version(lib.pkg.version) 14 | .usage('[options] [modules ...]'); 15 | 16 | /** Define CLI Help 17 | ================================*/ 18 | program.on('--help', function() { 19 | console.log(' Examples:'); 20 | console.log(' clever remove clever-background-tasks'); 21 | console.log(' clever remove auth clever-background-tasks'); 22 | console.log(''); 23 | }); 24 | 25 | /** Parse CLI Arguments 26 | ================================*/ 27 | program.parse(process.argv); 28 | if (program.args.length < 1) { 29 | program.help(); 30 | } 31 | 32 | // Tell promise we want long stack traces for easier debugging 33 | Promise.longStackTraces(); 34 | 35 | /** 36 | * Finds all of the modules within lib.util.locations.get() 37 | * 38 | * @param {String[]} modules 39 | * @return {Promise} 40 | * @api private 41 | */ 42 | 43 | function findModules(modules) { 44 | return new Promise(function(resolve, reject) { 45 | lib .util 46 | .locations.get() 47 | .then(function(locations) { 48 | var _modules = []; 49 | 50 | async.each( 51 | modules, 52 | function(module, next) { 53 | async.each( 54 | locations, 55 | function(location, fn) { 56 | var walk = require('findit')(path.join(location.moduleDir, location.modulePath)) 57 | , pkg; 58 | 59 | walk.on('file', function(file) { 60 | if (path.basename(file) === 'bower.json') { 61 | pkg = require(file); 62 | } else if (path.basename(file) === 'package.json' && !fs.existsSync(file.replace('package.json', 'bower.json'))) { 63 | pkg = require(file); 64 | } 65 | 66 | if (typeof pkg !== 'undefined' && pkg.name === module) { 67 | var name = path.join(location.moduleDir, location.modulePath, pkg.rename || pkg.name); 68 | if (_modules.indexOf(name) === -1) { 69 | _modules.push(name); 70 | } 71 | } 72 | }); 73 | 74 | walk.on('end', function() { 75 | fn(); 76 | }); 77 | }, 78 | next 79 | ); 80 | }, 81 | function(err) { 82 | if (!!err || _modules.length < 1) { 83 | return reject('There are no modules to remove.'); 84 | } 85 | 86 | async.each( 87 | _modules, 88 | rimraf, 89 | function(err) { 90 | if (!!err) { 91 | return reject(err); 92 | } 93 | 94 | resolve(); 95 | } 96 | ); 97 | }); 98 | }); 99 | }); 100 | } 101 | 102 | /** Start Removing 103 | ================================*/ 104 | findModules(program.args) 105 | .then(function() { 106 | lib.utils.success('Modules have been removed from your project.'); 107 | process.exit(0); 108 | }, lib.utils.error); 109 | -------------------------------------------------------------------------------- /bin/clever-repl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , fs = require('fs') 7 | , os = require('os') 8 | , _ = require('lodash') 9 | , replFile = path.join(__dirname, '..', 'lib', 'repl.js'); 10 | 11 | lib 12 | .util 13 | .locations 14 | .get() 15 | .then(function(projects) { 16 | var project = _.find(projects, function(p) { 17 | return p.name === 'backend'; 18 | }); 19 | 20 | if (typeof project === 'undefined') { 21 | lib.utils.fail('Couldn\'t find the backend CleverStack directory! Possible reasons could include:\n* Not running the REPL command within the root folder of the project\n* Not setting the correct NODE_PATH environment variable'); 22 | } 23 | 24 | if (!process.env.NODE_ENV || !fs.existsSync(path.join(project.moduleDir, 'config', process.env.NODE_ENV + 'js'))) { 25 | process.env.NODE_ENV = 'local'; 26 | } 27 | 28 | var processEnv = process.env; 29 | processEnv.NODE_PATH = path.resolve(path.join(project.moduleDir, 'lib')) + path.sep + (os.platform() === 'win32' ? ';' : ':') + path.resolve(path.join(project.moduleDir, 'modules')) + path.sep; 30 | processEnv.projectDir = project.moduleDir; 31 | processEnv.libDir = path.resolve(path.join(__dirname, '..', 'index')); 32 | 33 | var proc = require('child_process').spawn('node', [ replFile ], { cwd: process.cwd(), env: processEnv, stdio: 'inherit' }); 34 | proc.on('exit', function() { 35 | process.exit(); 36 | }); 37 | }).catch(function(err) { 38 | lib.utils.fail(err); 39 | }); 40 | -------------------------------------------------------------------------------- /bin/clever-routes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , fs = require('fs') 6 | , program = GLOBAL.program = {} 7 | , os = require('os') 8 | , _ = require('lodash') 9 | , routesFile = path.join(__dirname, '..', 'lib', 'routes.js'); 10 | 11 | lib 12 | .util 13 | .locations 14 | .get() 15 | .then(function(projects) { 16 | var project = _.find(projects, function(p) { 17 | return p.name === 'backend'; 18 | }); 19 | 20 | if (typeof project === 'undefined') { 21 | lib.utils.fail('Couldn\'t find the backend CleverStack directory! Possible reasons could include:\n* Not running the REPL command within the root folder of the project\n* Not setting the correct NODE_PATH environment variable'); 22 | } 23 | 24 | if (!process.env.NODE_ENV || !fs.existsSync(path.join(project.moduleDir, 'config', process.env.NODE_ENV + 'js'))) { 25 | process.env.NODE_ENV = 'local'; 26 | } 27 | 28 | var processEnv = process.env; 29 | processEnv.NODE_PATH = path.resolve(path.join(project.moduleDir, 'lib')) + path.sep + (os.platform() === 'win32' ? ';' : ':') + path.resolve(path.join(project.moduleDir, 'modules')) + path.sep; 30 | processEnv.projectDir = project.moduleDir; 31 | processEnv.libDir = path.resolve(path.join(__dirname, '..', 'index')); 32 | 33 | require('child_process').exec('node ' + routesFile, { cwd: process.cwd(), env: processEnv }, function (err, stdout) { 34 | console.log(stdout); 35 | process.exit(0); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /bin/clever-s: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | 5 | require(path.join(__dirname, 'clever-scaffold')); 6 | -------------------------------------------------------------------------------- /bin/clever-scaffold: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , scaffold = lib.generator.scaffold; 7 | 8 | /** Define CLI Usage 9 | ================================*/ 10 | program.version(lib.pkg.version); 11 | 12 | program 13 | .usage('[options] ') 14 | .option('--no-service', 'Disables generating a service.') 15 | .option('--no-controller', 'Disables generating a controller.') 16 | .option('--no-model', 'Disables generating a model.') 17 | .option('--no-task', 'Disables generating a task.') 18 | .option('--no-test', 'Disables generating a test.'); 19 | 20 | /** Define CLI Help 21 | ================================*/ 22 | program.on('--help', function() { 23 | console.log(' Note:'); 24 | console.log(' Scaffold will generate templates within ' + process.cwd()); 25 | console.log(' If you wish to generate an entire model use clever new '); 26 | console.log(''); 27 | console.log(' Example:'); 28 | console.log(' clever scaffold my_component'); 29 | console.log(' clever scaffold myComponent'); 30 | console.log(''); 31 | }); 32 | 33 | /** Parse CLI Arguments 34 | ================================*/ 35 | program.parse(process.argv); 36 | if (program.rawArgs.length < 3) { 37 | program.help(); 38 | } 39 | 40 | /** Start Scaffolding 41 | ================================*/ 42 | var filterOut = [] 43 | , filters = [ 'service', 'controller', 'model', 'task', 'test' ]; 44 | 45 | filters.forEach(function(filter) { 46 | if (program[ filter ] === false) { 47 | filterOut.push(filter); 48 | } 49 | }); 50 | 51 | if (filterOut.length === filters.length) { 52 | program.help(); 53 | } 54 | 55 | var args = program.rawArgs.splice(2); 56 | scaffold(args[ 0 ], filterOut, function(err) { 57 | if (!!err) { 58 | lib.utils.fail(err); 59 | process.exit(1); 60 | } 61 | 62 | process.exit(0); 63 | }); 64 | -------------------------------------------------------------------------------- /bin/clever-search: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander'); 6 | 7 | program.version(lib.pkg.version); 8 | 9 | program.on('--help', function() { 10 | console.log(' Examples:'); 11 | console.log(' clever search users'); 12 | console.log(' clever search users auth email'); 13 | console.log(''); 14 | }); 15 | 16 | program.parse(process.argv); 17 | 18 | // args void of initial commands 19 | var args = process.argv.slice(2); 20 | 21 | if (!args) { 22 | program.help(); 23 | } 24 | 25 | lib 26 | .search 27 | .aggregate(args) 28 | .spread(function(npm, bower) { 29 | var repos = npm.concat(bower); 30 | 31 | if (repos.length < 1) { 32 | lib.utils.fail('Couldn\'t find any modules that were compatible with CleverStack.'); 33 | } 34 | 35 | lib.utils.success('Found ' + repos.length + ' module' + (repos.length !== 1 ? 's' : '')); 36 | console.log(''); 37 | 38 | repos.forEach(lib.repos.display); 39 | process.exit(0); 40 | }) 41 | .catch(function(err) { 42 | lib.utils.fail(err); 43 | }); 44 | -------------------------------------------------------------------------------- /bin/clever-serve: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | 5 | require(path.join(__dirname, 'clever-server')); 6 | -------------------------------------------------------------------------------- /bin/clever-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , fs = require('fs') 7 | , os = require('os') 8 | , isWin = /^win32/.test(os.platform()) 9 | , spawn = require('child_process').spawn; 10 | 11 | /** Define CLI Usage 12 | ================================*/ 13 | program 14 | .version(lib.pkg.version) 15 | .option('-x, --host [host]', 'Set the host for grunt server') 16 | .option('-p, --port [port]', 'Set the port for grunt server'); 17 | 18 | /** Define CLI Help 19 | ================================*/ 20 | program.on('--help', function() { 21 | console.log(' Example:'); 22 | console.log(' clever server'); 23 | console.log(' clever --host 10.0.0.0 server'); 24 | console.log(' clever --port 7777 server'); 25 | console.log(''); 26 | }); 27 | 28 | /** Parse CLI Arguments 29 | ================================*/ 30 | program.parse(process.argv); 31 | 32 | 33 | /** Start Servers 34 | ================================*/ 35 | // get a list of directories within $CWD (or package.json if we're inside the directory...) 36 | var currentDir = path.resolve(process.cwd()) 37 | , dir = fs.readdirSync(currentDir) 38 | , isInProject = false 39 | , folders = []; 40 | 41 | dir.filter(function(d) { 42 | var stats = fs.statSync(path.resolve(path.join(currentDir, d))); 43 | return d === 'package.json' || stats.isDirectory(); 44 | }) 45 | // now let's try to find package information within those directories 46 | // basically we're trying to figure out if it's the backend or frontend directory... 47 | .forEach(function(d) { 48 | isInProject = [ 'package.json' ].indexOf(d) === -1; 49 | 50 | var pkg = isInProject ? path.resolve(path.join(currentDir, d, 'package.json')) : path.resolve(path.join(currentDir, d)); 51 | if (fs.existsSync(pkg)) { 52 | var readPkg = require(pkg) 53 | , hasPkgName = readPkg.hasOwnProperty('name'); 54 | 55 | // we only need to know if it's an official cleverstack repo or not... 56 | // since the grunt server option is the same, we just literally need to 57 | // use indexOf 58 | if (hasPkgName && ['angular-seed', 'node-seed'].indexOf(readPkg.name) > -1) { 59 | folders.push({ 60 | name: readPkg.name, 61 | path: path.resolve(path.join(pkg, '..')) 62 | }); 63 | } 64 | } 65 | }); 66 | 67 | if (folders.length < 1) { 68 | lib.utils.fail('CleverStack couldn\'t find a backend or frontend directory within ' + process.cwd()); 69 | } 70 | 71 | var procs = []; 72 | 73 | folders.forEach(function(folder, i) { 74 | var args = [ '--base', folder.path, '--gruntfile', path.resolve(path.join(folder.path, 'Gruntfile.js')) ]; 75 | 76 | if (program.host && isInProject) { 77 | args.push('--host'); 78 | args.push(program.host); 79 | } 80 | 81 | if (program.port && isInProject) { 82 | args.push('--port'); 83 | args.push(program.port); 84 | } 85 | 86 | if (folder.name === 'node-seed') { 87 | args.push('server:web'); 88 | } else { 89 | args.push('server'); 90 | } 91 | 92 | var env = process.env; 93 | 94 | if (fs.existsSync(path.join(folder.path, 'lib'))) { 95 | // @TODO implement node_path helper and cater with different os types (aka ;) 96 | var nodePath = [ path.join(folder.path, 'lib') + path.sep, path.join(folder.path, 'modules') + path.sep ].join(':'); 97 | env.NODE_PATH = process.env.NODE_PATH ? process.env.NODE_PATH + (os.platform() === 'win32' ? ';' : ':') + nodePath : nodePath; 98 | } 99 | 100 | procs[i] = spawn(!isWin ? 'grunt' : 'grunt.cmd', args, { cwd: folder.path, env: env, stdio: 'inherit' }); 101 | }); 102 | -------------------------------------------------------------------------------- /bin/clever-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , fs = require('fs') 7 | , os = require('os') 8 | , isWin = /^win32/.test(os.platform()) 9 | , spawn = require('child_process').spawn 10 | , async = require('async') 11 | , folders = []; 12 | 13 | /** 14 | * Looks for a Gruntfile within seeds folder for grunt test 15 | * 16 | * @param {String} reporter What type of reporter do you want to display (Mocha reporters) 17 | * @return {Undefined} process.exit(0) 18 | */ 19 | 20 | function start(reporter) { 21 | lib.utils.info('Scanning folders for Gruntfiles...'); 22 | 23 | var walker = require('findit')(process.cwd()); 24 | 25 | walker.on('directory', function(dir, stat, stop) { 26 | var base = path.basename(dir); 27 | if ([ '.git', 'node_modules', 'lib', 'tests', 'spec', 'config', 'app', 'scripts', 'test', 'modules' ].indexOf(base) > -1) { 28 | stop(); 29 | } 30 | }); 31 | 32 | walker.on('file', function(root) { 33 | if ([ 'gruntfile.js', 'grunt.js' ].indexOf(path.basename(root).toLowerCase()) > -1) { 34 | folders.push({ 35 | path: path.dirname(root), 36 | name: path.basename(root) 37 | }); 38 | } 39 | }); 40 | 41 | walker.on('end', function() { 42 | if (folders.length < 1) { 43 | lib.utils.fail('CleverStack couldn\'t find a seed directory with a Gruntfile within ' + process.cwd()); 44 | } 45 | 46 | // find the shortest path (should be either the $PWD or one directory deep) 47 | var shortestPath = folders.reduce(function(p, c) { 48 | return p.path.split(path.sep).length > c.path.split(path.sep).length ? c : p; 49 | }); 50 | 51 | folders = folders.filter(function(f) { 52 | return f.path.split(path.sep).length === shortestPath.path.split(path.sep).length; 53 | }); 54 | 55 | async.eachSeries( 56 | folders, 57 | function(folder, next) { 58 | var args = [ '--base', folder.path, '--gruntfile', path.resolve(path.join(folder.path, folder.name)) ] 59 | , env = process.env; 60 | 61 | args.push(('test' + (typeof reporter._name !== 'string' ? '' : ':' + reporter._name))); 62 | 63 | if (!process.env.NODE_ENV) { 64 | env.NODE_ENV = 'local'; 65 | } 66 | 67 | if (fs.existsSync(path.resolve(path.join(folder.path, 'modules')))) { 68 | // @TODO implement node_path helper 69 | var paths = process.env.NODE_PATH ? [process.env.NODE_PATH] : []; 70 | paths.push(path.resolve(path.join(folder.path, 'lib')) + path.sep); 71 | paths.push(path.resolve(path.join(folder.path, 'modules')) + path.sep); 72 | env.NODE_PATH = paths.join(os.platform() === 'win32' ? ';' : ':'); 73 | } 74 | 75 | var proc = spawn(!isWin ? 'grunt' : 'grunt.cmd', args, { cwd: folder.path, env: env, stdio: 'inherit' }) 76 | , error = ''; 77 | 78 | proc.on('error', function(err) { 79 | error += err; 80 | }); 81 | 82 | proc.on('close', function(code) { 83 | if (code !== 0) { 84 | return lib.utils.fail(error); 85 | } 86 | 87 | next(); 88 | }); 89 | }, 90 | function() { 91 | // grunt doesn't pass an error to us... 92 | // grunt will quit before we get to here... 93 | lib.utils.success('Tests ran successfully.'); 94 | process.exit(0); 95 | } 96 | ); 97 | }); 98 | } 99 | 100 | /** Define CLI Usage 101 | ================================*/ 102 | program.version(lib.pkg.version); 103 | 104 | var reporters = [ 'e2e', 'unit', 'coverage' ]; 105 | 106 | reporters.forEach(function(reporter) { 107 | program 108 | .command(reporter) 109 | .description((reporter === 'coverage' ? 'Generates unit test coverage reports.' : 'Runs ' + reporter + ' tests')) 110 | .action(start); 111 | }); 112 | 113 | /** Define CLI Help 114 | ================================*/ 115 | program.on('--help', function() { 116 | console.log(' Examples:'); 117 | console.log(''); 118 | console.log(' clever test coverage'); 119 | console.log(' clever test e2e'); 120 | console.log(' clever test unit'); 121 | console.log(''); 122 | }); 123 | 124 | /** Parse CLI Arguments 125 | ================================*/ 126 | program.parse(process.argv); 127 | 128 | 129 | /** Start tests 130 | ================================*/ 131 | if (!program.args.length) { 132 | start('unit'); 133 | } 134 | -------------------------------------------------------------------------------- /bin/clever-tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | 5 | require(path.join(__dirname, 'clever-test')); 6 | -------------------------------------------------------------------------------- /bin/clever-upgrade: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | , lib = GLOBAL.lib = require(path.join(__dirname, '..', 'lib')) 5 | , program = GLOBAL.program = require('commander') 6 | , Promise = require('bluebird') 7 | , async = require('async') 8 | , _ = require('lodash'); 9 | 10 | /** Define CLI Usage 11 | ================================*/ 12 | program 13 | .option('-v, --verbose', 'verbose output useful for debugging') 14 | .version(lib.pkg.version); 15 | 16 | /** Define CLI Help 17 | ================================*/ 18 | program.on('--help', function() { 19 | console.log(' Examples:'); 20 | console.log(''); 21 | console.log(' clever upgrade clever-orm'); 22 | console.log(' clever upgrade clever-orm@0.0.3 clever-datatables@0.0.2'); 23 | console.log(' clever upgrade backend'); 24 | console.log(' clever upgrade frontend'); 25 | console.log(''); 26 | }); 27 | 28 | /** Parse CLI Arguments 29 | ================================*/ 30 | program.parse(process.argv); 31 | var args = []; 32 | process.argv.slice(2).forEach(function(arg) { 33 | if (arg !== '-v' && arg !== '--verbose') { 34 | args.push(arg); 35 | } 36 | }); 37 | 38 | /** Start Upgrading 39 | ================================*/ 40 | // We don't need version numbers when we're checking for backend or frontend... 41 | var _args = args.map(function (a) { 42 | return a.split('@')[ 0 ]; 43 | }); 44 | 45 | // Figure out what we're trying to upgrade... 46 | var findBackend = _args.indexOf('backend'); 47 | if (findBackend > -1) { 48 | var backendVersion = args[ findBackend ].split('@')[ 1 ]; 49 | args[ findBackend ] = 'node-seed' + (typeof backendVersion !== 'undefined' ? '@' + backendVersion : ''); 50 | } 51 | 52 | var findFrontend = _args.indexOf('frontend'); 53 | if (findFrontend > -1) { 54 | var frontendVersion = args[ findFrontend ].split('@')[ 1 ]; 55 | args[ findFrontend ] = 'node-seed' + (typeof frontendVersion !== 'undefined' ? '@' + frontendVersion : ''); 56 | } 57 | 58 | var modules = []; 59 | if (args.length < 1) { 60 | modules.push('node-seed'); 61 | modules.push('angular-seed'); 62 | } else { 63 | modules = args; 64 | } 65 | 66 | lib .util 67 | .locations 68 | .get() 69 | .then(function(locations) { 70 | // Filter for module's existence 71 | async.map( 72 | modules, 73 | function(module, filter) { 74 | var moduleSplit = module.split('@') 75 | , moduleName = moduleSplit[ 0 ] 76 | , moduleVersion = '*'; 77 | 78 | if (typeof moduleSplit[ 1 ] !== 'undefined') { 79 | moduleVersion = moduleSplit[ 1 ]; 80 | } 81 | 82 | lib .util 83 | .module 84 | .findConfigAndVersionForModule(locations, moduleName, moduleVersion) 85 | .then(function(m) { 86 | filter(null, m); 87 | }, filter); 88 | }, 89 | function (err, modulesToInstall) { 90 | var modulesInstall = modulesToInstall.filter(function (m) { 91 | return typeof m === 'object' && m !== null; 92 | }); 93 | 94 | if (!modulesInstall.length) { 95 | return lib.utils.fail('There are no modules to upgrade.'); 96 | } 97 | 98 | var backendModules = modulesInstall.filter(function (m) { 99 | return m.type === 'backend'; 100 | }) 101 | .map(function (m) { 102 | return m.name; 103 | }); 104 | 105 | var frontendModules = modulesInstall.filter(function (m) { 106 | return m.type === 'frontend'; 107 | }) 108 | .map(function (m) { 109 | return m.name; 110 | }); 111 | 112 | var actions = [ ] 113 | , backendLoc = _.find(locations, function (loc) { return loc.name === 'backend'; }) 114 | , frontendLoc = _.find(locations, function (loc) { return loc.name === 'frontend'; }); 115 | 116 | if (backendModules.length && !!backendLoc) { 117 | actions.push(lib.project.setupModules(backendLoc, backendModules)); 118 | } 119 | 120 | if (frontendModules.length && !!frontendLoc) { 121 | actions.push(lib.project.setupModules(frontendLoc, frontendModules)); 122 | } 123 | 124 | Promise.all(actions) 125 | .then(function () { 126 | lib.utils.success('Upgrade process has been completed.'); 127 | process.exit(0); 128 | }) 129 | .catch(function (err) { 130 | lib.utils.fail(err); 131 | }); 132 | }); 133 | }) 134 | .catch(function (err) { 135 | lib.utils.fail(err); 136 | }); 137 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = require(path.join(__dirname, 'lib')); 4 | -------------------------------------------------------------------------------- /lib/boot.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | , fs = require('fs') 3 | , lib = require(process.env.libDir) 4 | , tryPath = path.resolve(path.join(process.env.projectDir, 'lib', 'utils')) 5 | , utils; 6 | 7 | if (fs.existsSync(tryPath)) { 8 | try { 9 | utils = require(tryPath); 10 | } catch (error) { 11 | if (error.code === 'ENOENT' && error.path.match(/lib\.json$/) !== null) { 12 | lib.utils.fail('CleverStack couldn\'t find the environment configuration file. Please make sure you set your NODE_ENV envrionment variable.'); 13 | } else { 14 | lib.utils.fail(error); 15 | } 16 | } 17 | } 18 | 19 | if (utils === null) { 20 | lib.utils.fail('Couldn\'t find the backend CleverStack directory! Possible reasons could include:\n* Not running the command within the root folder of the project\n* Not setting the correct NODE_PATH environment variable'); 21 | } 22 | 23 | // Bootstrap the environment 24 | var env = utils.bootstrapEnv(); 25 | 26 | // Load all the modules 27 | try { 28 | // Fire the routesInitialized event so that our templated event handlers are parsed 29 | env.moduleLoader.on('modulesLoaded', function() { 30 | env.moduleLoader.emit('routesInitialized'); 31 | }); 32 | env.moduleLoader.loadModules(); 33 | } catch (_error) { 34 | if (_error.code === 'MODULE_NOT_FOUND') { 35 | lib.utils.fail('Couldn\'t find the backend CleverStack directory! Possible reasons could include:\n* Not running the command within the root folder of the project\n* Not setting the correct NODE_PATH environment variable'); 36 | } 37 | } 38 | 39 | exports.env = env; 40 | -------------------------------------------------------------------------------- /lib/colors.js: -------------------------------------------------------------------------------- 1 | var clc = require('cli-color'); 2 | 3 | module.exports = { 4 | sky: clc.cyanBright, 5 | green: clc.xterm( 112 ), 6 | blue: clc.xterm( 68 ), 7 | orange: clc.xterm( 172 ), 8 | red: clc.xterm( 1 ), 9 | gray: clc.xterm( 7 ), 10 | grey: clc.xterm( 7 ), 11 | darkGray: clc.xterm( 8 ), 12 | darkGrey: clc.xterm( 8 ), 13 | lightGreen: clc.xterm( 11 ), 14 | lightGray: clc.xterm( 250 ) 15 | }; 16 | -------------------------------------------------------------------------------- /lib/command.js: -------------------------------------------------------------------------------- 1 | var spawn = require('child_process').spawn 2 | , path = require('path') 3 | , fs = require('fs'); 4 | 5 | /** 6 | * Launches the main clever bin program 7 | * 8 | * @param {String} thePath 9 | * @param {Commander} program 10 | * @param {String} cmd 11 | * @param {String[]} args 12 | * @api public 13 | */ 14 | 15 | module.exports = function (thePath, program, cmd, args) { 16 | if (arguments.length < 4) { 17 | args = cmd; 18 | cmd = program; 19 | program = require(path.join(__dirname, 'program')); 20 | } 21 | 22 | if (arguments.length < 2) { 23 | cmd = 'clever'; 24 | } 25 | 26 | if (!cmd) { 27 | program.help(); 28 | } 29 | 30 | // executable name 31 | var bin = 'clever-' + cmd; 32 | if (cmd === 'clever') { 33 | bin = 'clever'; 34 | } 35 | 36 | // local or resolve to absolute executable path 37 | var local = path.join(thePath, bin); 38 | 39 | if (fs.existsSync(local)) { 40 | bin = local; 41 | } else { 42 | // @TODO Support windows here 43 | bin = process.env.PATH.split(':').reduce(function(binary, p) { 44 | p = path.resolve(p, bin); 45 | return fs.existsSync(p) && fs.statSync(p).isFile() ? p : binary; 46 | }, bin); 47 | } 48 | 49 | // if the bin doesn't exist within the cleverstack binary 50 | // try finding it within the project/module folder... 51 | if (!fs.existsSync(bin)) { 52 | bin = path.join(__dirname, cmd); 53 | 54 | // if bin/cmd doesn't exist, then try clever- prefix 55 | if (!fs.existsSync(bin)) { 56 | bin = path.join(__dirname, 'clever-' + cmd); 57 | } 58 | } 59 | 60 | // display help if bin does not exist 61 | if (!fs.existsSync(bin)) { 62 | console.error('\n %s command does not exist', bin); 63 | program.help(); 64 | process.exit(0); 65 | } 66 | 67 | // Windows support 68 | args.unshift(bin); 69 | 70 | // spawn 71 | var proc = spawn('node', args, { stdio: 'inherit' }); 72 | proc.on('close', function(code) { 73 | process.exit(code); 74 | }); 75 | }; 76 | -------------------------------------------------------------------------------- /lib/generate/fs.js: -------------------------------------------------------------------------------- 1 | var Promise = require('bluebird') 2 | , path = require('path') 3 | , async = require('async') 4 | , mkdirp = require('mkdirp') 5 | , fs = require('fs') 6 | , paths = require(path.join(__dirname, 'paths')); 7 | 8 | /** 9 | * Adds a list of directories 10 | * 11 | * @param {String[]} dirs Directories to add 12 | * @return {Promise} Returns a promise 13 | * @api private 14 | */ 15 | var makeDirs = exports.makeDirs = function(dirs) { 16 | return new Promise(function(resolve, reject) { 17 | async.each( 18 | dirs, 19 | function(dir, next) { 20 | mkdirp(dir, next); 21 | }, 22 | function(err) { 23 | if (!!err) { 24 | return reject(err); 25 | } 26 | 27 | resolve(dirs); 28 | } 29 | ); 30 | }); 31 | }; 32 | 33 | /** 34 | * Creates directories within the seed 35 | * 36 | * @param {Object} project Object returned from util.locations.get() 37 | * @param {String[]} tmpls An array of which templates to create 38 | * @param {String} names Name of the module 39 | * @return {Promise} Returns a promise 40 | * @api public 41 | */ 42 | exports.touchDirs = function(project, tmpls, names) { 43 | return new Promise(function(resolve, reject) { 44 | var dirs = [] 45 | , walk = require('findit')(path.join(__dirname, '..', '..', 'templates', project.name)); 46 | 47 | walk.on('directory', function(dir) { 48 | var hasSubFolder = tmpls.indexOf(dir.split(path.sep).splice(-2)[ 0 ]) > -1 49 | , hasParentFolder = tmpls.indexOf(dir.split(path.sep).splice(-1)[ 0 ]) > -1 50 | , inFolder = hasSubFolder || hasParentFolder 51 | , isNotBasename = path.basename(dir) !== project.name; 52 | 53 | if (isNotBasename && inFolder) { 54 | names.forEach(function (name) { 55 | dirs.push(dir.replace(path.resolve(path.join(__dirname, '..', '..', 'templates', project.name)), paths.getModulePath(project, name))); 56 | }); 57 | } 58 | }); 59 | 60 | walk.on('end', function() { 61 | makeDirs(dirs).then(function(dirs) { 62 | resolve(dirs); 63 | }, function (err) { 64 | reject(err); 65 | }); 66 | }); 67 | }); 68 | }; 69 | 70 | /** 71 | * Checks to see if generating conflicts with any files/folders already created 72 | * 73 | * @param {Object} project Object returned from util.locations.get() 74 | * @param {String[]} dirs An array of dir paths 75 | * @param {String[]} tmpls An array of templates 76 | * @param {String[]} names An array of names to generate 77 | * @return {Promise} Returns a promise from bluebird 78 | * @api public 79 | */ 80 | exports.checkFiles = function(project, dirs, tmpls, names) { 81 | return new Promise(function(resolve, reject) { 82 | var found = false; 83 | 84 | async.each( 85 | names, 86 | function(name, next) { 87 | async.each( 88 | tmpls, 89 | function(tmpl, _next) { 90 | var walk = require('findit')(path.join(__dirname, '..', '..', 'templates', project.name, tmpl)); 91 | 92 | walk.on('file', function(file) { 93 | var realPath = path.resolve(file.replace(path.join(__dirname, '..', '..', 'templates', project.name, tmpl), path.join(paths.getModulePath(project, name), tmpl))) 94 | , realName = paths.fileName(file.split(path.sep).splice(-1).join(path.sep), name); 95 | 96 | if (fs.existsSync(realPath.replace(file.split(path.sep).reverse()[ 0 ], realName))) { 97 | found = path.join(realPath, realName); 98 | } 99 | }); 100 | 101 | walk.on('end', function() { 102 | _next(found === false ? null : found.split(path.sep).reverse()[ 0 ] + ' already exists within ' + found.split(path.sep).splice(-1)); 103 | }, next); 104 | }, 105 | function(err) { 106 | if (!!err) { 107 | reject(err); 108 | } else { 109 | resolve(); 110 | } 111 | }); 112 | } 113 | ); 114 | }); 115 | }; 116 | -------------------------------------------------------------------------------- /lib/generate/index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | exports.fs = require(path.join(__dirname, 'fs' )); 4 | exports.paths = require(path.join(__dirname, 'paths' )); 5 | exports.render = require(path.join(__dirname, 'render')); 6 | -------------------------------------------------------------------------------- /lib/generate/paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | , tcase = require('t-case') 3 | , i = require('i')(); 4 | 5 | /** 6 | * Returns the template path for a specific seed 7 | * 8 | * @param {Object} project Object returned from util.locations.get() 9 | * @param {String} name Name of the seed 10 | * @return {String} Path to the template 11 | * @api public 12 | */ 13 | 14 | exports.getTemplatePath = function(project, name) { 15 | return path.resolve([ __dirname, '..', '..', 'templates', project.name ].concat(name).join(path.sep)); 16 | }; 17 | 18 | /** 19 | * Returns module's path 20 | * 21 | * @param {Object} project Object returned from util.locations.get() 22 | * @param {String} name Name of the module 23 | * @return {String} Path to the module 24 | * @api public 25 | */ 26 | 27 | exports.getModulePath = function(project, name) { 28 | var n = name.split(path.sep) 29 | , moduleName = n.splice(-1)[ 0 ] 30 | , proj = project.useCWD === true ? process.cwd() : path.join(project.moduleDir, project.modulePath); 31 | 32 | return path.resolve([ proj ].concat(n.length > 0 ? n.join(path.sep) : [ ], moduleName).join(path.sep)); 33 | }; 34 | 35 | /** 36 | * Returns the correct filename from templates 37 | * 38 | * @param {String} templateName Template's file name 39 | * @param {String} name Module's name 40 | * @return {String} New file name 41 | * @api public 42 | */ 43 | 44 | exports.fileName = function(templateName, name) { 45 | name = templateName 46 | .replace('Template', tcase.classCase(i.singularize(name))) 47 | .replace('template', tcase.classCase(i.singularize(name))); 48 | 49 | return name; 50 | }; 51 | -------------------------------------------------------------------------------- /lib/generate/render.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | , async = require('async') 3 | , fs = require('fs') 4 | , tcase = require('t-case') 5 | , es = require('event-stream') 6 | , i = require('i')() 7 | , paths = require(path.join(__dirname, 'paths')); 8 | 9 | /** 10 | * Transforms the file from a template to the actual module 11 | * 12 | * @param {String} from Path to the file to convert from 13 | * @param {String} to Path to convert the file into 14 | * @param {String} name Name of the module 15 | * @param {Function} fn Callback functions 16 | * @return {Function} Returns fn 17 | * @api public 18 | */ 19 | 20 | var transformFile = exports.transformFile = function(from, to, name, fn) { 21 | var file = fs.createWriteStream(to); 22 | var read = fs.createReadStream(from, { encoding: 'utf-8' }) 23 | .pipe(es.replace('{{modulename}}', name)) 24 | .pipe(es.replace('{{Template}}', i.singularize(tcase.classCase(name)))) 25 | .pipe(es.replace('{{TemplateName}}', i.singularize(tcase.classCase(name)))) 26 | .pipe(es.replace('{{template-name}}', i.singularize(tcase.paramCase(name)))) 27 | .pipe(es.replace('{{_template_}}', i.singularize(tcase.classCase(name)))) 28 | .pipe(es.replace('{{template_name}}', i.singularize(tcase.classCase(name)))) 29 | .pipe(file); 30 | 31 | read.on('error', fn); 32 | 33 | file 34 | .on('error', fn) 35 | .on('close', function() { 36 | fn(null, to); 37 | }); 38 | }; 39 | 40 | /** 41 | * Compiles a list of files to transform 42 | * 43 | * @param {String[]} dirs Path to directories to look into 44 | * @param {String[]} names Module names 45 | * @param {String[]} tmpls Which templates we want from the seed 46 | * @param {Object} project Object returned from util.locations.get() 47 | * @param {Function} fn Callback functions 48 | * @return {Functions} Returns fn 49 | * @api public 50 | */ 51 | 52 | exports.template = function(dirs, names, tmpls, project, fn) { 53 | var files = []; 54 | 55 | async.each( 56 | names, 57 | function(name, next) { 58 | async.each( 59 | tmpls, 60 | function(tmpl, _next) { 61 | var filter = path.join(paths.getModulePath(project, name), tmpl); 62 | 63 | async.eachSeries( 64 | dirs.filter(function(dir) { 65 | return filter.indexOf(dir) > -1; 66 | }), 67 | function eachFile(dir, __next) { 68 | var _files = [] 69 | , templateHome = paths.getTemplatePath(project, tmpl) 70 | , finder = require('findit')(templateHome); 71 | 72 | finder.on('file', function(file) { 73 | _files.push(file); 74 | }); 75 | 76 | finder.on('end', function() { 77 | async.eachSeries( 78 | _files, 79 | function eachFileEnd(file, ___next) { 80 | var _fileName = i.singularize(name.split(path.sep).splice(-1)[ 0 ]); 81 | 82 | var fileName = file.replace(templateHome, '') 83 | .replace('Template', tcase.classCase(_fileName)) 84 | .replace('template', tcase.classCase(_fileName)) 85 | , to = path.resolve(path.join(paths.getModulePath(project, name) , tmpl, fileName )); 86 | 87 | transformFile(file, to, name, function(err, filePath) { 88 | if (!!err) { 89 | return ___next(err); 90 | } 91 | 92 | files.push(filePath); 93 | 94 | ___next(); 95 | }); 96 | }, 97 | function(err) { 98 | __next(err); 99 | } 100 | ); 101 | }); 102 | }, 103 | _next 104 | ); 105 | }, 106 | next 107 | ); 108 | }, 109 | function(err) { 110 | fn(err, files); 111 | } 112 | ); 113 | }; 114 | -------------------------------------------------------------------------------- /lib/generator.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | , async = require('async') 3 | , fs = require('fs') 4 | , util = GLOBAL.lib.util 5 | , utils = GLOBAL.lib.utils 6 | , generator = require(path.join(__dirname, 'generate', 'index')); 7 | 8 | /** 9 | * Executes the generation process 10 | * 11 | * @param {Object[]} projects Objects returned from util.locations.get() 12 | * @param {String[]} tmpls An array of which templates to take from 13 | * @param {String[]} names Names of the modules 14 | * @param {Function} fn Callback functions 15 | * @return {Function} Returns fn 16 | * @api private 17 | */ 18 | function generateRun(projects, tmpls, names, fn) { 19 | async.each( 20 | projects, 21 | function(project, next) { 22 | generator.fs 23 | .touchDirs(project, tmpls, names) 24 | .then(function(dirs) { 25 | return generator 26 | .fs 27 | .checkFiles(project, dirs, tmpls, names) 28 | .then(function() {}) 29 | .return(dirs); 30 | }) 31 | .then(function(dirs) { 32 | generator 33 | .render 34 | .template(dirs, names, tmpls, project, function(err, files) { 35 | if (!!err) { 36 | return fn(err); 37 | } 38 | 39 | files.forEach(function(file) { 40 | utils.success('Created ' + file); 41 | }); 42 | 43 | next(); 44 | }); 45 | }, 46 | function(err) { 47 | utils.fail(err); 48 | }) 49 | .catch(function(err) { 50 | fn(err); 51 | }); 52 | }, 53 | fn 54 | ); 55 | } 56 | 57 | /** 58 | * Helper function for scaffold vs generate 59 | * 60 | * @param {Object} project Object returned from project.locations() 61 | * @param {String[]} tmpls An array of which templates to look into 62 | * @param {String[]} names An array of module names 63 | * @param {Function} fn Callback function 64 | * @return {Function} Returns fn 65 | * @api public 66 | */ 67 | exports.generate = function(project, tmpls, names, fn) { 68 | if (arguments.length < 4) { 69 | fn = names; 70 | names = tmpls; 71 | tmpls = project; 72 | project = null; 73 | } 74 | 75 | fn = typeof fn === 'function' ? fn : function noop () { }; 76 | names = Array.isArray(names) ? names : [ names ]; 77 | tmpls = Array.isArray(tmpls) ? tmpls : [ tmpls ]; 78 | 79 | if (!!project) { 80 | project = Array.isArray(project) ? project : [ project ]; 81 | generateRun(project, tmpls, names, fn); 82 | } else { 83 | util 84 | .locations 85 | .get(true) 86 | .then(function(projects) { 87 | projects = Array.isArray(projects) ? projects : [ projects ]; 88 | generateRun(projects, tmpls, names, fn); 89 | }, fn); 90 | } 91 | }; 92 | 93 | /** 94 | * Generates a scaffold 95 | * 96 | * @param {Object} project Object returned by util.locations.get() 97 | * @param {String} name Name of the module 98 | * @param {String[]} filterOut Which templates to filter out 99 | * @param {Function} fn Callback function 100 | * @return {Function} Returns fn 101 | * @api private 102 | */ 103 | function generateScaffold(project, name, filterOut, fn) { 104 | var _path = path.join(__dirname, '..', 'templates', project.name) 105 | , walk = require('findit')(_path) 106 | , dirs = [] 107 | , files = [] 108 | , found = false 109 | , modPath = generator.paths.getModulePath(project, name); 110 | 111 | walk.on('directory', function(dir) { 112 | dirs.push(modPath + dir.replace(_path, '')); 113 | }); 114 | 115 | walk.on('file', function(file) { 116 | var to = generator.paths.fileName(file.replace(_path, modPath), name); 117 | if (fs.existsSync(to)) { 118 | found = true; 119 | } 120 | 121 | files.push({ from: file, to: to }); 122 | }); 123 | 124 | walk.on('end', function() { 125 | if (found === true) { 126 | return utils.fail(name + ' already exists within ' + modPath); 127 | } 128 | 129 | generator 130 | .fs 131 | .makeDirs(dirs) 132 | .then(function() { 133 | async.each( 134 | files, 135 | function(file, next) { 136 | generator.render.transformFile(file.from, file.to, name, next); 137 | }, 138 | fn 139 | ); 140 | }, fn); 141 | }); 142 | } 143 | 144 | /** 145 | * Scaffolds into a new module directory 146 | * 147 | * @param {Object[]} projects Objects returned from util.locations.get() 148 | * @param {String[]} names Names of the module 149 | * @param {String[]} filterOut Which templates that you want to exclude 150 | * @param {Function} fn Callback functions 151 | * @return {Function} Returns fn 152 | * @api public 153 | */ 154 | exports.newModule = function(projects, names, filterOut, fn) { 155 | projects = Array.isArray(projects) ? projects : [ projects ]; 156 | 157 | async.each( 158 | projects, 159 | function(project, next) { 160 | generateScaffold(project, names, filterOut, next); 161 | }, 162 | fn 163 | ); 164 | }; 165 | 166 | /** 167 | * Scaffolds a project within process.cwd() 168 | * 169 | * @param {Object} project Object returned from util.locations.get() 170 | * @param {String[]} names Names of the module 171 | * @param {String[]} filterOut Which templates you want to exclude 172 | * @param {Function} fn Callback functions 173 | * @return {Functions} Returns fn 174 | * @api private 175 | */ 176 | function scaffoldProject(project, names, filterOut, fn) { 177 | project.useCWD = true; 178 | 179 | async.each( 180 | names, 181 | function(name, next) { 182 | generateScaffold(project, name, filterOut, next); 183 | }, 184 | fn 185 | ); 186 | } 187 | 188 | /** 189 | * Helper function to scaffold projects 190 | * 191 | * @param {String} name Name of the module 192 | * @param {String[]} filterOut Which templates you want to exclude 193 | * @param {Function} fn Callback function 194 | * @return {Functions} Returns fn 195 | * @api public 196 | */ 197 | module.exports.scaffold = function(name, filterOut, fn) { 198 | name = Array.isArray(name) ? name : [ name ]; 199 | filterOut = Array.isArray(filterOut) ? filterOut : []; 200 | 201 | // Just for easability, we'll add an 's' to the end of the filters to cover a quasi-plural form 202 | filterOut = filterOut.concat( 203 | filterOut.map(function(filter) { 204 | return filter === 'factory' ? 'factories' : filter + 's'; 205 | }) 206 | ); 207 | 208 | util 209 | .locations 210 | .get() 211 | .then(function(projects) { 212 | async.each( 213 | projects, 214 | function(p, next) { 215 | scaffoldProject(p, name, filterOut, next); 216 | }, 217 | function(err) { 218 | if (!!err) { 219 | return utils.fail(err); 220 | } 221 | 222 | utils.success('Scaffold complete.'); 223 | 224 | if (typeof fn === 'function') { 225 | return fn(); 226 | } 227 | } 228 | ); 229 | }) 230 | .error(fn); 231 | }; 232 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var path = require( 'path' ) 2 | , libs = module.exports = {} 3 | , loaded = {}; 4 | 5 | // note: leave ./program.js out of this otherwise commander will blend sub programs together 6 | var availableLibs = [ 7 | 'command', 'colors', 'repos', 'utils', 'search', 'install', 'project', 'packages', 'generator', 8 | [ 'util', path.join( 'util', 'index' ) ], 9 | [ 'pkg', path.join( '..', 'package.json' ) ] 10 | ]; 11 | 12 | // Only require the lib if we haven't already done so 13 | if ( GLOBAL.lib === undefined ) { 14 | availableLibs.forEach( function( libName ) { 15 | var libPath = libName; 16 | 17 | // availableLibs = [ [ name, path ], ... ] 18 | if ( libName instanceof Array ) { 19 | libPath = libName[ 1 ]; 20 | libName = libName[ 0 ]; 21 | } 22 | Object.defineProperty( libs, libName, { 23 | get: function() { 24 | if ( !loaded[ libName ] ) { 25 | loaded[ libName ] = require( path.join( __dirname, libPath ) ); 26 | } 27 | return loaded[ libName ]; 28 | }, 29 | enumerable: true 30 | }); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /lib/install.js: -------------------------------------------------------------------------------- 1 | var Promise = require('bluebird') 2 | , path = require('path') 3 | , _ = require('lodash') 4 | , https = require('follow-redirects').https 5 | , proxyAgent = require('https-proxy-agent') 6 | , async = require('async') 7 | , utils = GLOBAL.lib.utils 8 | , search = GLOBAL.lib.search 9 | , packages = GLOBAL.lib.packages 10 | , util = GLOBAL.lib.util; 11 | 12 | /** 13 | * Launches the installation process 14 | * Checks for seed folders depending on CWD 15 | * Separates which packages we need via Bower and NPM 16 | * Installs the NPM/Bower modules within the seeds 17 | * 18 | * @param {Array} repos 19 | * @return {Promise} 20 | * @api private 21 | */ 22 | function install(repos) { 23 | return new Promise(function(resolve, reject) { 24 | util.locations 25 | .findAvailableCommands() 26 | .spread(function(locations) { 27 | return search.aggregate(repos).spread(function(npm, bower) { 28 | return [ locations, npm, bower ]; 29 | }); 30 | }) 31 | .spread(function(locations, npm, bower) { 32 | var actions = [] 33 | // todo: make this into a function... 34 | // todo: also make packages.locations() a prototype for .isBackend() utility functions, etc. 35 | , backend = _.find(locations, function(location) { 36 | return location.name === 'backend'; 37 | }) 38 | , frontend = _.find(locations, function(location) { 39 | return location.name === 'frontend'; 40 | }); 41 | 42 | if (typeof backend === 'undefined' && frontend === 'undefined') { 43 | utils.fail('Couldn\'t find a CleverStack seed. Please make sure that you\'re trying to install within your CleverStack project.'); 44 | } 45 | 46 | if (typeof backend === 'undefined') { 47 | npm = []; 48 | } 49 | 50 | if (typeof frontend === 'undefined') { 51 | bower = []; 52 | } 53 | 54 | if (npm.length < 1 && bower.length < 1) { 55 | utils.fail('No modules to install, please make sure you\'re tring to install CleverStack compatible modules and that you\'re in the correct seed folder.'); 56 | } 57 | 58 | if (npm.length > 0) { 59 | actions.push(packages.installWithNpm(backend, npm)); 60 | } 61 | 62 | if (bower.length > 0) { 63 | actions.push(packages.installWithBower(frontend, bower)); 64 | } 65 | 66 | Promise 67 | .all(actions) 68 | .then(function() { 69 | resolve([ backend, frontend, npm, bower ]); 70 | }) 71 | .catch(function(err) { 72 | reject(err); 73 | }); 74 | }) 75 | .catch(function(err) { 76 | reject(err); 77 | }); 78 | }); 79 | } 80 | 81 | function installBackendModules(backendPath, npm) { 82 | return new Promise(function(resolve, reject) { 83 | npm = npm.map(function(n) { 84 | return n.name; 85 | }); 86 | 87 | var walker = require('findit')(path.join(backendPath.moduleDir, backendPath.modulePath)) 88 | , dirs = []; 89 | 90 | walker.on('directory', function(dir, stat, stop) { 91 | var _dirs = dir.split(path.sep) 92 | , _dir = _dirs.pop() 93 | , mdir = path.dirname(dir).split(path.sep).pop(); 94 | 95 | if (mdir === 'modules') { 96 | if (npm.indexOf(_dir) === -1) { 97 | return stop(); 98 | } 99 | 100 | dirs.push(path.join(_dirs.join(path.sep), _dir)); 101 | } 102 | }); 103 | 104 | walker.on('end', function() { 105 | if (dirs.length > 0) { 106 | lib.utils.info([ ' Installing module peerDependencies...' ].join('')); 107 | 108 | async.each( 109 | dirs, 110 | function installModulePeerDependencies(dir, installed) { 111 | util 112 | .dependencies 113 | .installPeerDependencies(dir, path.join(backendPath.moduleDir, backendPath.modulePath)) 114 | .then(function () { 115 | installed(); 116 | }) 117 | .catch(installed); 118 | }, 119 | function peerDependenciesInstalled(err) { 120 | if (!!err) { 121 | return reject(err); 122 | } 123 | 124 | async.eachSeries( 125 | npm, 126 | function(module, next) { 127 | util 128 | .grunt 129 | .runTasks(backendPath.moduleDir, path.join(backendPath.moduleDir, backendPath.modulePath, module)) 130 | .then(next, next); 131 | }, 132 | function( err) { 133 | if (!!err) { 134 | return reject(err); 135 | } 136 | 137 | resolve(); 138 | } 139 | ); 140 | } 141 | ); 142 | } 143 | }); 144 | }); 145 | } 146 | 147 | 148 | exports.run = function(args) { 149 | return new Promise(function(resolve, reject) { 150 | install(args) 151 | .spread(function(backendPath, frontendPath, npm /*, bower */) { 152 | var actions = []; 153 | 154 | if (npm.length > 0) { 155 | actions.push(installBackendModules(backendPath, npm)); 156 | } 157 | 158 | Promise 159 | .all(actions) 160 | .then(function runNpmTasksForModules() { 161 | resolve(); 162 | }) 163 | .catch(reject); 164 | }) 165 | .catch(reject); 166 | }); 167 | }; 168 | 169 | /** 170 | * Returns JSON object from an HTTP(S) request 171 | * 172 | * @param {Object} options HTTP Object 173 | * @return {Promise} Returns a promise from bluebird 174 | * @public 175 | */ 176 | exports.getJSON = function(options) { 177 | // Handle HTTP_PROXY and HTTPS_PROXY environment variables 178 | var proxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null; 179 | if (proxy !== null) { 180 | options.agent = new proxyAgent(proxy); 181 | } 182 | 183 | return new Promise(function(resolve) { 184 | var req = https.request(options, function(res) { 185 | res.setEncoding('utf-8'); 186 | 187 | if (res.statusCode !== 200) { 188 | return resolve(); 189 | } 190 | 191 | var responseString = ''; 192 | 193 | res.on('data', function(data) { 194 | responseString += data; 195 | }); 196 | 197 | res.on('end', function() { 198 | var body = JSON.parse(responseString); 199 | resolve(body); 200 | }); 201 | }); 202 | 203 | req.end(); 204 | }); 205 | }; 206 | -------------------------------------------------------------------------------- /lib/program.js: -------------------------------------------------------------------------------- 1 | var program = require('commander') 2 | , path = require('path') 3 | , pkg = require(path.join(__dirname, '..', 'package.json')); 4 | 5 | program 6 | .usage(' [options]') 7 | .version(pkg.version); 8 | 9 | program.on('--help', function() { 10 | console.log(' Commands:'); 11 | console.log(''); 12 | console.log(' build - Builds production-ready code for the frontend seed'); 13 | console.log(' downgrade - Downgrades a CleverStack implementation'); 14 | console.log(' help - Displays this help message'); 15 | console.log(' init [backend|frontend] - Initialized a new project'); 16 | console.log(' install - Installs a module within CleverStack'); 17 | console.log(' generate