Browse files

Initial commit. Refactoring angular-project-template into yeoman gene…

…rator.
  • Loading branch information...
0 parents commit e41fe8316fa0e1f4636a2dcba0f3da471e91943f Chris Gross committed Jun 18, 2013
10 .editorconfig
@@ -0,0 +1,10 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
1 .gitattributes
@@ -0,0 +1 @@
+* text=auto
2 .gitignore
@@ -0,0 +1,2 @@
+node_modules/
+temp/
22 .jshintrc
@@ -0,0 +1,22 @@
+{
+ "node": true,
+ "es5": true,
+ "esnext": true,
+ "bitwise": true,
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "indent": 4,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "quotmark": "single",
+ "regexp": true,
+ "undef": true,
+ "unused": true,
+ "strict": true,
+ "trailing": true,
+ "smarttabs": true,
+ "white": true
+}
4 .travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - '0.8'
+ - '0.10'
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright 2013 Chris Gross
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
98 README.md
@@ -0,0 +1,98 @@
+#generator-cg-angular
+
+>Yeoman Generator for Enterprise Angular Projects
+
+Features
+
+* Provides a directory structure geared towards large Angular projects.
+ * Each controller, service, filter, and directive are placed in their own file.
+ * All files related to a conceptual unit are placed together. For example, the controller and HTML file for a partial are placed together in the same directory.
+* Provides a ready-made Grunt build that produces an extremely optimized distribution.
+* Integrates Bower for package management
+* Includes Yeoman sub-generators for directives, services, partials, and filters
+* Integrates LESS and includes Bootstrap via the source LESS files allowing you to reuse Bootstrap vars/mixins/etc.
+* Testable - Included Yeoman sub-generators also build test skeletons. Run test via `grunt test`.
+
+Directory Layout
+-------------
+Below is an explanation of the folder structure.
+
+ /css ........................................... usually only contains app.less
+ app.less ................................... main app-wide styles
+ /img ........................................... images (not created by default but included in bin if added)
+ /js ............................................ app global javascript files
+ setup.js ................................... angular module initialization and route setup
+ /directive. .................................... angular directives folder
+ my-directive.js ............................ example simple directive
+ /my-directive2 ............................. example complex directive (contains external partial)
+ my-directive2.js ....................... complex directive javascript
+ my-directive2.html ..................... complex directive partial
+ my-directive2.less ..................... complex directive LESS
+ /filter ........................................ angular filters folder
+ my-filter.js ............................... example filter
+ /partial ....................................... angular partials folder
+ /my-partial ................................ example partial
+ my-partial.html ........................ example partial html
+ my-partial.js .......................... example partial controller
+ my-partial.less ........................ example partial LESS
+ /service ....................................... angular services folder
+ my-service.js .............................. example service
+ /bin ........................................... distributable version of app built using grunt and Gruntfile.js
+ /lib ........................................... 3rd party libraries, managed by bower (renamed components to lib)
+ /node_modules .................................. npm managed libraries used by grunt
+
+Getting Started
+-------------
+
+Prerequisites: Node, Grunt, Yeoman, and Bower. Once Node is installed, do:
+
+ npm install -g grunt-cli yo bower
+
+Next, install this generator:
+
+ npm install -g generator-cg-angular
+
+To create a project:
+
+ mkdir MyNewAwesomeApp
+ cd MyNewAwesomeApp
+ yo cg-angular
+
+Grunt Tasks
+-------------
+
+Now that the project is created, you have 3 simple Grunt commands available:
+
+ grunt server #This will run a development server with watch & reload enabled.
+ grunt test #Run headless unit tests using PhantomJS.
+ grunt build #Places a fully optimized (minified, concatenated, and more) in /bin
+
+Yeoman Subgenerators
+-------------
+
+There are a set of sub-generators to initialize empty Angular components. Each of these generators will:
+
+* Create one or more skeleton files (javascript, LESS, html, etc) for the component type
+* Create a skeleton unit test in /test
+* Update index.html and add the necessary `script` tags.
+* Update app.less and add the @import as needed.
+* For partials, update the setup.js, adding the necessary route call if a route was entered in the generator prompts.
+
+There are generators for `directive`,`partial`,`service`, and `filter`.
+
+Running a generator:
+
+ yo cg-angular:directive my-awesome-directive
+ yo cg-angular:partial my-partial
+ yo cg-angular:service my-service
+ yo cg-angular:filter my-filter
+
+The name paramater passed (i.e. 'my-awesome-directive') will be used for directory and/or file names. The generators will derive appropriate class names from this parameter (ex. 'my-awesome-directive' will convert to a class name of 'MyAwesomeDirective').
+
+One quick note, each sub-generator pulls the Angular app/module name from the package.json. Therefore, if you choose to change the name of your Angular app/module, you must ensure that the name in the package.json stays in sync.
+
+Release History
+-------------
+
+* 6/18/2013 v1.0.0 - Initial release of template as Yeoman generator.
+
41 app/index.js
@@ -0,0 +1,41 @@
+'use strict';
+var util = require('util');
+var path = require('path');
+var yeoman = require('yeoman-generator');
+
+
+var CgangularGenerator = module.exports = function CgangularGenerator(args, options, config) {
+ yeoman.generators.Base.apply(this, arguments);
+
+ this.on('end', function () {
+ this.installDependencies({ skipInstall: options['skip-install'] });
+ });
+
+ this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
+};
+
+util.inherits(CgangularGenerator, yeoman.generators.Base);
+
+CgangularGenerator.prototype.askFor = function askFor() {
+ var cb = this.async();
+
+ var prompts = [{
+ name: 'appname',
+ message: 'What would you like the angular app/module name to be?',
+ default: path.basename(process.cwd())
+ }];
+
+ this.prompt(prompts, function (props) {
+ this.appname = props.appname;
+
+ cb();
+ }.bind(this));
+};
+
+CgangularGenerator.prototype.app = function app() {
+ this.directory('skeleton/','./');
+ this.template('skeleton/js/setup.js','./js/setup.js');
+ this.template('skeleton/bower.json','./bower.json');
+ this.template('skeleton/index.html','./index.html');
+ this.template('skeleton/package.json','./package.json');
+};
3 app/templates/skeleton/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory" : "lib"
+}
10 app/templates/skeleton/.editorconfig
@@ -0,0 +1,10 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
22 app/templates/skeleton/.jshintrc
@@ -0,0 +1,22 @@
+{
+ "node": true,
+ "es5": true,
+ "esnext": true,
+ "bitwise": true,
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "indent": 4,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "quotmark": "single",
+ "regexp": true,
+ "undef": true,
+ "unused": true,
+ "strict": true,
+ "trailing": true,
+ "smarttabs": true,
+ "white": true
+}
203 app/templates/skeleton/Gruntfile.js
@@ -0,0 +1,203 @@
+'use strict';
+var path = require('path');
+var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
+
+var folderMount = function folderMount(connect, point) {
+ return connect.static(path.resolve(point));
+};
+
+module.exports = function (grunt) {
+ // Project configuration.
+ grunt.initConfig({
+ connect: {
+ livereload: {
+ options: {
+ port: 9001,
+ middleware: function(connect, options) {
+ return [lrSnippet, folderMount(connect, options.base)]
+ }
+ }
+ }
+ },
+ regarde: {
+ all: {
+ files: ['js/**/*','css/**/*','img/**/*','lib/**/*','partials/**/*','services/**/*','filters/**/*','index.html'],
+ tasks: ['livereload']
+ }
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true,
+ browser: true,
+ smarttabs: true,
+ globals: {
+ jQuery: true,
+ angular: true,
+ console: true,
+ $: true,
+ _: true,
+ moment: true,
+ app: true
+ }
+ },
+ files: ['js/**/*.js','partials/**/*.js','services/**/*.js','filters/**/*.js']
+ },
+ clean: {
+ before:{
+ src:['bin','temp']
+ },
+ after: {
+ src:['temp']
+ }
+ },
+ less: {
+ production: {
+ options: {
+ },
+ files: {
+ "temp/app.css": "css/app.less"
+ }
+ }
+ },
+ ngtemplates: {
+ app: {
+ src: [ 'partials/**/*.html','directives/**/*.html' ],
+ dest: 'temp/templates.js'
+ }
+ },
+ copy: {
+ main: {
+ files: [
+ {src: ['index.html'], dest: 'bin/'},
+ {src: ['img/**'], dest: 'bin/'},
+ {src: ['lib/angular-ui/build/angular-ui-ieshiv.js'], dest: 'bin/'},
+ {src: ['lib/font-awesome/build/assets/font-awesome/font/**'], dest: 'bin/',filter:'isFile',expand:true},
+ // {src: ['lib/select2/*.png','lib/select2/*.gif'], dest:'bin/css/',flatten:true,expand:true},
+ {src: ['lib/angular-mocks/angular-mocks.js'], dest: 'bin/'}
+ ]
+ }
+ },
+ dom_munger:{
+ readscripts: {
+ options: {
+ read:{selector:'script[data-build!="exclude"]',attribute:'src',writeto:'appjs'}
+ },
+ src:'index.html'
+ },
+ readcss: {
+ options: {
+ read:{selector:'link[rel="stylesheet"]',attribute:'href',writeto:'appcss'}
+ },
+ src:'index.html'
+ },
+ removescripts: {
+ options:{
+ remove:'script[data-remove!="exclude"]',
+ append:{selector:'head',html:'<script src="app.full.min.js"></script>'}
+ },
+ src:'bin/index.html'
+ },
+ addscript: {
+ options:{
+ append:{selector:'body',html:'<script src="app.full.min.js"></script>'}
+ },
+ src:'bin/index.html'
+ },
+ removecss: {
+ options:{
+ remove:'link',
+ append:{selector:'head',html:'<link rel="stylesheet" href="css/app.full.min.css">'}
+ },
+ src:'bin/index.html'
+ },
+ addcss: {
+ options:{
+ append:{selector:'head',html:'<link rel="stylesheet" href="css/app.full.min.css">'}
+ },
+ src:'bin/index.html'
+ }
+ },
+ cssmin: {
+ main: {
+ src:['temp/app.css','<%= dom_munger.data.appcss %>'],
+ dest:'bin/css/app.full.min.css'
+ }
+ },
+ concat: {
+ main: {
+ src: ['<%= dom_munger.data.appjs %>','<%= ngtemplates.app.dest %>'],
+ dest: 'temp/app.full.js'
+ }
+ },
+ ngmin: {
+ main: {
+ src:'temp/app.full.js',
+ dest: 'temp/app.full.js'
+ }
+ },
+ uglify: {
+ main: {
+ src: 'temp/app.full.js',
+ dest:'bin/app.full.min.js'
+ }
+ },
+ htmlmin: {
+ main: {
+ options: {
+ removeComments: true,
+ collapseWhitespace: true
+ },
+ files: {
+ 'bin/index.html': 'bin/index.html'
+ }
+ }
+ },
+ imagemin: {
+ main:{
+ files: [{
+ expand: true, cwd:'bin/',
+ src:['**/{*.png,*.jpg}'],
+ dest: 'bin/'
+ }]
+ }
+ },
+ jasmine: {
+ unit: {
+ src: ['<%= dom_munger.data.appjs %>','lib/angular-mocks/angular-mocks.js'],
+ options: {
+ specs: 'test/unit/*.js'
+ }
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-regarde');
+ grunt.loadNpmTasks('grunt-contrib-connect');
+ grunt.loadNpmTasks('grunt-contrib-livereload');
+ grunt.loadNpmTasks('grunt-angular-templates');
+ grunt.loadNpmTasks('grunt-contrib-clean');
+ grunt.loadNpmTasks('grunt-contrib-copy');
+ grunt.loadNpmTasks('grunt-contrib-cssmin');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-dom-munger');
+ grunt.loadNpmTasks('grunt-contrib-htmlmin');
+ grunt.loadNpmTasks('grunt-contrib-imagemin');
+ grunt.loadNpmTasks('grunt-contrib-less');
+ grunt.loadNpmTasks('grunt-contrib-jasmine');
+ grunt.loadNpmTasks('grunt-ngmin');
+
+ grunt.registerTask('build',['jshint','clean:before','less','dom_munger:readcss','dom_munger:readscripts','ngtemplates','cssmin','concat','ngmin','uglify','copy','dom_munger:removecss','dom_munger:addcss','dom_munger:removescripts','dom_munger:addscript','htmlmin','imagemin','clean:after']);
+ grunt.registerTask('server', ['livereload-start','jshint','connect', 'regarde']);
+ grunt.registerTask('test',['dom_munger:readscripts','jasmine'])
+};
25 app/templates/skeleton/bower.json
@@ -0,0 +1,25 @@
+{
+ "name": "<%= _.slugify(appname) %>",
+ "version": "0.0.0",
+ "main": "index.html",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "lib"
+ ],
+ "dependencies": {
+ "jquery": "1.x",
+ "lodash": "~1.2.1",
+ "bootstrap": "~2.3.2",
+ "angular": "~1.0.7",
+ "angular-resource": "~1.0.7",
+ "angular-cookies": "~1.0.7",
+ "angular-mocks": "~1.0.7",
+ "angular-ui": "~0.4.0",
+ "angular-ui-utils": "~0.0.2",
+ "angular-bootstrap": "~0.3.0",
+ "moment": "~2.0.0",
+ "less.js": "~1.4.0",
+ "font-awesome": "~3.1.1"
+ }
+}
9 app/templates/skeleton/css/app.less
@@ -0,0 +1,9 @@
+@import "../lib/bootstrap/less/bootstrap.less";
+@import "../lib/font-awesome/build/assets/font-awesome/less/font-awesome.less";
+@FontAwesomePath: "../lib/font-awesome/build/assets/font-awesome/font";
+
+/* Directive LESS */
+/* Add Directive LESS Above */
+
+/* Partial LESS */
+/* Add Partial LESS Above */
67 app/templates/skeleton/index.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html ng-app="<%= _.slugify(appname) %>">
+<head>
+ <title>Sample</title>
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <!-- Libs -->
+ <link href="lib/angular-ui/build/angular-ui.css" rel="stylesheet">
+
+ <!-- App CSS -->
+ <link href="css/app.less" type="text/css" rel="stylesheet/less">
+
+</head>
+<body>
+
+ <!-- Libs -->
+ <script src="lib/less.js/dist/less-1.4.0.js" data-build="exclude"></script>
+ <script src="lib/jquery/jquery.js"></script>
+ <script src="lib/lodash/dist/lodash.compat.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-affix.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-alert.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-button.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-carousel.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-collapse.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-dropdown.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-modal.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-tooltip.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-popover.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-scrollspy.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-tab.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-transition.js"></script>
+ <script src="lib/bootstrap/js/bootstrap-typeahead.js"></script>
+ <script src="lib/angular/angular.min.js"></script>
+ <script src="lib/angular-resource/angular-resource.js"></script>
+ <script src="lib/angular-cookies/angular-cookies.js"></script>
+ <script src="lib/angular-ui/build/angular-ui.js"></script>
+ <script src="lib/angular-bootstrap/ui-bootstrap.js"></script>
+ <script src="lib/angular-bootstrap/ui-bootstrap-tpls.js"></script>
+ <script src="lib/moment/min/moment.min.js"></script>
+
+ <!-- Main App JS -->
+ <script src="js/setup.js"></script>
+
+ <!-- Service JS -->
+ <!-- Add New Service JS Above -->
+
+ <!-- Directive JS -->
+ <!-- Add New Directive JS Above -->
+
+ <!-- Filter JS -->
+ <!-- Add New Filter JS Above -->
+
+ <!-- Partial JS -->
+ <!-- Add New Partial JS Above -->
+
+ <div>
+ <div id="content" class="container">
+ <div class="row">
+ <div ng-view>
+ </div>
+ </div>
+ </div>
+ </div>
+
+</body>
+</html>
24 app/templates/skeleton/js/setup.js
@@ -0,0 +1,24 @@
+angular.module('<%= _.slugify(appname) %>', ["ui.bootstrap","ui"]);
+
+angular.module('<%= _.slugify(appname) %>').config(['$routeProvider', function($routeProvider) {
+
+ $routeProvider.
+ /* Add New Routes Above */
+ otherwise({redirectTo:'/home'});
+
+}]);
+
+angular.module('<%= _.slugify(appname) %>').run(['$rootScope', function($rootScope) {
+
+ $rootScope.safeApply = function(fn) {
+ var phase = $rootScope.$$phase;
+ if (phase === '$apply' || phase === '$digest') {
+ if (fn && (typeof(fn) === 'function')) {
+ fn();
+ }
+ } else {
+ this.$apply(fn);
+ }
+ };
+
+}]);
24 app/templates/skeleton/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "<%= _.slugify(appname) %>",
+ "version": "0.1.0",
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-contrib-livereload": "~0.1.2",
+ "grunt-regarde": "~0.1.1",
+ "grunt-contrib-connect": "~0.2.0",
+ "grunt-contrib-copy": "~0.4.1",
+ "grunt-contrib-clean": "~0.4.0",
+ "grunt-contrib-concat": "~0.1.3",
+ "grunt-contrib-cssmin": "~0.5.0",
+ "grunt-contrib-uglify": "~0.2.0",
+ "grunt-jasmine-task": "0.2.x",
+ "grunt-angular-templates": "~0.3.1",
+ "grunt-contrib-jshint": "~0.3.0",
+ "grunt-dom-munger": "~2.0.0",
+ "grunt-contrib-htmlmin": "~0.1.1",
+ "grunt-contrib-imagemin": "~0.1.2",
+ "grunt-contrib-jasmine": "~0.4.1",
+ "grunt-ngmin": "0.0.2",
+ "grunt-contrib-less": "~0.6.0"
+ }
+}
59 directive/index.js
@@ -0,0 +1,59 @@
+'use strict';
+var util = require('util');
+var yeoman = require('yeoman-generator');
+var path = require('path');
+var cgUtils = require('../utils.js');
+
+var DirectiveGenerator = module.exports = function DirectiveGenerator(args, options, config) {
+
+ yeoman.generators.NamedBase.apply(this, arguments);
+
+ try {
+ this.appname = require(path.join(process.cwd(), 'package.json')).name;
+ } catch (e) {
+ this.appname = 'Cant find name from package.json';
+ }
+
+};
+
+util.inherits(DirectiveGenerator, yeoman.generators.NamedBase);
+
+DirectiveGenerator.prototype.askFor = function askFor() {
+ var cb = this.async();
+
+ var prompts = [{
+ type:'confirm',
+ name: 'needpartial',
+ message: 'Does this directive need an external html file (i.e. partial)?',
+ default: true
+ }];
+
+ this.prompt(prompts, function (props) {
+ this.needpartial = props.needpartial;
+
+ cb();
+ }.bind(this));
+};
+
+DirectiveGenerator.prototype.files = function files() {
+
+ if (this.needpartial){
+ this.template('directive.js', 'directive/'+this.name+'/'+this.name+'.js');
+ this.template('directive.html', 'directive/'+this.name+'/'+this.name+'.html');
+ this.template('directive.less', 'directive/'+this.name+'/'+this.name+'.less');
+ this.template('spec.js', 'test/unit/directive/'+this.name+'.js');
+
+ cgUtils.addToFile('index.html','<script src="directive/'+this.name+'/'+this.name+'.js"></script>',cgUtils.DIRECTIVE_JS_MARKER,' ');
+ this.log.writeln(' updating'.green + ' %s','index.html');
+
+ cgUtils.addToFile('css/app.less','@import "../directive/'+this.name+'/'+this.name+'.less";',cgUtils.DIRECTIVE_LESS_MARKER,'');
+ this.log.writeln(' updating'.green + ' %s','app/app.less');
+ } else {
+ this.template('directive_simple.js', 'directive/'+this.name+'.js');
+ this.template('spec.js', 'test/unit/directive/'+this.name+'.js');
+
+ cgUtils.addToFile('index.html','<script src="directive/'+this.name+'.js"></script>',cgUtils.DIRECTIVE_JS_MARKER,' ');
+ this.log.writeln(' updating'.green + ' %s','index.html');
+ }
+
+};
4 directive/templates/directive.html
@@ -0,0 +1,4 @@
+<div>
+
+
+</div>
14 directive/templates/directive.js
@@ -0,0 +1,14 @@
+angular.module('<%= appname %>').directive('<%= _.classify(name) %>', function() {
+ return {
+ restrict: 'E',
+ replace: true,
+ scope: {
+
+ },
+ templateUrl: 'directives/<%= name %>/<%= name %>.html',
+ link: function(scope, element, attrs, fn) {
+
+
+ }
+ };
+});
0 directive/templates/directive.less
No changes.
9 directive/templates/directive_simple.js
@@ -0,0 +1,9 @@
+angular.module('<%= appname %>').directive('<%= _.classify(name) %>', function() {
+ return {
+ restrict: 'A',
+ link: function(scope, element, attrs, fn) {
+
+
+ }
+ };
+});
23 directive/templates/spec.js
@@ -0,0 +1,23 @@
+describe('<%= _.classify(name) %>', function() {
+
+ beforeEach(module('<%= appname %>'));
+
+ var scope,compile;
+
+ beforeEach(inject(function($rootScope,$compile) {
+ scope = $rootScope.$new();
+ compile = $compile;
+ }));
+
+ it('should ...', function() {
+
+ /*
+ To test your directive, you need to create some html that would use your directive,
+ send that through compile() then compare the results.
+
+ var element = compile('<div mydirective name="name">hi</div>')(scope);
+ expect(element.text()).toBe('hello, world');
+ */
+
+ });
+});
27 filter/index.js
@@ -0,0 +1,27 @@
+'use strict';
+var util = require('util');
+var yeoman = require('yeoman-generator');
+var path = require('path');
+var cgUtils = require('../utils.js');
+
+var FilterGenerator = module.exports = function FilterGenerator(args, options, config) {
+
+ yeoman.generators.NamedBase.apply(this, arguments);
+
+ try {
+ this.appname = require(path.join(process.cwd(), 'package.json')).name;
+ } catch (e) {
+ this.appname = 'Cant find name from package.json';
+ }
+
+};
+
+util.inherits(FilterGenerator, yeoman.generators.NamedBase);
+
+FilterGenerator.prototype.files = function files() {
+ this.template('filter.js', 'filter/'+this.name+'.js');
+ this.template('spec.js', 'test/unit/filter/'+this.name+'.js');
+
+ cgUtils.addToFile('index.html','<script src="filter/'+this.name+'.js"></script>',cgUtils.FILTER_JS_MARKER,' ');
+ this.log.writeln(' updating'.green + ' %s','index.html');
+};
5 filter/templates/filter.js
@@ -0,0 +1,5 @@
+angular.module('<%= appname %>').filter('<%= name %>', function() {
+ return function(input,arg) {
+ return "";
+ };
+});
11 filter/templates/spec.js
@@ -0,0 +1,11 @@
+describe('<%= name %>', function() {
+
+ beforeEach(module('<%= appname %>'));
+
+ it('should ...', inject(function(<%= name %>Filter) {
+
+ expect(<%= name %>Filter('filter input')).toEqual('filter result');
+
+ }));
+
+});
39 package.json
@@ -0,0 +1,39 @@
+{
+ "name": "generator-cg-angular",
+ "version": "1.0.0",
+ "description": "Yeoman Generator for Enterprise Angular projects.",
+ "keywords": [
+ "yeoman-generator"
+ ],
+ "homepage": "https://github.com/cgross/generator-cg-angular",
+ "bugs": "https://github.com/cgross/generator-cg-angular/issues",
+ "author": {
+ "name": "Chris Gross",
+ "email": "schtoo@schtoo.com",
+ "url": "https://github.com/cgross"
+ },
+ "main": "app/index.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/cgross/generator-cg-angular.git"
+ },
+ "scripts": {
+ "test": "mocha"
+ },
+ "dependencies": {
+ "yeoman-generator": "~0.12.0",
+ "underscore": "~1.4.4",
+ "underscore.string": "~2.3.1"
+ },
+ "devDependencies": {
+ "mocha": "~1.10.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ },
+ "licenses": [
+ {
+ "type": "MIT"
+ }
+ ]
+}
60 partial/index.js
@@ -0,0 +1,60 @@
+'use strict';
+var util = require('util');
+var yeoman = require('yeoman-generator');
+var path = require('path');
+var cgUtils = require('../utils.js');
+var _ = require('underscore');
+
+_.str = require('underscore.string');
+_.mixin(_.str.exports());
+
+var PartialGenerator = module.exports = function PartialGenerator(args, options, config) {
+
+ yeoman.generators.NamedBase.apply(this, arguments);
+
+ try {
+ this.appname = require(path.join(process.cwd(), 'package.json')).name;
+ } catch (e) {
+ this.appname = 'Cant find name from package.json';
+ }
+
+};
+
+util.inherits(PartialGenerator, yeoman.generators.NamedBase);
+
+PartialGenerator.prototype.askFor = function askFor() {
+ var cb = this.async();
+
+ var prompts = [{
+ name: 'route',
+ message: 'Enter your route name (i.e. /mypartial/:id). If you don\'t want a route added for you, leave this empty.'
+ }];
+
+ this.prompt(prompts, function (props) {
+ this.route = props.route;
+
+ cb();
+ }.bind(this));
+};
+
+PartialGenerator.prototype.files = function files() {
+
+ this.ctrlname = _.classify(this.name) + 'Ctrl';
+
+ this.template('partial.js', 'partial/'+this.name+'/'+this.name+'.js');
+ this.template('partial.html', 'partial/'+this.name+'/'+this.name+'.html');
+ this.template('partial.less', 'partial/'+this.name+'/'+this.name+'.less');
+ this.template('spec.js', 'test/unit/controller/'+this.name+'.js');
+
+ cgUtils.addToFile('index.html','<script src="partial/'+this.name+'/'+this.name+'.js"></script>',cgUtils.PARTIAL_JS_MARKER,' ');
+ this.log.writeln(' updating'.green + ' %s','index.html');
+
+ cgUtils.addToFile('css/app.less','@import "../partial/'+this.name+'/'+this.name+'.less";',cgUtils.PARTIAL_LESS_MARKER,'');
+ this.log.writeln(' updating'.green + ' %s','app/app.less');
+
+ if (this.route && this.route.length > 0){
+ cgUtils.addToFile('js/setup.js','when("'+this.route+'",{templateUrl: "partial/'+this.name+'/'+this.name+'.html"}).',cgUtils.ROUTE_MARKER,'\t');
+ this.log.writeln(' updating'.green + ' %s','js/setup.js');
+ }
+
+};
4 partial/templates/partial.html
@@ -0,0 +1,4 @@
+<div class="span12" ng-controller="<%= ctrlname %>">
+
+
+</div>
4 partial/templates/partial.js
@@ -0,0 +1,4 @@
+angular.module('<%= appname %>').controller('<%= ctrlname %>',function($scope){
+
+
+});
0 partial/templates/partial.less
No changes.
18 partial/templates/spec.js
@@ -0,0 +1,18 @@
+describe('<%= ctrlname %>', function() {
+
+ beforeEach(module('<%= appname %>'));
+
+ var scope,ctrl;
+
+ beforeEach(inject(function($rootScope, $controller) {
+ scope = $rootScope.$new();
+ ctrl = $controller(app.<%= ctrlname %>, {$scope: scope});
+ }));
+
+ it('should ...', inject(function() {
+
+ expect(1).toEqual(1);
+
+ }));
+
+});
27 service/index.js
@@ -0,0 +1,27 @@
+'use strict';
+var util = require('util');
+var yeoman = require('yeoman-generator');
+var path = require('path');
+var cgUtils = require('../utils.js');
+
+var ServiceGenerator = module.exports = function ServiceGenerator(args, options, config) {
+
+ yeoman.generators.NamedBase.apply(this, arguments);
+
+ try {
+ this.appname = require(path.join(process.cwd(), 'package.json')).name;
+ } catch (e) {
+ this.appname = 'Cant find name from package.json';
+ }
+
+};
+
+util.inherits(ServiceGenerator, yeoman.generators.NamedBase);
+
+ServiceGenerator.prototype.files = function files() {
+ this.template('service.js', 'service/'+this.name+'.js');
+ this.template('spec.js', 'test/unit/service/'+this.name+'.js');
+
+ cgUtils.addToFile('index.html','<script src="service/'+this.name+'.js"></script>',cgUtils.SERVICE_JS_MARKER,' ');
+ this.log.writeln(' updating'.green + ' %s','index.html');
+};
6 service/templates/service.js
@@ -0,0 +1,6 @@
+angular.module('<%= appname %>').factory('<%= name %>',function() {
+
+ var <%= name %> = {};
+
+ return <%= name %>;
+});
11 service/templates/spec.js
@@ -0,0 +1,11 @@
+describe('{%= js_name %}', function() {
+
+ beforeEach(module('<%= appname %>'));
+
+ it('should ...', inject(function({%= js_name %}) {
+
+ //expect({%= js_name %}.doSomething()).toEqual('something');
+
+ }));
+
+});
38 test/test-creation.js
@@ -0,0 +1,38 @@
+/*global describe, beforeEach, it*/
+'use strict';
+
+var path = require('path');
+var helpers = require('yeoman-generator').test;
+
+
+describe('cg-angular generator', function () {
+ beforeEach(function (done) {
+ helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
+ if (err) {
+ return done(err);
+ }
+
+ this.app = helpers.createGenerator('cgangular:app', [
+ '../../app'
+ ]);
+ done();
+ }.bind(this));
+ });
+
+ it('creates expected files', function (done) {
+ var expected = [
+ // add files you expect to exist here.
+ '.jshintrc',
+ '.editorconfig'
+ ];
+
+ helpers.mockPrompt(this.app, {
+ 'someOption': 'Y'
+ });
+ this.app.options['skip-install'] = true;
+ this.app.run({}, function () {
+ helpers.assertFiles(expected);
+ done();
+ });
+ });
+});
11 test/test-load.js
@@ -0,0 +1,11 @@
+/*global describe, beforeEach, it*/
+'use strict';
+
+var assert = require('assert');
+
+describe('cg-angular generator', function () {
+ it('can be imported without blowing up', function () {
+ var app = require('../app');
+ assert(app !== undefined);
+ });
+});
27 utils.js
@@ -0,0 +1,27 @@
+var path = require('path');
+var fs = require('fs');
+
+exports.addToFile = function(filename,lineToAdd,beforeMarker,spacing){
+
+ try {
+ var fullPath = path.join(process.cwd(),filename);
+ var fileSrc = fs.readFileSync(fullPath,'utf8');
+
+ var indexOf = fileSrc.indexOf(beforeMarker);
+ fileSrc = fileSrc.substring(0,indexOf) + lineToAdd + "\n" + spacing + fileSrc.substring(indexOf);
+
+ fs.writeFileSync(fullPath,fileSrc);
+
+ } catch(e) {
+ throw e;
+ }
+};
+
+exports.DIRECTIVE_LESS_MARKER = "/* Add Directive LESS Above */";
+exports.DIRECTIVE_JS_MARKER = "<!-- Add New Directive JS Above -->";
+exports.FILTER_JS_MARKER = "<!-- Add New Filter JS Above -->";
+exports.SERVICE_JS_MARKER = "<!-- Add New Service JS Above -->";
+exports.PARTIAL_LESS_MARKER = "/* Add Partial LESS Above */";
+exports.PARTIAL_JS_MARKER = "<!-- Add New Partial JS Above -->";
+
+exports.ROUTE_MARKER = "/* Add New Routes Above */";

0 comments on commit e41fe83

Please sign in to comment.