├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── README.MD ├── README.md ├── app ├── USAGE ├── index.js └── templates │ ├── bootstrap.css │ ├── images │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png │ └── styles │ ├── css │ ├── bootstrap.css │ └── main.css │ └── scss │ └── main.scss ├── common └── index.js ├── constant ├── USAGE └── index.js ├── contributing.md ├── controller ├── USAGE └── index.js ├── decorator ├── USAGE └── index.js ├── directive ├── USAGE └── index.js ├── factory ├── USAGE └── index.js ├── filter ├── USAGE └── index.js ├── main └── index.js ├── package.json ├── provider ├── USAGE └── index.js ├── route ├── USAGE └── index.js ├── script-base.js ├── service ├── USAGE └── index.js ├── templates ├── coffeescript-min │ ├── app.coffee │ ├── controller.coffee │ ├── decorator.coffee │ ├── directive.coffee │ ├── filter.coffee │ ├── service │ │ ├── constant.coffee │ │ ├── factory.coffee │ │ ├── provider.coffee │ │ ├── service.coffee │ │ └── value.coffee │ └── spec │ │ ├── controller.coffee │ │ ├── directive.coffee │ │ ├── filter.coffee │ │ └── service.coffee ├── coffeescript │ ├── app.coffee │ ├── controller.coffee │ ├── decorator.coffee │ ├── directive.coffee │ ├── filter.coffee │ ├── service │ │ ├── constant.coffee │ │ ├── factory.coffee │ │ ├── provider.coffee │ │ ├── service.coffee │ │ └── value.coffee │ └── spec │ │ ├── controller.coffee │ │ ├── directive.coffee │ │ ├── filter.coffee │ │ └── service.coffee ├── common │ ├── Gruntfile.js │ ├── Procfile │ ├── _bower.json │ ├── _package.json │ ├── app.js │ ├── bower.json │ ├── gitignore │ ├── index.html │ ├── package.json │ ├── root │ │ ├── .bowerrc │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .jshintrc │ │ ├── app │ │ │ ├── .buildignore │ │ │ ├── .htaccess │ │ │ ├── 404.html │ │ │ ├── favicon.ico │ │ │ ├── robots.txt │ │ │ ├── styles │ │ │ │ └── main.css │ │ │ └── views │ │ │ │ └── main.html │ │ └── test │ │ │ ├── .jshintrc │ │ │ └── runner.html │ └── view.html ├── javascript-min │ ├── app.js │ ├── controller.js │ ├── decorator.js │ ├── directive.js │ ├── filter.js │ ├── service │ │ ├── constant.js │ │ ├── factory.js │ │ ├── provider.js │ │ ├── service.js │ │ └── value.js │ └── spec │ │ ├── controller.js │ │ ├── directive.js │ │ ├── filter.js │ │ └── service.js └── javascript │ ├── app.js │ ├── controller.js │ ├── decorator.js │ ├── directive.js │ ├── filter.js │ ├── service │ ├── constant.js │ ├── factory.js │ ├── provider.js │ ├── service.js │ └── value.js │ └── spec │ ├── controller.js │ ├── directive.js │ ├── filter.js │ └── service.js ├── test ├── test-appname-substitution.js └── test-file-creation.js ├── util.js ├── value ├── USAGE └── index.js └── view ├── USAGE └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/temp 3 | test/UpperCaseBug 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.8' 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## v0.3.1 (2013-07-24) 3 | 4 | 5 | #* **Bug Fixes:** 6 | 7 | * **app:** 8 | * order of script inclusions ([9919b2d0](http://github.com/yeoman/generator-angular/commit/9919b2d0bb749cbe5e795608c2b93c3504e3298b), closes [#278](http://github.com/yeoman/generator-angular/issues/278)) 9 | * copy glyphicons for sass ([2c458009](http://github.com/yeoman/generator-angular/commit/2c4580096572678de6212c8592fb553c10b3a4c0), closes [#269](http://github.com/yeoman/generator-angular/issues/269)) 10 | * add jQuery \ into index.html template ([3766b4ff](http://github.com/yeoman/generator-angular/commit/3766b4ffe1b91a647a34577ae529d11c994e3a1d)) 11 | * **docs:** 12 | * fix section explaining generating services ([8b4787c6](http://github.com/yeoman/generator-angular/commit/8b4787c649b918cb2baf78369e86c86156bca2ec)) 13 | * Add explicit instructions for installing yo ([8404c068](http://github.com/yeoman/generator-angular/commit/8404c0687ab582e15b1f46f96da4f7812d641912)) 14 | 15 | 16 | #* **Features:** 17 | 18 | * **app:** 19 | * generate Travis config ([38a4ce9b](http://github.com/yeoman/generator-angular/commit/38a4ce9baa207c49c79b2f3128c2c3637164c011)) 20 | * use checkboxes for module selection ([65fe9d25](http://github.com/yeoman/generator-angular/commit/65fe9d25fdc1f9fa9c24c4858915c2b63b4531cb)) 21 | * add jshintrc for testing folder ([8727288b](http://github.com/yeoman/generator-angular/commit/8727288bcefdb255f3c24cf80ab1c7868b86d044)) 22 | * **build:** add support for svg optimization ([03d63c69](http://github.com/yeoman/generator-angular/commit/03d63c69e8006e563baee0cc4a4ba459e7c13ccd)) 23 | 24 | 25 | ## 0.3.0 (2013-06-26) 26 | 27 | #* **Features:** 28 | 29 | * **decorator:** 30 | * Add decorator template files ([c9f80b3d](http://github.com/yeoman/generator-angular/commit/c9f80b3d)) 31 | * Define creation of decorator at decorator/index.js and added USAGE File ([4c53c1ad](http://github.com/yeoman/generator-angular/commit/4c53c1ad)) 32 | * Add prompt if file already exists ([7d9b862c](http://github.com/yeoman/generator-angular/commit/7d9b862c)) 33 | 34 | * **build:** 35 | * Replace regard with contrib-watch ([edf00565](http://github.com/yeoman/generator-angular/commit/edf00565)) 36 | 37 | #* **Bug Fixes:** 38 | 39 | * **build:** 40 | * bad concatenation of main.css ([4c7e4b29](http://github.com/yeoman/generator-angular/commit/4c7e4b29)) 41 | * Bumped yeoman-generator version for new prompt ([9e899bb2](http://github.com/yeoman/generator-angular/commit/9e899bb2)) 42 | * don't override generated css files ([dd6a0cb1](http://github.com/yeoman/generator-angular/commit/dd6a0cb1)) 43 | * use Usemin for all CSS. ([e6c2fa52](http://github.com/yeoman/generator-angular/commit/e6c2fa52)) 44 | * dropped nospawn option from watch ([02f61f82](http://github.com/yeoman/generator-angular/commit/02f61f82)) 45 | * add svg files to the copy task ([4b897ac8](http://github.com/yeoman/generator-angular/commit/4b897ac8)) 46 | * updated generated dependencies ([cab7c423](http://github.com/yeoman/generator-angular/commit/cab7c423)) 47 | * add httpFontsPath to Gruntfile ([b00deb1a](http://github.com/yeoman/generator-angular/commit/b00deb1a)) 48 | * coffeescript build was empty ([54edc9de](http://github.com/yeoman/generator-angular/commit/54edc9de)) 49 | * add compass task only if compass-flavored bootstrap is selected ([4408413e](http://github.com/yeoman/generator-angular/commit/4408413e)) 50 | 51 | * **app:** 52 | * Bootstrap Compass no prompt on Bootstrap no ([e73ffc49](http://github.com/yeoman/generator-angular/commit/e73ffc49)) 53 | * Use boolean prompts ([da89e70d](http://github.com/yeoman/generator-angular/commit/da89e70d)) 54 | * components to bower_components ([01cee4ba](http://github.com/yeoman/generator-angular/commit/01cee4ba)) 55 | 56 | * **coffee:** syntax for minsafe directives ([62677ec0](http://github.com/yeoman/generator-angular/commit/62677ec0)) 57 | 58 | * **decorator:** 59 | 60 | * removed second dot in warning message ([6a89f8e5](http://github.com/yeoman/generator-angular/commit/6a89f8e5)) 61 | * use [] instead of new Array() to initialize prompts (jsHint) ([360222a6](http://github.com/yeoman/generator-angular/commit/360222a6)) 62 | 63 | * **test:** Updated tests for new prompt ([64e57571](http://github.com/yeoman/generator-angular/commit/64e57571)) 64 | 65 | * **cli:** fix typo in angular:constant generator usage ([6cbb80fd](http://github.com/yeoman/generator-angular/commit/6cbb80fd)) 66 | 67 | 68 | ## v0.2.2 (2013-04-20) 69 | 70 | #* **Features:** 71 | * **build:** Integrate grunt-rev into build process (87bab71) 72 | 73 | * **app:** 74 | 75 | * automatically install dependencies (9f95630) 76 | * add coffee option to Karma generator (e81b624) 77 | 78 | * **misc:** add Grunt support to automate releases and changelogs (9daa50a) 79 | 80 | #* **Bug Fixes:** 81 | * **build:** 82 | 83 | * remove all files except git related on clean (21a0f43) 84 | 85 | * fix Bower error caused by incorrect templates. (0ab5448) 86 | 87 | * Moved duplicate grunt options into own section (3869ca8) 88 | 89 | * grunt-bower-hooks was renamed (3bbaacd) 90 | 91 | * Watch SVG files. Fixes generator-webapp#41 (45fe8ab) 92 | 93 | * display correct message when running npm/bower (3498aa1) 94 | 95 | * add Bootstrap reference when not using Compass (d123897) 96 | 97 | * add SVG files to Grunt rev task. (3c8daab) 98 | 99 | * Changed to shallow copy fonts (1f6b864) 100 | 101 | * Ignore test subfolder (a07627b) 102 | 103 | * finify bootstrap img (263ce61) 104 | 105 | * **coffee:** 106 | 107 | * Fix compiling coffeescript files (71daa7f) 108 | 109 | * fix loading coffeescript tests (9692a21) 110 | 111 | * fix coffeescript directive test (aa2a9c0) 112 | 113 | * rewrite app.coffee file when called with --coffee (0f5256d) 114 | 115 | * **app:** 116 | 117 | * Remove `process.cwd()` from CS detection (3a707f4) 118 | 119 | * use this.env.options.appPath (404c752) 120 | 121 | * use `installDependencies()` method (8369d9a) 122 | 123 | * invoke karma:app with `skip-install` option if defined (7e47dc2) 124 | 125 | * tag closing inconsistency (ref #177) (51bd8d8) 126 | 127 | * **test:** 128 | 129 | * Use $scope in tests instead of {} (58603bd) 130 | 131 | * add Node 0.10 to travis file (60b1ea7) 132 | 133 | * **gen:** 134 | 135 | * Fix controller spec generation (3bb58eb) 136 | 137 | * remove trailing comma in gruntfile. (32afa5a) 138 | 139 | * **readme:** 140 | 141 | * add note to readme about making a node_modules dir until global generators are supported (73a2450) 142 | 143 | * add a note about running commands from the root app folder (f986c77) 144 | 145 | * switched to global generators (18ef336) 146 | 147 | * add note to readme about commit message conventions (d125dd2) 148 | 149 | * Improve readme (8262b93) 150 | 151 | * added documentation of route adding (7c5e03c) 152 | 153 | * Corrected file extension in example (a1149ea) 154 | 155 | * **tests:** skip install on tests (5035d94) 156 | 157 | 158 | ## v0.2.1 (2013-04-07) 159 | 160 | #* **Features:** 161 | * **build:** Integrate grunt-rev into build process (87bab71) 162 | 163 | * **app:** automatically install dependencies (9f95630) 164 | 165 | * **misc:** add Grunt support to automate releases and changelogs (9daa50a) 166 | 167 | 168 | 169 | #* **Bug Fixes:** 170 | * **build:** 171 | 172 | * remove all files except git related on clean (21a0f43) 173 | 174 | * fix Bower error caused by incorrect templates. (0ab5448) 175 | 176 | * Moved duplicate grunt options into own section (3869ca8) 177 | 178 | * grunt-bower-hooks was renamed (3bbaacd) 179 | 180 | * Watch SVG files. Fixes generator-webapp#41 (45fe8ab) 181 | 182 | * **coffee:** 183 | 184 | * Fix compiling coffeescript files (71daa7f) 185 | 186 | * fix loading coffeescript tests (9692a21) 187 | 188 | * fix coffeescript directive test (aa2a9c0) 189 | 190 | * rewrite app.coffee file when called with --coffee (0f5256d) 191 | 192 | * **app:** 193 | 194 | * Remove `process.cwd()` from CS detection (3a707f4) 195 | 196 | * **test:** 197 | 198 | * Use $scope in tests instead of {} (58603bd) 199 | 200 | * **gen:** 201 | 202 | * Fix controller spec generation (3bb58eb) 203 | 204 | * **readme:** 205 | 206 | * add note to readme about making a node_modules dir until global generators are supported (73a2450) 207 | 208 | * add a note about running commands from the root app folder (f986c77) 209 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var markdown = require('marked'); 3 | var semver = require('semver'); 4 | 5 | module.exports = function (grunt) { 6 | grunt.initConfig({ 7 | pkg: grunt.file.readJSON('package.json'), 8 | changelog: { 9 | options: { 10 | dest: 'CHANGELOG.md', 11 | versionFile: 'package.json' 12 | } 13 | }, 14 | release: { 15 | options: { 16 | commitMessage: '<%= version %>', 17 | tagName: 'v<%= version %>', 18 | bump: false, // we have our own bump 19 | file: 'package.json' 20 | } 21 | }, 22 | stage: { 23 | options: { 24 | files: ['CHANGELOG.md'] 25 | } 26 | } 27 | }); 28 | 29 | grunt.registerTask('bump', 'bump manifest version', function (type) { 30 | var options = this.options({ 31 | file: grunt.config('pkgFile') || 'package.json' 32 | }); 33 | 34 | function setup(file, type) { 35 | var pkg = grunt.file.readJSON(file); 36 | var newVersion = pkg.version = semver.inc(pkg.version, type || 'patch'); 37 | return { 38 | file: file, 39 | pkg: pkg, 40 | newVersion: newVersion 41 | }; 42 | } 43 | 44 | var config = setup(options.file, type); 45 | grunt.file.write(config.file, JSON.stringify(config.pkg, null, ' ') + '\n'); 46 | grunt.log.ok('Version bumped to ' + config.newVersion); 47 | }); 48 | 49 | grunt.registerTask('stage', 'git add files before running the release task', function () { 50 | var files = this.options().files; 51 | grunt.util.spawn({ 52 | cmd: process.platform === 'win32' ? 'git.cmd' : 'git', 53 | args: ['add'].concat(files) 54 | }, grunt.task.current.async()); 55 | }); 56 | 57 | grunt.loadNpmTasks('grunt-release'); 58 | grunt.loadNpmTasks('grunt-conventional-changelog'); 59 | 60 | grunt.registerTask('default', ['bump', 'changelog', 'stage', 'release']); 61 | }; 62 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | generator-express-angular 2 | ========================= 3 | 4 | yeoman angular generator with express 5 | 6 | ## Usage 7 | 8 | Install `generator-express-angular`: 9 | ``` 10 | npm install -g generator-express-angular 11 | ``` 12 | 13 | Make a new directory, and `cd` into it: 14 | ``` 15 | mkdir my-new-project && cd $_ 16 | ``` 17 | 18 | Run `yo express-angular`, optionally passing an app name: 19 | ``` 20 | yo express-angular [app-name] 21 | ``` 22 | 23 | ## Generators 24 | 25 | Available generators: 26 | 27 | * [express-angular](#app) (aka [express-angular:app](#app)) 28 | * [express-angular:controller](#controller) 29 | * [express-angular:directive](#directive) 30 | * [express-angular:filter](#filter) 31 | * [express-angular:route](#route) 32 | * [express-angular:service](#service) 33 | * [express-angular:view](#view) 34 | 35 | **Note: Generators are to be run from the root directory of your app.** 36 | 37 | ### App 38 | Sets up a new AngularJS app, generating all the boilerplate you need to get started. The app generator also optionally installs Twitter Bootstrap and additional AngularJS modules, such as angular-resource. 39 | 40 | Example: 41 | ```bash 42 | yo express-angular 43 | ``` 44 | 45 | ### Route 46 | Generates a controller and view, and configures a route in `app/scripts/app.js` connecting them. 47 | 48 | Example: 49 | ```bash 50 | yo express-angular:route myroute 51 | ``` 52 | 53 | Produces `app/scripts/controllers/myroute.js`: 54 | ```javascript 55 | angular.module('myMod').controller('MyrouteCtrl', function ($scope) { 56 | // ... 57 | }); 58 | ``` 59 | 60 | Produces `app/views/myroute.html`: 61 | ```html 62 |

This is the myroute view

63 | ``` 64 | 65 | ### Controller 66 | Generates a controller in `app/scripts/controllers`. 67 | 68 | Example: 69 | ```bash 70 | yo express-angular:controller user 71 | ``` 72 | 73 | Produces `app/scripts/controllers/user.js`: 74 | ```javascript 75 | angular.module('myMod').controller('UserCtrl', function ($scope) { 76 | // ... 77 | }); 78 | ``` 79 | ### Directive 80 | Generates a directive in `app/scripts/directives`. 81 | 82 | Example: 83 | ```bash 84 | yo express-angular:directive myDirective 85 | ``` 86 | 87 | Produces `app/scripts/directives/myDirective.js`: 88 | ```javascript 89 | angular.module('myMod').directive('myDirective', function () { 90 | return { 91 | template: '
', 92 | restrict: 'E', 93 | link: function postLink(scope, element, attrs) { 94 | element.text('this is the myDirective directive'); 95 | } 96 | }; 97 | }); 98 | ``` 99 | 100 | ### Filter 101 | Generates a filter in `app/scripts/filters`. 102 | 103 | Example: 104 | ```bash 105 | yo express-angular:filter myFilter 106 | ``` 107 | 108 | Produces `app/scripts/filters/myFilter.js`: 109 | ```javascript 110 | angular.module('myMod').filter('myFilter', function () { 111 | return function (input) { 112 | return 'myFilter filter:' + input; 113 | }; 114 | }); 115 | ``` 116 | 117 | ### View 118 | Generates an HTML view file in `app/views`. 119 | 120 | Example: 121 | ```bash 122 | yo express-angular:view user 123 | ``` 124 | 125 | Produces `app/views/user.html`: 126 | ```html 127 |

This is the user view

128 | ``` 129 | 130 | ### Service 131 | Generates an AngularJS service. 132 | 133 | Example: 134 | ```bash 135 | yo express-angular:service myService 136 | ``` 137 | 138 | Produces `app/scripts/services/myService.js`: 139 | ```javascript 140 | angular.module('myMod').factory('myService', function () { 141 | // ... 142 | }); 143 | ``` 144 | 145 | #### Options 146 | There are options for each of the methods for registering services. For more on using these services, see the [module API AngularJS documentation](http://docs.angularjs.org/api/angular.Module). 147 | 148 | ##### Factory 149 | Invoked with `--factory` 150 | 151 | This is the default method when creating a service. Running `yo express-angular:service myService --factory` is the same as running `yo express-angular:service myService` 152 | 153 | ##### Service 154 | Invoked with `--service` 155 | 156 | ##### Value 157 | Invoked with `--value` 158 | 159 | ##### Constant 160 | Invoked with `--constant` 161 | 162 | ## Options 163 | In general, these options can be applied to any generator, though they only affect generators that produce scripts. 164 | 165 | ### CoffeeScript 166 | For generators that output scripts, the `--coffee` option will output CoffeeScript instead of JavaScript. 167 | 168 | For example: 169 | ```bash 170 | yo express-angular:controller user --coffee 171 | ``` 172 | 173 | Produces `app/scripts/controller/user.coffee`: 174 | ```coffeescript 175 | angular.module('myMod') 176 | .controller 'UserCtrl', ($scope) -> 177 | ``` 178 | 179 | A project can mix CoffeScript and JavaScript files. 180 | 181 | ### Minification Safe 182 | By default, generators produce unannotated code. Without annotations, AngularJS's DI system will break when minified. Typically, these annotations the make minification safe are added automatically at build-time, after application files are concatenated, but before they are minified. By providing the `--minsafe` option, the code generated will out-of-the-box be ready for minification. The trade-off is between amount of boilerplate, and build process complexity. 183 | 184 | #### Example 185 | ```bash 186 | yo express-angular:controller user --minsafe 187 | ``` 188 | 189 | Produces `app/controller/user.js`: 190 | ```javascript 191 | angular.module('myMod').controller('UserCtrl', ['$scope', function ($scope) { 192 | // ... 193 | }]); 194 | ``` 195 | 196 | #### Background 197 | Unannotated: 198 | ```javascript 199 | angular.module('myMod').controller('MyCtrl', function ($scope, $http, myService) { 200 | // ... 201 | }); 202 | ``` 203 | 204 | Annotated: 205 | ```javascript 206 | angular.module('myMod').controller('MyCtrl', 207 | ['$scope', '$http', 'myService', function ($scope, $http, myService) { 208 | 209 | // ... 210 | }]); 211 | ``` 212 | 213 | 214 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | generator-express-angular 2 | ========================= 3 | 4 | yeoman angular generator with express 5 | 6 | ## Usage 7 | 8 | Install `generator-express-angular`: 9 | ``` 10 | npm install -g generator-express-angular 11 | ``` 12 | 13 | Make a new directory, and `cd` into it: 14 | ``` 15 | mkdir my-new-project && cd $_ 16 | ``` 17 | 18 | Run `yo express-angular`, optionally passing an app name: 19 | ``` 20 | yo express-angular [app-name] 21 | ``` 22 | 23 | ## Generators 24 | 25 | Available generators: 26 | 27 | * [express-angular](#app) (aka [express-angular:app](#app)) 28 | * [express-angular:controller](#controller) 29 | * [express-angular:directive](#directive) 30 | * [express-angular:filter](#filter) 31 | * [express-angular:route](#route) 32 | * [express-angular:service](#service) 33 | * [express-angular:view](#view) 34 | 35 | **Note: Generators are to be run from the root directory of your app.** 36 | 37 | ### App 38 | Sets up a new AngularJS app, generating all the boilerplate you need to get started. The app generator also optionally installs Twitter Bootstrap and additional AngularJS modules, such as angular-resource. 39 | 40 | Example: 41 | ```bash 42 | yo express-angular 43 | ``` 44 | 45 | ### Route 46 | Generates a controller and view, and configures a route in `app/scripts/app.js` connecting them. 47 | 48 | Example: 49 | ```bash 50 | yo express-angular:route myroute 51 | ``` 52 | 53 | Produces `app/scripts/controllers/myroute.js`: 54 | ```javascript 55 | angular.module('myMod').controller('MyrouteCtrl', function ($scope) { 56 | // ... 57 | }); 58 | ``` 59 | 60 | Produces `app/views/myroute.html`: 61 | ```html 62 |

This is the myroute view

63 | ``` 64 | 65 | ### Controller 66 | Generates a controller in `app/scripts/controllers`. 67 | 68 | Example: 69 | ```bash 70 | yo express-angular:controller user 71 | ``` 72 | 73 | Produces `app/scripts/controllers/user.js`: 74 | ```javascript 75 | angular.module('myMod').controller('UserCtrl', function ($scope) { 76 | // ... 77 | }); 78 | ``` 79 | ### Directive 80 | Generates a directive in `app/scripts/directives`. 81 | 82 | Example: 83 | ```bash 84 | yo express-angular:directive myDirective 85 | ``` 86 | 87 | Produces `app/scripts/directives/myDirective.js`: 88 | ```javascript 89 | angular.module('myMod').directive('myDirective', function () { 90 | return { 91 | template: '
', 92 | restrict: 'E', 93 | link: function postLink(scope, element, attrs) { 94 | element.text('this is the myDirective directive'); 95 | } 96 | }; 97 | }); 98 | ``` 99 | 100 | ### Filter 101 | Generates a filter in `app/scripts/filters`. 102 | 103 | Example: 104 | ```bash 105 | yo express-angular:filter myFilter 106 | ``` 107 | 108 | Produces `app/scripts/filters/myFilter.js`: 109 | ```javascript 110 | angular.module('myMod').filter('myFilter', function () { 111 | return function (input) { 112 | return 'myFilter filter:' + input; 113 | }; 114 | }); 115 | ``` 116 | 117 | ### View 118 | Generates an HTML view file in `app/views`. 119 | 120 | Example: 121 | ```bash 122 | yo express-angular:view user 123 | ``` 124 | 125 | Produces `app/views/user.html`: 126 | ```html 127 |

This is the user view

128 | ``` 129 | 130 | ### Service 131 | Generates an AngularJS service. 132 | 133 | Example: 134 | ```bash 135 | yo express-angular:service myService 136 | ``` 137 | 138 | Produces `app/scripts/services/myService.js`: 139 | ```javascript 140 | angular.module('myMod').factory('myService', function () { 141 | // ... 142 | }); 143 | ``` 144 | 145 | #### Options 146 | There are options for each of the methods for registering services. For more on using these services, see the [module API AngularJS documentation](http://docs.angularjs.org/api/angular.Module). 147 | 148 | ##### Factory 149 | Invoked with `--factory` 150 | 151 | This is the default method when creating a service. Running `yo express-angular:service myService --factory` is the same as running `yo express-angular:service myService` 152 | 153 | ##### Service 154 | Invoked with `--service` 155 | 156 | ##### Value 157 | Invoked with `--value` 158 | 159 | ##### Constant 160 | Invoked with `--constant` 161 | 162 | ## Options 163 | In general, these options can be applied to any generator, though they only affect generators that produce scripts. 164 | 165 | ### CoffeeScript 166 | For generators that output scripts, the `--coffee` option will output CoffeeScript instead of JavaScript. 167 | 168 | For example: 169 | ```bash 170 | yo express-angular:controller user --coffee 171 | ``` 172 | 173 | Produces `app/scripts/controller/user.coffee`: 174 | ```coffeescript 175 | angular.module('myMod') 176 | .controller 'UserCtrl', ($scope) -> 177 | ``` 178 | 179 | A project can mix CoffeScript and JavaScript files. 180 | 181 | ### Minification Safe 182 | By default, generators produce unannotated code. Without annotations, AngularJS's DI system will break when minified. Typically, these annotations the make minification safe are added automatically at build-time, after application files are concatenated, but before they are minified. By providing the `--minsafe` option, the code generated will out-of-the-box be ready for minification. The trade-off is between amount of boilerplate, and build process complexity. 183 | 184 | #### Example 185 | ```bash 186 | yo express-angular:controller user --minsafe 187 | ``` 188 | 189 | Produces `app/controller/user.js`: 190 | ```javascript 191 | angular.module('myMod').controller('UserCtrl', ['$scope', function ($scope) { 192 | // ... 193 | }]); 194 | ``` 195 | 196 | #### Background 197 | Unannotated: 198 | ```javascript 199 | angular.module('myMod').controller('MyCtrl', function ($scope, $http, myService) { 200 | // ... 201 | }); 202 | ``` 203 | 204 | Annotated: 205 | ```javascript 206 | angular.module('myMod').controller('MyCtrl', 207 | ['$scope', '$http', 'myService', function ($scope, $http, myService) { 208 | 209 | // ... 210 | }]); 211 | ``` 212 | 213 | 214 | 215 | 216 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Grievoushead/generator-express-angular/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 217 | 218 | -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a default AngularJS app 3 | 4 | Example: 5 | yo angular [--coffee] [--minsafe] 6 | 7 | This will create: 8 | Gruntfile.js 9 | bower.json 10 | 11 | app/index.html 12 | app/scripts/your-app-name-here.js 13 | app/scripts/controllers/main.js 14 | app/bower_components/angular/angular.js 15 | app/styles/main.css 16 | app/views/main.html 17 | 18 | test/lib/angular-mocks.js 19 | test/spec/controllers/main.js 20 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var spawn = require('child_process').spawn; 5 | var yeoman = require('yeoman-generator'); 6 | 7 | 8 | var Generator = module.exports = function Generator(args, options) { 9 | yeoman.generators.Base.apply(this, arguments); 10 | this.argument('appname', { type: String, required: false }); 11 | this.appname = this.appname || path.basename(process.cwd()); 12 | this.indexFile = this.engine(this.read('../../templates/common/index.html'), 13 | this); 14 | 15 | args = ['main']; 16 | 17 | if (typeof this.env.options.appPath === 'undefined') { 18 | try { 19 | this.env.options.appPath = require(path.join(process.cwd(), 'bower.json')).appPath; 20 | } catch (e) {} 21 | this.env.options.appPath = this.env.options.appPath || 'app'; 22 | } 23 | 24 | this.appPath = this.env.options.appPath; 25 | 26 | if (typeof this.env.options.coffee === 'undefined') { 27 | this.option('coffee'); 28 | 29 | // attempt to detect if user is using CS or not 30 | // if cml arg provided, use that; else look for the existence of cs 31 | if (!this.options.coffee && 32 | this.expandFiles(path.join(this.appPath, '/scripts/**/*.coffee'), {}).length > 0) { 33 | this.options.coffee = true; 34 | } 35 | 36 | this.env.options.coffee = this.options.coffee; 37 | } 38 | 39 | if (typeof this.env.options.minsafe === 'undefined') { 40 | this.option('minsafe'); 41 | this.env.options.minsafe = this.options.minsafe; 42 | args.push('--minsafe'); 43 | } 44 | 45 | this.hookFor('angular:common', { 46 | args: args 47 | }); 48 | 49 | this.hookFor('angular:main', { 50 | args: args 51 | }); 52 | 53 | this.hookFor('angular:controller', { 54 | args: args 55 | }); 56 | 57 | this.hookFor('karma', { 58 | as: 'app', 59 | options: { 60 | options: { 61 | coffee: this.options.coffee, 62 | travis: true, 63 | 'skip-install': this.options['skip-install'] 64 | } 65 | } 66 | }); 67 | 68 | this.on('end', function () { 69 | this.installDependencies({ skipInstall: this.options['skip-install'] }); 70 | }); 71 | 72 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 73 | }; 74 | 75 | util.inherits(Generator, yeoman.generators.Base); 76 | 77 | Generator.prototype.askForBootstrap = function askForBootstrap() { 78 | var cb = this.async(); 79 | 80 | this.prompt([{ 81 | type: 'confirm', 82 | name: 'bootstrap', 83 | message: 'Would you like to include Twitter Bootstrap?', 84 | default: true 85 | }, { 86 | type: 'confirm', 87 | name: 'compassBootstrap', 88 | message: 'Would you like to use Twitter Bootstrap for Compass (as opposed to vanilla CSS)?', 89 | default: true, 90 | when: function (props) { 91 | return props.bootstrap; 92 | } 93 | }], function (props) { 94 | this.bootstrap = props.bootstrap; 95 | this.compassBootstrap = props.compassBootstrap; 96 | 97 | cb(); 98 | }.bind(this)); 99 | }; 100 | 101 | Generator.prototype.askForModules = function askForModules() { 102 | var cb = this.async(); 103 | 104 | var prompts = [{ 105 | type: 'checkbox', 106 | name: 'modules', 107 | message: 'Which modules would you like to include?', 108 | choices: [{ 109 | value: 'resourceModule', 110 | name: 'angular-resource.js', 111 | checked: true 112 | }, { 113 | value: 'cookiesModule', 114 | name: 'angular-cookies.js', 115 | checked: true 116 | }, { 117 | value: 'sanitizeModule', 118 | name: 'angular-sanitize.js', 119 | checked: true 120 | }] 121 | }]; 122 | 123 | this.prompt(prompts, function (props) { 124 | var hasMod = function (mod) { return props.modules.indexOf(mod) !== -1; }; 125 | this.resourceModule = hasMod('resourceModule'); 126 | this.cookiesModule = hasMod('cookiesModule'); 127 | this.sanitizeModule = hasMod('sanitizeModule'); 128 | 129 | cb(); 130 | }.bind(this)); 131 | }; 132 | 133 | // Waiting a more flexible solution for #138 134 | Generator.prototype.bootstrapFiles = function bootstrapFiles() { 135 | var sass = this.compassBootstrap; 136 | var files = []; 137 | var source = 'styles/' + ( sass ? 'scss/' : 'css/' ); 138 | 139 | if (sass) { 140 | files.push('main.scss'); 141 | this.copy('images/glyphicons-halflings.png', 'app/images/glyphicons-halflings.png'); 142 | this.copy('images/glyphicons-halflings-white.png', 'app/images/glyphicons-halflings-white.png'); 143 | } else { 144 | if (this.bootstrap) { 145 | files.push('bootstrap.css'); 146 | } 147 | files.push('main.css'); 148 | } 149 | 150 | files.forEach(function (file) { 151 | this.copy(source + file, 'app/styles/' + file); 152 | }.bind(this)); 153 | 154 | this.indexFile = this.appendFiles({ 155 | html: this.indexFile, 156 | fileType: 'css', 157 | optimizedPath: 'styles/main.css', 158 | sourceFileList: files.map(function (file) { 159 | return 'styles/' + file.replace('.scss', '.css'); 160 | }), 161 | searchPath: ['.tmp', 'app'] 162 | }); 163 | }; 164 | 165 | Generator.prototype.bootstrapJs = function bootstrapJs() { 166 | if (!this.bootstrap) { 167 | return; // Skip if disabled. 168 | } 169 | 170 | // Wire Twitter Bootstrap plugins 171 | this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', [ 172 | 'bower_components/bootstrap-sass/js/bootstrap-affix.js', 173 | 'bower_components/bootstrap-sass/js/bootstrap-alert.js', 174 | 'bower_components/bootstrap-sass/js/bootstrap-dropdown.js', 175 | 'bower_components/bootstrap-sass/js/bootstrap-tooltip.js', 176 | 'bower_components/bootstrap-sass/js/bootstrap-modal.js', 177 | 'bower_components/bootstrap-sass/js/bootstrap-transition.js', 178 | 'bower_components/bootstrap-sass/js/bootstrap-button.js', 179 | 'bower_components/bootstrap-sass/js/bootstrap-popover.js', 180 | 'bower_components/bootstrap-sass/js/bootstrap-typeahead.js', 181 | 'bower_components/bootstrap-sass/js/bootstrap-carousel.js', 182 | 'bower_components/bootstrap-sass/js/bootstrap-scrollspy.js', 183 | 'bower_components/bootstrap-sass/js/bootstrap-collapse.js', 184 | 'bower_components/bootstrap-sass/js/bootstrap-tab.js' 185 | ]); 186 | }; 187 | 188 | Generator.prototype.extraModules = function extraModules() { 189 | var modules = []; 190 | if (this.resourceModule) { 191 | modules.push('bower_components/angular-resource/angular-resource.js'); 192 | } 193 | 194 | if (this.cookiesModule) { 195 | modules.push('bower_components/angular-cookies/angular-cookies.js'); 196 | } 197 | 198 | if (this.sanitizeModule) { 199 | modules.push('bower_components/angular-sanitize/angular-sanitize.js'); 200 | } 201 | 202 | if (modules.length) { 203 | this.indexFile = this.appendScripts(this.indexFile, 'scripts/modules.js', 204 | modules); 205 | } 206 | }; 207 | 208 | Generator.prototype.appJs = function appJs() { 209 | this.indexFile = this.appendFiles({ 210 | html: this.indexFile, 211 | fileType: 'js', 212 | optimizedPath: 'scripts/scripts.js', 213 | sourceFileList: ['scripts/app.js', 'scripts/controllers/main.js'], 214 | searchPath: ['.tmp', 'app'] 215 | }); 216 | }; 217 | 218 | Generator.prototype.createIndexHtml = function createIndexHtml() { 219 | this.write(path.join(this.appPath, 'index.html'), this.indexFile); 220 | }; 221 | 222 | Generator.prototype.packageFiles = function () { 223 | this.template('../../templates/common/_bower.json', 'bower.json'); 224 | this.template('../../templates/common/_package.json', 'package.json'); 225 | this.template('../../templates/common/Gruntfile.js', 'Gruntfile.js'); 226 | }; 227 | 228 | Generator.prototype.express = function express() { 229 | this.copy('../../templates/common/Procfile', 'Procfile'); 230 | this.copy('../../templates/common/app.js', 'app.js'); 231 | }; 232 | -------------------------------------------------------------------------------- /app/templates/images/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerhiiKozachenko/generator-express-angular/a69786c67b2f83fecabd983e95903aa642de9bcf/app/templates/images/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /app/templates/images/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerhiiKozachenko/generator-express-angular/a69786c67b2f83fecabd983e95903aa642de9bcf/app/templates/images/glyphicons-halflings.png -------------------------------------------------------------------------------- /app/templates/styles/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fafafa; 3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | color: #333; 5 | } 6 | 7 | .hero-unit { 8 | margin: 50px auto 0 auto; 9 | width: 300px; 10 | font-size: 18px; 11 | font-weight: 200; 12 | line-height: 30px; 13 | background-color: #eee; 14 | border-radius: 6px; 15 | padding: 60px; 16 | } 17 | 18 | .hero-unit h1 { 19 | font-size: 60px; 20 | line-height: 1; 21 | letter-spacing: -1px; 22 | } 23 | -------------------------------------------------------------------------------- /app/templates/styles/scss/main.scss: -------------------------------------------------------------------------------- 1 | $iconSpritePath: "../images/glyphicons-halflings.png"; 2 | $iconWhiteSpritePath: "../images/glyphicons-halflings-white.png"; 3 | 4 | @import "bootstrap-sass/lib/bootstrap"; 5 | 6 | /* Put your CSS here */ 7 | html, body { 8 | margin: 20px; 9 | } 10 | 11 | body { 12 | background: #fafafa; 13 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 14 | color: #333; 15 | } 16 | 17 | .hero-unit { 18 | margin: 50px auto 0 auto; 19 | width: 300px; 20 | font-size: 18px; 21 | font-weight: 200; 22 | line-height: 30px; 23 | background-color: #eee; 24 | border-radius: 6px; 25 | padding: 60px; 26 | } 27 | 28 | .hero-unit h1 { 29 | font-size: 60px; 30 | line-height: 1; 31 | letter-spacing: -1px; 32 | } 33 | -------------------------------------------------------------------------------- /common/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | 7 | module.exports = Generator; 8 | 9 | function Generator() { 10 | yeoman.generators.Base.apply(this, arguments); 11 | } 12 | 13 | util.inherits(Generator, yeoman.generators.Base); 14 | 15 | Generator.prototype.setupEnv = function setupEnv() { 16 | // Copies the contents of the generator `templates` 17 | // directory into your users new application path 18 | this.sourceRoot(path.join(__dirname, '../templates/common')); 19 | this.directory('root', '.', true); 20 | this.copy('gitignore', '.gitignore'); 21 | }; 22 | -------------------------------------------------------------------------------- /constant/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS constant. 3 | Docs: http://docs.angularjs.org/guide/dev_guide.services.creating_services 4 | 5 | Example: 6 | yo angular:constant thing [--coffee] [--minsafe] 7 | 8 | This will create: 9 | app/scripts/services/thing.js 10 | -------------------------------------------------------------------------------- /constant/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | 6 | 7 | module.exports = Generator; 8 | 9 | function Generator() { 10 | ScriptBase.apply(this, arguments); 11 | } 12 | 13 | util.inherits(Generator, ScriptBase); 14 | 15 | Generator.prototype.createServiceFiles = function createServiceFiles() { 16 | this.appTemplate('service/constant'); 17 | this.testTemplate('spec/service'); 18 | }; 19 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 2 | -------------------------------------------------------------------------------- /controller/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new Angular controller 3 | 4 | Example: 5 | yo angular:controller Thing [--coffee] [--minsafe] 6 | 7 | This will create: 8 | app/scripts/controllers/thing-ctrl.js 9 | -------------------------------------------------------------------------------- /controller/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | 6 | 7 | module.exports = Generator; 8 | 9 | function Generator() { 10 | ScriptBase.apply(this, arguments); 11 | 12 | // if the controller name is suffixed with ctrl, remove the suffix 13 | // if the controller name is just "ctrl," don't append/remove "ctrl" 14 | if (this.name && this.name.toLowerCase() !== 'ctrl' && this.name.substr(-4).toLowerCase() === 'ctrl') { 15 | this.name = this.name.slice(0, -4); 16 | } 17 | } 18 | 19 | util.inherits(Generator, ScriptBase); 20 | 21 | Generator.prototype.createControllerFiles = function createControllerFiles() { 22 | this.appTemplate('controller'); 23 | this.testTemplate('spec/controller'); 24 | }; 25 | -------------------------------------------------------------------------------- /decorator/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS decorator for a specified service 3 | 4 | Example: 5 | yo angular:decorator serviceName [--coffee] 6 | 7 | This will create: 8 | app/scripts/decorators/serviceNameDecorator.js 9 | -------------------------------------------------------------------------------- /decorator/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var ScriptBase = require('../script-base.js'); 4 | var fs = require('fs'); 5 | 6 | var Generator = module.exports = function Generator(args, options) { 7 | ScriptBase.apply(this, arguments); 8 | this.fileName = this.name; 9 | }; 10 | 11 | util.inherits(Generator, ScriptBase); 12 | 13 | Generator.prototype.askForOverwrite = function askForOverwrite() { 14 | var cb = this.async(); 15 | 16 | // TODO: Any yeoman.util function to handle this? 17 | var fileExists = fs.existsSync(this.env.cwd + '/app/scripts/' + buildRelativePath(this.fileName) + '.js'); 18 | if (fileExists) { 19 | var prompts = [{ 20 | type: 'confirm', 21 | name: 'overwriteDecorator', 22 | message: 'Would you like to overwrite existing decorator?', 23 | default: false 24 | }]; 25 | 26 | this.prompt(prompts, function (props) { 27 | this.overwriteDecorator = props.overwriteDecorator; 28 | 29 | cb(); 30 | }.bind(this)); 31 | } else { 32 | cb(); 33 | } 34 | }; 35 | 36 | Generator.prototype.askForNewName = function askForNewName() { 37 | var cb = this.async(); 38 | 39 | if (this.overwriteDecorator === undefined || this.overwriteDecorator === true) { 40 | cb(); 41 | return; 42 | } 43 | 44 | var prompts = []; 45 | prompts.push({ 46 | name: 'decoratorName', 47 | message: 'Alternative name for the decorator' 48 | }); 49 | 50 | this.prompt(prompts, function (props) { 51 | this.fileName = props.decoratorName; 52 | 53 | cb(); 54 | }.bind(this)); 55 | }; 56 | 57 | Generator.prototype.createDecoratorFiles = function createDecoratorFiles() { 58 | this.appTemplate('decorator', 'scripts/' + buildRelativePath(this.fileName)); 59 | this.addScriptToIndex(buildRelativePath(this.fileName)); 60 | }; 61 | 62 | function buildRelativePath(fileName){ 63 | return 'decorators/' + fileName + 'Decorator'; 64 | } 65 | -------------------------------------------------------------------------------- /directive/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new Angular directive 3 | 4 | Example: 5 | yo angular:directive thing [--coffee] [--minsafe] 6 | 7 | This will create: 8 | app/scripts/directives/thing.js 9 | -------------------------------------------------------------------------------- /directive/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createDirectiveFiles = function createDirectiveFiles() { 17 | this.appTemplate('directive'); 18 | this.testTemplate('spec/directive'); 19 | }; 20 | -------------------------------------------------------------------------------- /factory/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS service. 3 | Docs: http://docs.angularjs.org/guide/dev_guide.services.creating_services 4 | 5 | Example: 6 | yo angular:factory thing [--coffee] [--minsafe] 7 | 8 | This will create: 9 | app/scripts/services/thing.js 10 | -------------------------------------------------------------------------------- /factory/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createServiceFiles = function createServiceFiles() { 17 | this.appTemplate('service/factory'); 18 | this.testTemplate('spec/service'); 19 | }; 20 | -------------------------------------------------------------------------------- /filter/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS filter 3 | 4 | Example: 5 | yo angular:filter thing [--coffee] [--minsafe] 6 | 7 | This will create: 8 | app/scripts/filters/thing.js 9 | -------------------------------------------------------------------------------- /filter/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createFilterFiles = function createFilterFiles() { 17 | this.appTemplate('filter', 'scripts/filters/' + this.name); 18 | this.testTemplate('spec/filter', 'filters/' + this.name); 19 | this.addScriptToIndex('filters/' + this.name); 20 | }; 21 | -------------------------------------------------------------------------------- /main/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var ScriptBase = require('../script-base.js'); 5 | var yeoman = require('yeoman-generator'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createAppFile = function createAppFile() { 17 | this.appTemplate('app', 'scripts/app'); 18 | }; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-express-angular", 3 | "version": "0.2.8", 4 | "description": "Yeoman generator for AngularJS + Express", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "scaffold", 8 | "framework", 9 | "component", 10 | "front-end", 11 | "app" 12 | ], 13 | "homepage": "https://github.com/Grievoushead/generator-express-angular", 14 | "bugs": "https://github.com/Grievoushead/generator-express-angular/issues", 15 | "author": "Grievoushead", 16 | "main": "app/index.js", 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/Grievoushead/generator-express-angular.git" 20 | }, 21 | "scripts": { 22 | "test": "mocha" 23 | }, 24 | "dependencies": { 25 | "yeoman-generator": "~0.13.4", 26 | "generator-angular": "~0.4.0" 27 | }, 28 | "peerDependencies": { 29 | "generator-karma": "~0.5.0", 30 | "yo": ">=1.0.0-rc.1.1" 31 | }, 32 | "devDependencies": { 33 | "mocha": "~1.12.0", 34 | "grunt": "~0.4.1", 35 | "grunt-contrib-jshint": "~0.6.0", 36 | "grunt-conventional-changelog": "~1.0.0", 37 | "marked": "~0.2.8", 38 | "semver": "~2.0.0", 39 | "grunt-release": "~0.3.3" 40 | }, 41 | "engines": { 42 | "node": ">=0.8.0", 43 | "npm": ">=1.2.10" 44 | }, 45 | "licenses": [ 46 | { 47 | "type": "BSD" 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /provider/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS service. 3 | Docs: http://docs.angularjs.org/guide/dev_guide.services.creating_services 4 | 5 | Example: 6 | yo angular:provider thing [--coffee] [--minsafe] 7 | 8 | This will create: 9 | app/scripts/services/thing.js 10 | -------------------------------------------------------------------------------- /provider/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createServiceFiles = function createServiceFiles() { 17 | this.appTemplate('service/provider'); 18 | this.testTemplate('spec/service'); 19 | }; 20 | -------------------------------------------------------------------------------- /route/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS route 3 | 4 | Example: 5 | yo angular:route thing [--coffee] [--minsafe] 6 | 7 | This will create: 8 | app/scripts/controllers/thing.js 9 | app/views/thing.html 10 | And add routing to: 11 | app.js 12 | -------------------------------------------------------------------------------- /route/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | this.hookFor('angular:controller'); 13 | this.hookFor('angular:view'); 14 | } 15 | util.inherits(Generator, ScriptBase); 16 | 17 | Generator.prototype.rewriteAppJs = function () { 18 | var htmlTemplatePath = this.name + '.html', 19 | splicable, 20 | filePath = path.join(this.env.options.appPath, 'scripts/app.'); 21 | 22 | if (htmlTemplatePath.indexOf('/') === -1) { 23 | htmlTemplatePath = 'views/' + htmlTemplatePath; 24 | } 25 | 26 | if (this.env.options.coffee) { 27 | splicable = [ 28 | '.when \'/' + this.name + '\',', 29 | ' templateUrl: \'' + htmlTemplatePath + '\',', 30 | ' controller: \'' + this._.classify(this.name) + 'Ctrl\'' 31 | ]; 32 | filePath += 'coffee'; 33 | } else { 34 | splicable = [ 35 | '.when(\'/' + this.name + '\', {', 36 | ' templateUrl: \'' + htmlTemplatePath + '\',', 37 | ' controller: \'' + this._.classify(this.name) + 'Ctrl\'', 38 | '})' 39 | ]; 40 | filePath += 'js'; 41 | } 42 | 43 | angularUtils.rewriteFile({ 44 | file: filePath, 45 | needle: '.otherwise', 46 | splicable: splicable 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /script-base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var yeoman = require('yeoman-generator'); 5 | var angularUtils = require('./util.js'); 6 | 7 | module.exports = Generator; 8 | 9 | function Generator() { 10 | yeoman.generators.NamedBase.apply(this, arguments); 11 | 12 | try { 13 | this.appname = require(path.join(process.cwd(), 'bower.json')).name; 14 | } catch (e) { 15 | this.appname = path.basename(process.cwd()); 16 | } 17 | 18 | if (typeof this.env.options.appPath === 'undefined') { 19 | try { 20 | this.env.options.appPath = require(path.join(process.cwd(), 'bower.json')).appPath; 21 | } catch (e) {} 22 | this.env.options.appPath = this.env.options.appPath || 'app'; 23 | } 24 | 25 | if (typeof this.env.options.testPath === 'undefined') { 26 | try { 27 | this.env.options.testPath = require(path.join(process.cwd(), 'bower.json')).testPath; 28 | } catch (e) {} 29 | this.env.options.testPath = this.env.options.testPath || 'test/spec'; 30 | } 31 | 32 | if (typeof this.env.options.coffee === 'undefined') { 33 | this.option('coffee'); 34 | 35 | // attempt to detect if user is using CS or not 36 | // if cml arg provided, use that; else look for the existence of cs 37 | if (!this.options.coffee && 38 | this.expandFiles(path.join(this.env.options.appPath, '/scripts/**/*.coffee'), {}).length > 0) { 39 | this.options.coffee = true; 40 | } 41 | 42 | this.env.options.coffee = this.options.coffee; 43 | } 44 | 45 | if (typeof this.env.options.minsafe === 'undefined') { 46 | this.option('minsafe'); 47 | this.env.options.minsafe = this.options.minsafe; 48 | } 49 | 50 | var sourceRoot = '/templates/javascript'; 51 | this.scriptSuffix = '.js'; 52 | 53 | if (this.env.options.coffee) { 54 | sourceRoot = '/templates/coffeescript'; 55 | this.scriptSuffix = '.coffee'; 56 | } 57 | 58 | if (this.env.options.minsafe) { 59 | sourceRoot += '-min'; 60 | } 61 | 62 | this.sourceRoot(path.join(__dirname, sourceRoot)); 63 | 64 | this.moduleName = this._.camelize(this.appname) + 'App'; 65 | 66 | this.namespace = []; 67 | if (this.name.indexOf('/') !== -1) { 68 | this.namespace = this.name.split('/'); 69 | this.name = this.namespace.pop(); 70 | 71 | this.moduleName += '.' + this.namespace.join('.'); // add to parent ? 72 | } 73 | 74 | } 75 | 76 | util.inherits(Generator, yeoman.generators.NamedBase); 77 | 78 | Generator.prototype._dest = function (src) { 79 | if (src.indexOf('spec/') === 0) { 80 | src = src.substr(5); 81 | } else if (src.indexOf('service/') === 0) { 82 | src = src.substr(8); 83 | } 84 | return path.join((this.namespace.join('/') || src), this.name); 85 | }; 86 | 87 | Generator.prototype.appTemplate = function (src) { 88 | yeoman.generators.Base.prototype.template.apply(this, [ 89 | src + this.scriptSuffix, 90 | path.join(this.env.options.appPath, this._dest(src)) + this.scriptSuffix 91 | ]); 92 | this.addScriptToIndex(src); 93 | }; 94 | 95 | Generator.prototype.testTemplate = function (src) { 96 | yeoman.generators.Base.prototype.template.apply(this, [ 97 | src + this.scriptSuffix, 98 | path.join(this.env.options.testPath, this._dest(src)) + this.scriptSuffix 99 | ]); 100 | }; 101 | 102 | Generator.prototype.htmlTemplate = function (src) { 103 | yeoman.generators.Base.prototype.template.apply(this, [ 104 | src, 105 | path.join(this.env.options.appPath, this._dest(src)) 106 | ]); 107 | }; 108 | 109 | Generator.prototype.addScriptToIndex = function (src) { 110 | try { 111 | var appPath = this.env.options.appPath; 112 | var fullPath = path.join(appPath, 'index.html'); 113 | angularUtils.rewriteFile({ 114 | file: fullPath, 115 | needle: '', 116 | splicable: [ 117 | '' 118 | ] 119 | }); 120 | } catch (e) { 121 | console.log('\nUnable to find '.yellow + fullPath + '. Reference to '.yellow + this._dest(src) + '.js ' + 'not added.\n'.yellow); 122 | } 123 | }; 124 | -------------------------------------------------------------------------------- /service/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS service. 3 | Docs: http://docs.angularjs.org/guide/dev_guide.services.creating_services 4 | 5 | Example: 6 | yo angular:service thing [--coffee] [--minsafe] 7 | 8 | This will create: 9 | app/scripts/services/thing.js 10 | -------------------------------------------------------------------------------- /service/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createServiceFiles = function createServiceFiles() { 17 | this.appTemplate('service/service'); 18 | this.testTemplate('spec/service'); 19 | }; 20 | -------------------------------------------------------------------------------- /templates/coffeescript-min/app.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>', []) 4 | .config ['$routeProvider', ($routeProvider) -> 5 | $routeProvider 6 | .when '/', 7 | templateUrl: 'views/main.html' 8 | controller: 'MainCtrl' 9 | .otherwise 10 | redirectTo: '/' 11 | ] 12 | -------------------------------------------------------------------------------- /templates/coffeescript-min/controller.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>') 4 | .controller '<%= _.classify(name) %>Ctrl', ['$scope', ($scope) -> 5 | $scope.awesomeThings = [ 6 | 'HTML5 Boilerplate' 7 | 'AngularJS' 8 | 'Karma' 9 | ] 10 | ] 11 | -------------------------------------------------------------------------------- /templates/coffeescript-min/decorator.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>').config ['$provide', ($provide) -> 4 | $provide.decorator '<%= _.camelize(name) %>', ($delegate) -> 5 | # decorate the $delegate 6 | $delegate 7 | ] 8 | -------------------------------------------------------------------------------- /templates/coffeescript-min/directive.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .directive '<%= _.camelize(name) %>', [-> 5 | template: '
' 6 | restrict: 'E' 7 | link: (scope, element, attrs) -> 8 | element.text 'this is the <%= _.camelize(name) %> directive' 9 | ] 10 | -------------------------------------------------------------------------------- /templates/coffeescript-min/filter.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .filter '<%= _.camelize(name) %>', [() -> 5 | (input) -> 6 | '<%= _.camelize(name) %> filter: ' + input 7 | ] 8 | -------------------------------------------------------------------------------- /templates/coffeescript-min/service/constant.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>') 4 | .constant '<%= _.camelize(name) %>', 42 5 | -------------------------------------------------------------------------------- /templates/coffeescript-min/service/factory.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .factory '<%= _.camelize(name) %>', [() -> 5 | # Service logic 6 | # ... 7 | 8 | meaningOfLife = 42 9 | 10 | # Public API here 11 | { 12 | someMethod: () -> 13 | meaningOfLife; 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /templates/coffeescript-min/service/provider.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>') 4 | .provider '<%= _.camelize(name) %>', [() -> 5 | 6 | # Private variables 7 | salutation = 'Hello' 8 | 9 | # Private constructor 10 | Greeter () -> 11 | this.greet = () { 12 | salutation 13 | 14 | # Public API for configuration 15 | this.setSalutation = (s) -> 16 | salutation = s 17 | 18 | # Method for instantiating 19 | this.$get = () -> 20 | new Greeter() 21 | ] 22 | -------------------------------------------------------------------------------- /templates/coffeescript-min/service/service.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .service '<%= _.classify(name) %>', () -> 5 | # AngularJS will instantiate a singleton by calling "new" on this function 6 | -------------------------------------------------------------------------------- /templates/coffeescript-min/service/value.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .value '<%= _.camelize(name) %>', 42 5 | -------------------------------------------------------------------------------- /templates/coffeescript-min/spec/controller.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Controller: <%= _.classify(name) %>Ctrl', () -> 4 | 5 | # load the controller's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | <%= _.classify(name) %>Ctrl = {} 9 | scope = {} 10 | 11 | # Initialize the controller and a mock scope 12 | beforeEach inject ($controller, $rootScope) -> 13 | scope = $rootScope.$new() 14 | <%= _.classify(name) %>Ctrl = $controller '<%= _.classify(name) %>Ctrl', { 15 | $scope: scope 16 | } 17 | 18 | it 'should attach a list of awesomeThings to the scope', () -> 19 | expect(scope.awesomeThings.length).toBe 3 20 | -------------------------------------------------------------------------------- /templates/coffeescript-min/spec/directive.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Directive: <%= _.camelize(name) %>', () -> 4 | 5 | # load the directive's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | scope = {} 9 | 10 | beforeEach inject ($controller, $rootScope) -> 11 | scope = $rootScope.$new() 12 | 13 | it 'should make hidden element visible', inject ($compile) -> 14 | element = angular.element '<<%= _.dasherize(name) %>>>' 15 | element = $compile(element) scope 16 | expect(element.text()).toBe 'this is the <%= _.camelize(name) %> directive' 17 | -------------------------------------------------------------------------------- /templates/coffeescript-min/spec/filter.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Filter: <%= _.camelize(name) %>', () -> 4 | 5 | # load the filter's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | # initialize a new instance of the filter before each test 9 | <%= _.camelize(name) %> = {} 10 | beforeEach inject ($filter) -> 11 | <%= _.camelize(name) %> = $filter '<%= _.camelize(name) %>' 12 | 13 | it 'should return the input prefixed with "<%= _.camelize(name) %> filter:"', () -> 14 | text = 'angularjs' 15 | expect(<%= _.camelize(name) %> text).toBe ('<%= _.camelize(name) %> filter: ' + text) 16 | -------------------------------------------------------------------------------- /templates/coffeescript-min/spec/service.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Service: <%= _.camelize(name) %>', () -> 4 | 5 | # load the service's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | # instantiate service 9 | <%= _.camelize(name) %> = {} 10 | beforeEach inject (_<%= _.camelize(name) %>_) -> 11 | <%= _.camelize(name) %> = _<%= _.camelize(name) %>_ 12 | 13 | it 'should do something', () -> 14 | expect(!!<%= _.camelize(name) %>).toBe true 15 | -------------------------------------------------------------------------------- /templates/coffeescript/app.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>', []) 4 | .config ($routeProvider) -> 5 | $routeProvider 6 | .when '/', 7 | templateUrl: 'views/main.html' 8 | controller: 'MainCtrl' 9 | .otherwise 10 | redirectTo: '/' 11 | -------------------------------------------------------------------------------- /templates/coffeescript/controller.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= moduleName %>') 4 | .controller '<%= _.classify(name) %>Ctrl', ($scope) -> 5 | $scope.awesomeThings = [ 6 | 'HTML5 Boilerplate' 7 | 'AngularJS' 8 | 'Karma' 9 | ] 10 | -------------------------------------------------------------------------------- /templates/coffeescript/decorator.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>').config ($provide) -> 4 | $provide.decorator '<%= _.camelize(name) %>', ($delegate) -> 5 | # decorate the $delegate 6 | $delegate 7 | -------------------------------------------------------------------------------- /templates/coffeescript/directive.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .directive('<%= _.camelize(name) %>', () -> 5 | template: '
' 6 | restrict: 'E' 7 | link: (scope, element, attrs) -> 8 | element.text 'this is the <%= _.camelize(name) %> directive' 9 | ) 10 | -------------------------------------------------------------------------------- /templates/coffeescript/filter.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .filter '<%= _.camelize(name) %>', () -> 5 | (input) -> 6 | '<%= _.camelize(name) %> filter: ' + input 7 | -------------------------------------------------------------------------------- /templates/coffeescript/service/constant.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= _.camelize(appname) %>App') 4 | .constant '<%= _.camelize(name) %>', 42 5 | -------------------------------------------------------------------------------- /templates/coffeescript/service/factory.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .factory '<%= _.camelize(name) %>', () -> 5 | # Service logic 6 | # ... 7 | 8 | meaningOfLife = 42 9 | 10 | # Public API here 11 | { 12 | someMethod: () -> 13 | meaningOfLife; 14 | } 15 | -------------------------------------------------------------------------------- /templates/coffeescript/service/provider.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module('<%= _.camelize(appname) %>App') 4 | .provider '<%= _.camelize(name) %>', () -> 5 | 6 | # Private variables 7 | salutation = 'Hello' 8 | 9 | # Private constructor 10 | Greeter () -> 11 | this.greet = () { 12 | salutation 13 | 14 | # Public API for configuration 15 | this.setSalutation = (s) -> 16 | salutation = s 17 | 18 | # Method for instantiating 19 | this.$get = () -> 20 | new Greeter() 21 | -------------------------------------------------------------------------------- /templates/coffeescript/service/service.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= _.camelize(appname) %>App') 4 | .service '<%= _.classify(name) %>', () -> 5 | # AngularJS will instantiate a singleton by calling "new" on this function 6 | -------------------------------------------------------------------------------- /templates/coffeescript/service/value.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= _.camelize(appname) %>App') 4 | .value '<%= _.camelize(name) %>', 42 5 | -------------------------------------------------------------------------------- /templates/coffeescript/spec/controller.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Controller: <%= _.classify(name) %>Ctrl', () -> 4 | 5 | # load the controller's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | <%= _.classify(name) %>Ctrl = {} 9 | scope = {} 10 | 11 | # Initialize the controller and a mock scope 12 | beforeEach inject ($controller, $rootScope) -> 13 | scope = $rootScope.$new() 14 | <%= _.classify(name) %>Ctrl = $controller '<%= _.classify(name) %>Ctrl', { 15 | $scope: scope 16 | } 17 | 18 | it 'should attach a list of awesomeThings to the scope', () -> 19 | expect(scope.awesomeThings.length).toBe 3 20 | -------------------------------------------------------------------------------- /templates/coffeescript/spec/directive.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Directive: <%= _.camelize(name) %>', () -> 4 | 5 | # load the directive's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | scope = {} 9 | 10 | beforeEach inject ($controller, $rootScope) -> 11 | scope = $rootScope.$new() 12 | 13 | it 'should make hidden element visible', inject ($compile) -> 14 | element = angular.element '<<%= _.dasherize(name) %>>>' 15 | element = $compile(element) scope 16 | expect(element.text()).toBe 'this is the <%= _.camelize(name) %> directive' 17 | -------------------------------------------------------------------------------- /templates/coffeescript/spec/filter.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Filter: <%= _.camelize(name) %>', () -> 4 | 5 | # load the filter's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | # initialize a new instance of the filter before each test 9 | <%= _.camelize(name) %> = {} 10 | beforeEach inject ($filter) -> 11 | <%= _.camelize(name) %> = $filter '<%= _.camelize(name) %>' 12 | 13 | it 'should return the input prefixed with "<%= _.camelize(name) %> filter:"', () -> 14 | text = 'angularjs' 15 | expect(<%= _.camelize(name) %> text).toBe ('<%= _.camelize(name) %> filter: ' + text) 16 | -------------------------------------------------------------------------------- /templates/coffeescript/spec/service.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Service: <%= _.camelize(name) %>', () -> 4 | 5 | # load the service's module 6 | beforeEach module '<%= moduleName %>' 7 | 8 | # instantiate service 9 | <%= _.camelize(name) %> = {} 10 | beforeEach inject (_<%= _.camelize(name) %>_) -> 11 | <%= _.camelize(name) %> = _<%= _.camelize(name) %>_ 12 | 13 | it 'should do something', () -> 14 | expect(!!<%= _.camelize(name) %>).toBe true 15 | -------------------------------------------------------------------------------- /templates/common/Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 2 | 'use strict'; 3 | var LIVERELOAD_PORT = 35729; 4 | var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); 5 | var mountFolder = function (connect, dir) { 6 | return connect.static(require('path').resolve(dir)); 7 | }; 8 | 9 | // # Globbing 10 | // for performance reasons we're only matching one level down: 11 | // 'test/spec/{,*/}*.js' 12 | // use this if you want to recursively match all subfolders: 13 | // 'test/spec/**/*.js' 14 | 15 | module.exports = function (grunt) { 16 | // load all grunt tasks 17 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); 18 | 19 | // configurable paths 20 | var yeomanConfig = { 21 | app: 'app', 22 | dist: 'dist' 23 | }; 24 | 25 | try { 26 | yeomanConfig.app = require('./bower.json').appPath || yeomanConfig.app; 27 | } catch (e) {} 28 | 29 | grunt.initConfig({ 30 | yeoman: yeomanConfig, 31 | watch: { 32 | coffee: { 33 | files: ['<%%= yeoman.app %>/scripts/{,*/}*.coffee'], 34 | tasks: ['coffee:dist'] 35 | }, 36 | coffeeTest: { 37 | files: ['test/spec/{,*/}*.coffee'], 38 | tasks: ['coffee:test'] 39 | },<% if (compassBootstrap) { %> 40 | compass: { 41 | files: ['<%%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], 42 | tasks: ['compass:server'] 43 | },<% } %> 44 | livereload: { 45 | options: { 46 | livereload: LIVERELOAD_PORT 47 | }, 48 | files: [ 49 | '<%%= yeoman.app %>/{,*/}*.html', 50 | '{.tmp,<%%= yeoman.app %>}/styles/{,*/}*.css', 51 | '{.tmp,<%%= yeoman.app %>}/scripts/{,*/}*.js', 52 | '<%%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 53 | ] 54 | } 55 | }, 56 | connect: { 57 | options: { 58 | port: 9000, 59 | // Change this to '0.0.0.0' to access the server from outside. 60 | hostname: 'localhost' 61 | }, 62 | livereload: { 63 | options: { 64 | middleware: function (connect) { 65 | return [ 66 | lrSnippet, 67 | mountFolder(connect, '.tmp'), 68 | mountFolder(connect, yeomanConfig.app) 69 | ]; 70 | } 71 | } 72 | }, 73 | test: { 74 | options: { 75 | middleware: function (connect) { 76 | return [ 77 | mountFolder(connect, '.tmp'), 78 | mountFolder(connect, 'test') 79 | ]; 80 | } 81 | } 82 | }, 83 | dist: { 84 | options: { 85 | middleware: function (connect) { 86 | return [ 87 | mountFolder(connect, yeomanConfig.dist) 88 | ]; 89 | } 90 | } 91 | } 92 | }, 93 | open: { 94 | server: { 95 | url: 'http://localhost:<%%= connect.options.port %>' 96 | } 97 | }, 98 | clean: { 99 | dist: { 100 | files: [{ 101 | dot: true, 102 | src: [ 103 | '.tmp', 104 | '<%%= yeoman.dist %>/*', 105 | '!<%%= yeoman.dist %>/.git*' 106 | ] 107 | }] 108 | }, 109 | server: '.tmp' 110 | }, 111 | jshint: { 112 | options: { 113 | jshintrc: '.jshintrc' 114 | }, 115 | all: [ 116 | 'Gruntfile.js', 117 | '<%%= yeoman.app %>/scripts/{,*/}*.js' 118 | ] 119 | }, 120 | coffee: { 121 | dist: { 122 | files: [{ 123 | expand: true, 124 | cwd: '<%%= yeoman.app %>/scripts', 125 | src: '{,*/}*.coffee', 126 | dest: '.tmp/scripts', 127 | ext: '.js' 128 | }] 129 | }, 130 | test: { 131 | files: [{ 132 | expand: true, 133 | cwd: 'test/spec', 134 | src: '{,*/}*.coffee', 135 | dest: '.tmp/spec', 136 | ext: '.js' 137 | }] 138 | } 139 | },<% if (compassBootstrap) { %> 140 | compass: { 141 | options: { 142 | sassDir: '<%%= yeoman.app %>/styles', 143 | cssDir: '.tmp/styles', 144 | generatedImagesDir: '.tmp/images/generated', 145 | imagesDir: '<%%= yeoman.app %>/images', 146 | javascriptsDir: '<%%= yeoman.app %>/scripts', 147 | fontsDir: '<%%= yeoman.app %>/styles/fonts', 148 | importPath: '<%%= yeoman.app %>/bower_components', 149 | httpImagesPath: '/images', 150 | httpGeneratedImagesPath: '/images/generated', 151 | httpFontsPath: '/styles/fonts', 152 | relativeAssets: false 153 | }, 154 | dist: {}, 155 | server: { 156 | options: { 157 | debugInfo: true 158 | } 159 | } 160 | },<% } %> 161 | // not used since Uglify task does concat, 162 | // but still available if needed 163 | /*concat: { 164 | dist: {} 165 | },*/ 166 | rev: { 167 | dist: { 168 | files: { 169 | src: [ 170 | '<%%= yeoman.dist %>/scripts/{,*/}*.js', 171 | '<%%= yeoman.dist %>/styles/{,*/}*.css', 172 | '<%%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 173 | '<%%= yeoman.dist %>/styles/fonts/*' 174 | ] 175 | } 176 | } 177 | }, 178 | useminPrepare: { 179 | html: '<%%= yeoman.app %>/index.html', 180 | options: { 181 | dest: '<%%= yeoman.dist %>' 182 | } 183 | }, 184 | usemin: { 185 | html: ['<%%= yeoman.dist %>/{,*/}*.html'], 186 | css: ['<%%= yeoman.dist %>/styles/{,*/}*.css'], 187 | options: { 188 | dirs: ['<%%= yeoman.dist %>'] 189 | } 190 | }, 191 | imagemin: { 192 | dist: { 193 | files: [{ 194 | expand: true, 195 | cwd: '<%%= yeoman.app %>/images', 196 | src: '{,*/}*.{png,jpg,jpeg}', 197 | dest: '<%%= yeoman.dist %>/images' 198 | }] 199 | } 200 | }, 201 | svgmin: { 202 | dist: { 203 | files: [{ 204 | expand: true, 205 | cwd: '<%%= yeoman.app %>/images', 206 | src: '{,*/}*.svg', 207 | dest: '<%%= yeoman.dist %>/images' 208 | }] 209 | } 210 | }, 211 | cssmin: { 212 | // By default, your `index.html` will take care of 213 | // minification. This option is pre-configured if you do not wish to use 214 | // Usemin blocks. 215 | // dist: { 216 | // files: { 217 | // '<%%= yeoman.dist %>/styles/main.css': [ 218 | // '.tmp/styles/{,*/}*.css', 219 | // '<%%= yeoman.app %>/styles/{,*/}*.css' 220 | // ] 221 | // } 222 | // } 223 | }, 224 | htmlmin: { 225 | dist: { 226 | options: { 227 | /*removeCommentsFromCDATA: true, 228 | // https://github.com/yeoman/grunt-usemin/issues/44 229 | //collapseWhitespace: true, 230 | collapseBooleanAttributes: true, 231 | removeAttributeQuotes: true, 232 | removeRedundantAttributes: true, 233 | useShortDoctype: true, 234 | removeEmptyAttributes: true, 235 | removeOptionalTags: true*/ 236 | }, 237 | files: [{ 238 | expand: true, 239 | cwd: '<%%= yeoman.app %>', 240 | src: ['*.html', 'views/*.html'], 241 | dest: '<%%= yeoman.dist %>' 242 | }] 243 | } 244 | }, 245 | // Put files not handled in other tasks here 246 | copy: { 247 | dist: { 248 | files: [{ 249 | expand: true, 250 | dot: true, 251 | cwd: '<%%= yeoman.app %>', 252 | dest: '<%%= yeoman.dist %>', 253 | src: [ 254 | '*.{ico,png,txt}', 255 | '.htaccess', 256 | 'bower_components/**/*', 257 | 'images/{,*/}*.{gif,webp}', 258 | 'styles/fonts/*' 259 | ] 260 | }, { 261 | expand: true, 262 | cwd: '.tmp/images', 263 | dest: '<%%= yeoman.dist %>/images', 264 | src: [ 265 | 'generated/*' 266 | ] 267 | }] 268 | } 269 | }, 270 | concurrent: { 271 | server: [ 272 | 'coffee:dist'<% if (compassBootstrap) { %>, 273 | 'compass:server'<% } %> 274 | ], 275 | test: [ 276 | 'coffee'<% if (compassBootstrap) { %>, 277 | 'compass'<% } %> 278 | ], 279 | dist: [ 280 | 'coffee',<% if (compassBootstrap) { %> 281 | 'compass:dist',<% } %> 282 | 'imagemin', 283 | 'svgmin', 284 | 'htmlmin' 285 | ] 286 | }, 287 | karma: { 288 | unit: { 289 | configFile: 'karma.conf.js', 290 | singleRun: true 291 | } 292 | }, 293 | cdnify: { 294 | dist: { 295 | html: ['<%%= yeoman.dist %>/*.html'] 296 | } 297 | }, 298 | ngmin: { 299 | dist: { 300 | files: [{ 301 | expand: true, 302 | cwd: '<%%= yeoman.dist %>/scripts', 303 | src: '*.js', 304 | dest: '<%%= yeoman.dist %>/scripts' 305 | }] 306 | } 307 | }, 308 | uglify: { 309 | dist: { 310 | files: { 311 | '<%%= yeoman.dist %>/scripts/scripts.js': [ 312 | '<%%= yeoman.dist %>/scripts/scripts.js' 313 | ] 314 | } 315 | } 316 | } 317 | }); 318 | 319 | grunt.registerTask('server', function (target) { 320 | if (target === 'dist') { 321 | return grunt.task.run(['build', 'open', 'connect:dist:keepalive']); 322 | } 323 | 324 | grunt.task.run([ 325 | 'clean:server', 326 | 'concurrent:server', 327 | 'connect:livereload', 328 | 'open', 329 | 'watch' 330 | ]); 331 | }); 332 | 333 | grunt.registerTask('test', [ 334 | 'clean:server', 335 | 'concurrent:test', 336 | 'connect:test', 337 | 'karma' 338 | ]); 339 | 340 | grunt.registerTask('build', [ 341 | 'clean:dist', 342 | 'useminPrepare', 343 | 'concurrent:dist', 344 | 'concat', 345 | 'copy', 346 | 'cdnify', 347 | 'ngmin', 348 | 'cssmin', 349 | 'uglify', 350 | 'rev', 351 | 'usemin' 352 | ]); 353 | 354 | grunt.registerTask('default', [ 355 | 'jshint', 356 | 'test', 357 | 'build' 358 | ]); 359 | }; 360 | -------------------------------------------------------------------------------- /templates/common/Procfile: -------------------------------------------------------------------------------- 1 | web: node app.js 2 | -------------------------------------------------------------------------------- /templates/common/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.camelize(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": "~1.0.7", 6 | "json3": "~3.2.4",<% if (bootstrap) { %> 7 | "jquery": "~1.9.1", 8 | "bootstrap-sass": "~2.3.1", 9 | <% } %>"es5-shim": "~2.0.8"<% if (resourceModule) { %>, 10 | "angular-resource": "~1.0.7"<% } %><% if (cookiesModule) { %>, 11 | "angular-cookies": "~1.0.7"<% } %><% if (sanitizeModule) { %>, 12 | "angular-sanitize": "~1.0.7"<% } %> 13 | }, 14 | "devDependencies": { 15 | "angular-mocks": "~1.0.7", 16 | "angular-scenario": "~1.0.7" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /templates/common/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "express": "~3.0.0", 6 | "ejs": "~0.8.4" 7 | }, 8 | "devDependencies": { 9 | "grunt": "~0.4.1", 10 | "grunt-contrib-copy": "~0.4.1", 11 | "grunt-contrib-concat": "~0.3.0", 12 | "grunt-contrib-coffee": "~0.7.0", 13 | "grunt-contrib-uglify": "~0.2.0", 14 | "grunt-contrib-compass": "~0.3.0", 15 | "grunt-contrib-jshint": "~0.6.0", 16 | "grunt-contrib-cssmin": "~0.6.0", 17 | "grunt-contrib-connect": "~0.3.0", 18 | "grunt-contrib-clean": "~0.4.1", 19 | "grunt-contrib-htmlmin": "~0.1.3", 20 | "grunt-contrib-imagemin": "~0.1.4", 21 | "grunt-contrib-watch": "~0.4.0", 22 | "grunt-usemin": "~0.1.11", 23 | "grunt-svgmin": "~0.2.0", 24 | "grunt-rev": "~0.1.0", 25 | "grunt-karma": "~0.4.3", 26 | "grunt-open": "~0.2.0", 27 | "grunt-concurrent": "~0.3.0", 28 | "matchdep": "~0.1.2", 29 | "connect-livereload": "~0.2.0", 30 | "grunt-google-cdn": "~0.2.0", 31 | "grunt-ngmin": "~0.0.2" 32 | }, 33 | "engines": { 34 | "node": ">=0.8.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /templates/common/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | 3 | var app = express(); 4 | app.use(express.logger()); 5 | 6 | // Configuration 7 | 8 | app.configure(function(){ 9 | app.set('views', __dirname + '/app'); 10 | //app.set('view engine', 'jade'); 11 | app.use(express.bodyParser()); 12 | app.use(express.methodOverride()); 13 | app.use(express.static(__dirname + '/app')); 14 | app.use(app.router); 15 | app.engine('html', require('ejs').renderFile); 16 | }); 17 | 18 | app.get('/', function(request, response) { 19 | response.render('index.html') 20 | }); 21 | 22 | var port = process.env.PORT || 5000; 23 | app.listen(port, function() { 24 | console.log("Listening on " + port); 25 | }); 26 | -------------------------------------------------------------------------------- /templates/common/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.camelize(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": "~1.0.5", 6 | "json3": "~3.2.4", 7 | "es5-shim": "~2.0.8"<% if (resourceModule) { %>, 8 | "angular-resource": "~1.0.5"<% } %><% if (cookiesModule) { %>, 9 | "angular-cookies": "~1.0.5"<% } %><% if (sanitizeModule) { %>, 10 | "angular-sanitize": "~1.0.5"<% } %> 11 | }, 12 | "devDependencies": { 13 | "angular-mocks": "~1.0.5", 14 | "angular-scenario": "~1.0.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /templates/common/gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | app/bower_components 6 | -------------------------------------------------------------------------------- /templates/common/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 23 | 24 | 25 |
26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /templates/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "express": "~3.0.0", 6 | "ejs": "~0.8.4" 7 | }, 8 | "devDependencies": { 9 | "grunt": "~0.4.1", 10 | "grunt-contrib-copy": "~0.4.1", 11 | "grunt-contrib-concat": "~0.2.0", 12 | "grunt-contrib-coffee": "~0.7.0", 13 | "grunt-contrib-uglify": "~0.2.0", 14 | "grunt-contrib-compass": "~0.2.0", 15 | "grunt-contrib-jshint": "~0.4.3", 16 | "grunt-contrib-cssmin": "~0.6.0", 17 | "grunt-contrib-connect": "~0.3.0", 18 | "grunt-contrib-clean": "~0.4.1", 19 | "grunt-contrib-htmlmin": "~0.1.3", 20 | "grunt-contrib-imagemin": "~0.1.4", 21 | "grunt-contrib-livereload": "~0.1.2", 22 | "grunt-bower-requirejs": "~0.4.2", 23 | "grunt-usemin": "~0.1.11", 24 | "grunt-regarde": "~0.1.1", 25 | "grunt-rev": "~0.1.0", 26 | "grunt-karma": "~0.4.3", 27 | "grunt-open": "~0.2.0", 28 | "matchdep": "~0.1.2", 29 | "grunt-google-cdn": "~0.1.2", 30 | "grunt-ngmin": "~0.0.2" 31 | }, 32 | "engines": { 33 | "node": ">=0.8.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /templates/common/root/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /templates/common/root/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /templates/common/root/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /templates/common/root/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "angular": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /templates/common/root/app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /templates/common/root/app/.htaccess: -------------------------------------------------------------------------------- 1 | # Apache Configuration File 2 | 3 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 4 | # to the main server config file (usually called `httpd.conf`), you should add 5 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 6 | 7 | # ############################################################################## 8 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 9 | # ############################################################################## 10 | 11 | # ------------------------------------------------------------------------------ 12 | # | Cross-domain AJAX requests | 13 | # ------------------------------------------------------------------------------ 14 | 15 | # Enable cross-origin AJAX requests. 16 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 17 | # http://enable-cors.org/ 18 | 19 | # 20 | # Header set Access-Control-Allow-Origin "*" 21 | # 22 | 23 | # ------------------------------------------------------------------------------ 24 | # | CORS-enabled images | 25 | # ------------------------------------------------------------------------------ 26 | 27 | # Send the CORS header for images when browsers request it. 28 | # https://developer.mozilla.org/en/CORS_Enabled_Image 29 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 30 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 31 | 32 | 33 | 34 | 35 | SetEnvIf Origin ":" IS_CORS 36 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 37 | 38 | 39 | 40 | 41 | # ------------------------------------------------------------------------------ 42 | # | Web fonts access | 43 | # ------------------------------------------------------------------------------ 44 | 45 | # Allow access from all domains for web fonts 46 | 47 | 48 | 49 | Header set Access-Control-Allow-Origin "*" 50 | 51 | 52 | 53 | 54 | # ############################################################################## 55 | # # ERRORS # 56 | # ############################################################################## 57 | 58 | # ------------------------------------------------------------------------------ 59 | # | 404 error prevention for non-existing redirected folders | 60 | # ------------------------------------------------------------------------------ 61 | 62 | # Prevent Apache from returning a 404 error for a rewrite if a directory 63 | # with the same name does not exist. 64 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 65 | # http://www.webmasterworld.com/apache/3808792.htm 66 | 67 | Options -MultiViews 68 | 69 | # ------------------------------------------------------------------------------ 70 | # | Custom error messages / pages | 71 | # ------------------------------------------------------------------------------ 72 | 73 | # You can customize what Apache returns to the client in case of an error (see 74 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: 75 | 76 | ErrorDocument 404 /404.html 77 | 78 | 79 | # ############################################################################## 80 | # # INTERNET EXPLORER # 81 | # ############################################################################## 82 | 83 | # ------------------------------------------------------------------------------ 84 | # | Better website experience | 85 | # ------------------------------------------------------------------------------ 86 | 87 | # Force IE to render pages in the highest available mode in the various 88 | # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. 89 | # Use, if installed, Google Chrome Frame. 90 | 91 | 92 | Header set X-UA-Compatible "IE=edge,chrome=1" 93 | # `mod_headers` can't match based on the content-type, however, we only 94 | # want to send this header for HTML pages and not for the other resources 95 | 96 | Header unset X-UA-Compatible 97 | 98 | 99 | 100 | # ------------------------------------------------------------------------------ 101 | # | Cookie setting from iframes | 102 | # ------------------------------------------------------------------------------ 103 | 104 | # Allow cookies to be set from iframes in IE. 105 | 106 | # 107 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 108 | # 109 | 110 | # ------------------------------------------------------------------------------ 111 | # | Screen flicker | 112 | # ------------------------------------------------------------------------------ 113 | 114 | # Stop screen flicker in IE on CSS rollovers (this only works in 115 | # combination with the `ExpiresByType` directives for images from below). 116 | 117 | # BrowserMatch "MSIE" brokenvary=1 118 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 119 | # BrowserMatch "Opera" !brokenvary 120 | # SetEnvIf brokenvary 1 force-no-vary 121 | 122 | 123 | # ############################################################################## 124 | # # MIME TYPES AND ENCODING # 125 | # ############################################################################## 126 | 127 | # ------------------------------------------------------------------------------ 128 | # | Proper MIME types for all files | 129 | # ------------------------------------------------------------------------------ 130 | 131 | 132 | 133 | # Audio 134 | AddType audio/mp4 m4a f4a f4b 135 | AddType audio/ogg oga ogg 136 | 137 | # JavaScript 138 | # Normalize to standard type (it's sniffed in IE anyways): 139 | # http://tools.ietf.org/html/rfc4329#section-7.2 140 | AddType application/javascript js jsonp 141 | AddType application/json json 142 | 143 | # Video 144 | AddType video/mp4 mp4 m4v f4v f4p 145 | AddType video/ogg ogv 146 | AddType video/webm webm 147 | AddType video/x-flv flv 148 | 149 | # Web fonts 150 | AddType application/font-woff woff 151 | AddType application/vnd.ms-fontobject eot 152 | 153 | # Browsers usually ignore the font MIME types and sniff the content, 154 | # however, Chrome shows a warning if other MIME types are used for the 155 | # following fonts. 156 | AddType application/x-font-ttf ttc ttf 157 | AddType font/opentype otf 158 | 159 | # Make SVGZ fonts work on iPad: 160 | # https://twitter.com/FontSquirrel/status/14855840545 161 | AddType image/svg+xml svg svgz 162 | AddEncoding gzip svgz 163 | 164 | # Other 165 | AddType application/octet-stream safariextz 166 | AddType application/x-chrome-extension crx 167 | AddType application/x-opera-extension oex 168 | AddType application/x-shockwave-flash swf 169 | AddType application/x-web-app-manifest+json webapp 170 | AddType application/x-xpinstall xpi 171 | AddType application/xml atom rdf rss xml 172 | AddType image/webp webp 173 | AddType image/x-icon ico 174 | AddType text/cache-manifest appcache manifest 175 | AddType text/vtt vtt 176 | AddType text/x-component htc 177 | AddType text/x-vcard vcf 178 | 179 | 180 | 181 | # ------------------------------------------------------------------------------ 182 | # | UTF-8 encoding | 183 | # ------------------------------------------------------------------------------ 184 | 185 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 186 | AddDefaultCharset utf-8 187 | 188 | # Force UTF-8 for certain file formats. 189 | 190 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml 191 | 192 | 193 | 194 | # ############################################################################## 195 | # # URL REWRITES # 196 | # ############################################################################## 197 | 198 | # ------------------------------------------------------------------------------ 199 | # | Rewrite engine | 200 | # ------------------------------------------------------------------------------ 201 | 202 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is 203 | # necessary for the following directives to work. 204 | 205 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 206 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the 207 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 208 | 209 | # Also, some cloud hosting services require `RewriteBase` to be set: 210 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 211 | 212 | 213 | Options +FollowSymlinks 214 | # Options +SymLinksIfOwnerMatch 215 | RewriteEngine On 216 | # RewriteBase / 217 | 218 | 219 | # ------------------------------------------------------------------------------ 220 | # | Suppressing / Forcing the "www." at the beginning of URLs | 221 | # ------------------------------------------------------------------------------ 222 | 223 | # The same content should never be available under two different URLs especially 224 | # not with and without "www." at the beginning. This can cause SEO problems 225 | # (duplicate content), therefore, you should choose one of the alternatives and 226 | # redirect the other one. 227 | 228 | # By default option 1 (no "www.") is activated: 229 | # http://no-www.org/faq.php?q=class_b 230 | 231 | # If you'd prefer to use option 2, just comment out all the lines from option 1 232 | # and uncomment the ones from option 2. 233 | 234 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 235 | 236 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 237 | 238 | # Option 1: rewrite www.example.com → example.com 239 | 240 | 241 | RewriteCond %{HTTPS} !=on 242 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 243 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 244 | 245 | 246 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 247 | 248 | # Option 2: rewrite example.com → www.example.com 249 | 250 | # Be aware that the following might not be a good idea if you use "real" 251 | # subdomains for certain parts of your website. 252 | 253 | # 254 | # RewriteCond %{HTTPS} !=on 255 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] 256 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 257 | # 258 | 259 | 260 | # ############################################################################## 261 | # # SECURITY # 262 | # ############################################################################## 263 | 264 | # ------------------------------------------------------------------------------ 265 | # | Content Security Policy (CSP) | 266 | # ------------------------------------------------------------------------------ 267 | 268 | # You can mitigate the risk of cross-site scripting and other content-injection 269 | # attacks by setting a Content Security Policy which whitelists trusted sources 270 | # of content for your site. 271 | 272 | # The example header below allows ONLY scripts that are loaded from the current 273 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 274 | # work as-is for your site! 275 | 276 | # To get all the details you'll need to craft a reasonable policy for your site, 277 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or 278 | # see the specification: http://w3.org/TR/CSP). 279 | 280 | # 281 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 282 | # 283 | # Header unset Content-Security-Policy 284 | # 285 | # 286 | 287 | # ------------------------------------------------------------------------------ 288 | # | File access | 289 | # ------------------------------------------------------------------------------ 290 | 291 | # Block access to directories without a default document. 292 | # Usually you should leave this uncommented because you shouldn't allow anyone 293 | # to surf through every directory on your server (which may includes rather 294 | # private places like the CMS's directories). 295 | 296 | 297 | Options -Indexes 298 | 299 | 300 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 301 | 302 | # Block access to hidden files and directories. 303 | # This includes directories used by version control systems such as Git and SVN. 304 | 305 | 306 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 307 | RewriteCond %{SCRIPT_FILENAME} -f 308 | RewriteRule "(^|/)\." - [F] 309 | 310 | 311 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 312 | 313 | # Block access to backup and source files. 314 | # These files may be left by some text editors and can pose a great security 315 | # danger when anyone has access to them. 316 | 317 | 318 | Order allow,deny 319 | Deny from all 320 | Satisfy All 321 | 322 | 323 | # ------------------------------------------------------------------------------ 324 | # | Secure Sockets Layer (SSL) | 325 | # ------------------------------------------------------------------------------ 326 | 327 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: 328 | # prevent `https://www.example.com` when your certificate only allows 329 | # `https://secure.example.com`. 330 | 331 | # 332 | # RewriteCond %{SERVER_PORT} !^443 333 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 334 | # 335 | 336 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 337 | 338 | # Force client-side SSL redirection. 339 | 340 | # If a user types "example.com" in his browser, the above rule will redirect him 341 | # to the secure version of the site. That still leaves a window of opportunity 342 | # (the initial HTTP connection) for an attacker to downgrade or redirect the 343 | # request. The following header ensures that browser will ONLY connect to your 344 | # server via HTTPS, regardless of what the users type in the address bar. 345 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 346 | 347 | # 348 | # Header set Strict-Transport-Security max-age=16070400; 349 | # 350 | 351 | # ------------------------------------------------------------------------------ 352 | # | Server software information | 353 | # ------------------------------------------------------------------------------ 354 | 355 | # Avoid displaying the exact Apache version number, the description of the 356 | # generic OS-type and the information about Apache's compiled-in modules. 357 | 358 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 359 | 360 | # ServerTokens Prod 361 | 362 | 363 | # ############################################################################## 364 | # # WEB PERFORMANCE # 365 | # ############################################################################## 366 | 367 | # ------------------------------------------------------------------------------ 368 | # | Compression | 369 | # ------------------------------------------------------------------------------ 370 | 371 | 372 | 373 | # Force compression for mangled headers. 374 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 375 | 376 | 377 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 378 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 379 | 380 | 381 | 382 | # Compress all output labeled with one of the following MIME-types 383 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 384 | # and can remove the `` and `` lines 385 | # as `AddOutputFilterByType` is still in the core directives). 386 | 387 | AddOutputFilterByType DEFLATE application/atom+xml \ 388 | application/javascript \ 389 | application/json \ 390 | application/rss+xml \ 391 | application/vnd.ms-fontobject \ 392 | application/x-font-ttf \ 393 | application/x-web-app-manifest+json \ 394 | application/xhtml+xml \ 395 | application/xml \ 396 | font/opentype \ 397 | image/svg+xml \ 398 | image/x-icon \ 399 | text/css \ 400 | text/html \ 401 | text/plain \ 402 | text/x-component \ 403 | text/xml 404 | 405 | 406 | 407 | 408 | # ------------------------------------------------------------------------------ 409 | # | Content transformations | 410 | # ------------------------------------------------------------------------------ 411 | 412 | # Prevent some of the mobile network providers from modifying the content of 413 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 414 | 415 | # 416 | # Header set Cache-Control "no-transform" 417 | # 418 | 419 | # ------------------------------------------------------------------------------ 420 | # | ETag removal | 421 | # ------------------------------------------------------------------------------ 422 | 423 | # Since we're sending far-future expires headers (see below), ETags can 424 | # be removed: http://developer.yahoo.com/performance/rules.html#etags. 425 | 426 | # `FileETag None` is not enough for every server. 427 | 428 | Header unset ETag 429 | 430 | 431 | FileETag None 432 | 433 | # ------------------------------------------------------------------------------ 434 | # | Expires headers (for better cache control) | 435 | # ------------------------------------------------------------------------------ 436 | 437 | # The following expires headers are set pretty far in the future. If you don't 438 | # control versioning with filename-based cache busting, consider lowering the 439 | # cache time for resources like CSS and JS to something like 1 week. 440 | 441 | 442 | 443 | ExpiresActive on 444 | ExpiresDefault "access plus 1 month" 445 | 446 | # CSS 447 | ExpiresByType text/css "access plus 1 year" 448 | 449 | # Data interchange 450 | ExpiresByType application/json "access plus 0 seconds" 451 | ExpiresByType application/xml "access plus 0 seconds" 452 | ExpiresByType text/xml "access plus 0 seconds" 453 | 454 | # Favicon (cannot be renamed!) 455 | ExpiresByType image/x-icon "access plus 1 week" 456 | 457 | # HTML components (HTCs) 458 | ExpiresByType text/x-component "access plus 1 month" 459 | 460 | # HTML 461 | ExpiresByType text/html "access plus 0 seconds" 462 | 463 | # JavaScript 464 | ExpiresByType application/javascript "access plus 1 year" 465 | 466 | # Manifest files 467 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 468 | ExpiresByType text/cache-manifest "access plus 0 seconds" 469 | 470 | # Media 471 | ExpiresByType audio/ogg "access plus 1 month" 472 | ExpiresByType image/gif "access plus 1 month" 473 | ExpiresByType image/jpeg "access plus 1 month" 474 | ExpiresByType image/png "access plus 1 month" 475 | ExpiresByType video/mp4 "access plus 1 month" 476 | ExpiresByType video/ogg "access plus 1 month" 477 | ExpiresByType video/webm "access plus 1 month" 478 | 479 | # Web feeds 480 | ExpiresByType application/atom+xml "access plus 1 hour" 481 | ExpiresByType application/rss+xml "access plus 1 hour" 482 | 483 | # Web fonts 484 | ExpiresByType application/font-woff "access plus 1 month" 485 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 486 | ExpiresByType application/x-font-ttf "access plus 1 month" 487 | ExpiresByType font/opentype "access plus 1 month" 488 | ExpiresByType image/svg+xml "access plus 1 month" 489 | 490 | 491 | 492 | # ------------------------------------------------------------------------------ 493 | # | Filename-based cache busting | 494 | # ------------------------------------------------------------------------------ 495 | 496 | # If you're not using a build process to manage your filename version revving, 497 | # you might want to consider enabling the following directives to route all 498 | # requests such as `/css/style.12345.css` to `/css/style.css`. 499 | 500 | # To understand why this is important and a better idea than `*.css?v231`, read: 501 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 502 | 503 | # 504 | # RewriteCond %{REQUEST_FILENAME} !-f 505 | # RewriteCond %{REQUEST_FILENAME} !-d 506 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] 507 | # 508 | 509 | # ------------------------------------------------------------------------------ 510 | # | File concatenation | 511 | # ------------------------------------------------------------------------------ 512 | 513 | # Allow concatenation from within specific CSS and JS files, e.g.: 514 | # Inside of `script.combined.js` you could have 515 | # 516 | # 517 | # and they would be included into this single file. 518 | 519 | # 520 | # 521 | # Options +Includes 522 | # AddOutputFilterByType INCLUDES application/javascript application/json 523 | # SetOutputFilter INCLUDES 524 | # 525 | # 526 | # Options +Includes 527 | # AddOutputFilterByType INCLUDES text/css 528 | # SetOutputFilter INCLUDES 529 | # 530 | # 531 | 532 | # ------------------------------------------------------------------------------ 533 | # | Persistent connections | 534 | # ------------------------------------------------------------------------------ 535 | 536 | # Allow multiple requests to be sent over the same TCP connection: 537 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. 538 | 539 | # Enable if you serve a lot of static content but, be aware of the 540 | # possible disadvantages! 541 | 542 | # 543 | # Header set Connection Keep-Alive 544 | # 545 | -------------------------------------------------------------------------------- /templates/common/root/app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /templates/common/root/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SerhiiKozachenko/generator-express-angular/a69786c67b2f83fecabd983e95903aa642de9bcf/templates/common/root/app/favicon.ico -------------------------------------------------------------------------------- /templates/common/root/app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /templates/common/root/app/styles/main.css: -------------------------------------------------------------------------------- 1 | /* Will be compiled down to a single stylesheet with your sass files */ -------------------------------------------------------------------------------- /templates/common/root/app/views/main.html: -------------------------------------------------------------------------------- 1 |
2 |

'Allo, 'Allo!

3 |

You now have

4 | 7 |

installed.

8 |

Enjoy coding! - Yeoman

9 |
10 | -------------------------------------------------------------------------------- /templates/common/root/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "after": false, 23 | "afterEach": false, 24 | "angular": false, 25 | "before": false, 26 | "beforeEach": false, 27 | "browser": false, 28 | "describe": false, 29 | "expect": false, 30 | "inject": false, 31 | "it": false, 32 | "spyOn": false 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /templates/common/root/test/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End2end Test Runner 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /templates/common/view.html: -------------------------------------------------------------------------------- 1 |

This is the <%= name %> view.

2 | -------------------------------------------------------------------------------- /templates/javascript-min/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>', []) 4 | .config(['$routeProvider', function ($routeProvider) { 5 | $routeProvider 6 | .when('/', { 7 | templateUrl: 'views/main.html', 8 | controller: 'MainCtrl' 9 | }) 10 | .otherwise({ 11 | redirectTo: '/' 12 | }); 13 | }]); 14 | -------------------------------------------------------------------------------- /templates/javascript-min/controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .controller('<%= _.classify(name) %>Ctrl', ['$scope', function ($scope) { 5 | $scope.awesomeThings = [ 6 | 'HTML5 Boilerplate', 7 | 'AngularJS', 8 | 'Karma' 9 | ]; 10 | }]); 11 | -------------------------------------------------------------------------------- /templates/javascript-min/decorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .config(['$provide', function ($provide) { 5 | $provide.decorator('<%= _.camelize(name) %>', function ($delegate) { 6 | // decorate the $delegate 7 | return $delegate; 8 | }); 9 | }]); 10 | -------------------------------------------------------------------------------- /templates/javascript-min/directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .directive('<%= _.camelize(name) %>', [function () { 5 | return { 6 | template: '
', 7 | restrict: 'E', 8 | link: function postLink(scope, element, attrs) { 9 | element.text('this is the <%= _.camelize(name) %> directive'); 10 | } 11 | }; 12 | }]); 13 | -------------------------------------------------------------------------------- /templates/javascript-min/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .filter('<%= _.camelize(name) %>', [function () { 5 | return function (input) { 6 | return '<%= _.camelize(name) %> filter: ' + input; 7 | }; 8 | }]); 9 | -------------------------------------------------------------------------------- /templates/javascript-min/service/constant.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .constant('<%= _.camelize(name) %>', 42); 5 | -------------------------------------------------------------------------------- /templates/javascript-min/service/factory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .factory('<%= _.camelize(name) %>', [function() { 5 | // Service logic 6 | // ... 7 | 8 | var meaningOfLife = 42; 9 | 10 | // Public API here 11 | return { 12 | someMethod: function() { 13 | return meaningOfLife; 14 | } 15 | }; 16 | }]); 17 | -------------------------------------------------------------------------------- /templates/javascript-min/service/provider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .provider('<%= _.camelize(name) %>', [function() { 5 | 6 | // Private variables 7 | var salutation = 'Hello'; 8 | 9 | // Private constructor 10 | function Greeter() { 11 | this.greet = function() { 12 | return salutation; 13 | }; 14 | } 15 | 16 | // Public API for configuration 17 | this.setSalutation = function(s) { 18 | salutation = s; 19 | }; 20 | 21 | // Method for instantiating 22 | this.$get = function() { 23 | return new Greeter(); 24 | }; 25 | }]); 26 | -------------------------------------------------------------------------------- /templates/javascript-min/service/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .service('<%= _.classify(name) %>', function <%= _.classify(name) %>() { 5 | // AngularJS will instantiate a singleton by calling "new" on this function 6 | }); 7 | -------------------------------------------------------------------------------- /templates/javascript-min/service/value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .value('<%= _.camelize(name) %>', 42); 5 | -------------------------------------------------------------------------------- /templates/javascript-min/spec/controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: <%= _.classify(name) %>Ctrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | var <%= _.classify(name) %>Ctrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | <%= _.classify(name) %>Ctrl = $controller('<%= _.classify(name) %>Ctrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /templates/javascript-min/spec/directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Directive: <%= _.camelize(name) %>', function () { 4 | 5 | // load the directive's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | var element, 9 | scope; 10 | 11 | beforeEach(inject(function ($rootScope) { 12 | scope = $rootScope.$new(); 13 | })); 14 | 15 | it('should make hidden element visible', inject(function ($compile) { 16 | element = angular.element('<<%= _.dasherize(name) %>>>'); 17 | element = $compile(element)(scope); 18 | expect(element.text()).toBe('this is the <%= _.camelize(name) %> directive'); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /templates/javascript-min/spec/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Filter: <%= _.camelize(name) %>', function () { 4 | 5 | // load the filter's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | // initialize a new instance of the filter before each test 9 | var <%= _.camelize(name) %>; 10 | beforeEach(inject(function($filter) { 11 | <%= _.camelize(name) %> = $filter('<%= _.camelize(name) %>'); 12 | })); 13 | 14 | it('should return the input prefixed with "<%= _.camelize(name) %> filter:"', function () { 15 | var text = 'angularjs'; 16 | expect(<%= _.camelize(name) %>(text)).toBe('<%= _.camelize(name) %> filter: ' + text); 17 | }); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /templates/javascript-min/spec/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Service: <%= _.camelize(name) %>', function () { 4 | 5 | // load the service's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | // instantiate service 9 | var <%= _.camelize(name) %>; 10 | beforeEach(inject(function(_<%= _.camelize(name) %>_) { 11 | <%= _.camelize(name) %> = _<%= _.camelize(name) %>_; 12 | })); 13 | 14 | it('should do something', function () { 15 | expect(!!<%= _.camelize(name) %>).toBe(true); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /templates/javascript/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>', []) 4 | .config(function ($routeProvider) { 5 | $routeProvider 6 | .when('/', { 7 | templateUrl: 'views/main.html', 8 | controller: 'MainCtrl' 9 | }) 10 | .otherwise({ 11 | redirectTo: '/' 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /templates/javascript/controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .controller('<%= _.classify(name) %>Ctrl', function ($scope) { 5 | $scope.awesomeThings = [ 6 | 'HTML5 Boilerplate', 7 | 'AngularJS', 8 | 'Karma' 9 | ]; 10 | }); 11 | -------------------------------------------------------------------------------- /templates/javascript/decorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .config(function ($provide) { 5 | $provide.decorator('<%= _.camelize(name) %>', function ($delegate) { 6 | // decorate the $delegate 7 | return $delegate; 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /templates/javascript/directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .directive('<%= _.camelize(name) %>', function () { 5 | return { 6 | template: '
', 7 | restrict: 'E', 8 | link: function postLink(scope, element, attrs) { 9 | element.text('this is the <%= _.camelize(name) %> directive'); 10 | } 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /templates/javascript/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .filter('<%= _.camelize(name) %>', function () { 5 | return function (input) { 6 | return '<%= _.camelize(name) %> filter: ' + input; 7 | }; 8 | }); 9 | -------------------------------------------------------------------------------- /templates/javascript/service/constant.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .constant('<%= _.camelize(name) %>', 42); 5 | -------------------------------------------------------------------------------- /templates/javascript/service/factory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .factory('<%= _.camelize(name) %>', function () { 5 | // Service logic 6 | // ... 7 | 8 | var meaningOfLife = 42; 9 | 10 | // Public API here 11 | return { 12 | someMethod: function () { 13 | return meaningOfLife; 14 | } 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /templates/javascript/service/provider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .provider('<%= _.camelize(name) %>', function () { 5 | 6 | // Private variables 7 | var salutation = 'Hello'; 8 | 9 | // Private constructor 10 | function Greeter() { 11 | this.greet = function () { 12 | return salutation; 13 | }; 14 | } 15 | 16 | // Public API for configuration 17 | this.setSalutation = function (s) { 18 | salutation = s; 19 | }; 20 | 21 | // Method for instantiating 22 | this.$get = function () { 23 | return new Greeter(); 24 | }; 25 | }); 26 | -------------------------------------------------------------------------------- /templates/javascript/service/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .service('<%= _.classify(name) %>', function <%= _.classify(name) %>() { 5 | // AngularJS will instantiate a singleton by calling "new" on this function 6 | }); 7 | -------------------------------------------------------------------------------- /templates/javascript/service/value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= moduleName %>') 4 | .value('<%= _.camelize(name) %>', 42); 5 | -------------------------------------------------------------------------------- /templates/javascript/spec/controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: <%= _.classify(name) %>Ctrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | var <%= _.classify(name) %>Ctrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | <%= _.classify(name) %>Ctrl = $controller('<%= _.classify(name) %>Ctrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /templates/javascript/spec/directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Directive: <%= _.camelize(name) %>', function () { 4 | 5 | // load the directive's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | var element, 9 | scope; 10 | 11 | beforeEach(inject(function ($rootScope) { 12 | scope = $rootScope.$new(); 13 | })); 14 | 15 | it('should make hidden element visible', inject(function ($compile) { 16 | element = angular.element('<<%= _.dasherize(name) %>>>'); 17 | element = $compile(element)(scope); 18 | expect(element.text()).toBe('this is the <%= _.camelize(name) %> directive'); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /templates/javascript/spec/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Filter: <%= _.camelize(name) %>', function () { 4 | 5 | // load the filter's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | // initialize a new instance of the filter before each test 9 | var <%= _.camelize(name) %>; 10 | beforeEach(inject(function ($filter) { 11 | <%= _.camelize(name) %> = $filter('<%= _.camelize(name) %>'); 12 | })); 13 | 14 | it('should return the input prefixed with "<%= _.camelize(name) %> filter:"', function () { 15 | var text = 'angularjs'; 16 | expect(<%= _.camelize(name) %>(text)).toBe('<%= _.camelize(name) %> filter: ' + text); 17 | }); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /templates/javascript/spec/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Service: <%= _.camelize(name) %>', function () { 4 | 5 | // load the service's module 6 | beforeEach(module('<%= moduleName %>')); 7 | 8 | // instantiate service 9 | var <%= _.camelize(name) %>; 10 | beforeEach(inject(function (_<%= _.camelize(name) %>_) { 11 | <%= _.camelize(name) %> = _<%= _.camelize(name) %>_; 12 | })); 13 | 14 | it('should do something', function () { 15 | expect(!!<%= _.camelize(name) %>).toBe(true); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/test-appname-substitution.js: -------------------------------------------------------------------------------- 1 | /*global describe, before, it, beforeEach */ 2 | 'use strict'; 3 | var fs = require('fs'); 4 | var assert = require('assert'); 5 | var path = require('path'); 6 | var util = require('util'); 7 | var generators = require('yeoman-generator'); 8 | var helpers = require('yeoman-generator').test; 9 | 10 | 11 | describe('Angular generator template mechanism', function () { 12 | //TODO: Add underscore dependency and test with _.camelize(folderName); 13 | var folderName = 'UpperCaseBug'; 14 | var angular; 15 | 16 | beforeEach(function (done) { 17 | var deps = [ 18 | '../../app', 19 | '../../common', 20 | '../../controller', 21 | '../../main', [ 22 | helpers.createDummyGenerator(), 23 | 'karma:app' 24 | ] 25 | ]; 26 | helpers.testDirectory(path.join(__dirname, folderName), function (err) { 27 | if (err) { 28 | done(err); 29 | } 30 | angular = helpers.createGenerator('angular:app', deps); 31 | angular.options['skip-install'] = true; 32 | done(); 33 | }); 34 | }); 35 | 36 | it('should generate the same appName in every file', function (done) { 37 | var expectedAppName = folderName + 'App'; 38 | var expected = [ 39 | 'app/scripts/app.js', 40 | 'app/scripts/controllers/main.js', 41 | 'app/index.html', 42 | 'test/spec/controllers/main.js' 43 | ]; 44 | helpers.mockPrompt(angular, { 45 | bootstrap: true, 46 | compassBoostrap: true, 47 | modules: [] 48 | }); 49 | 50 | angular.run({}, function () { 51 | // Check if all files are created for the test 52 | helpers.assertFiles(expected); 53 | 54 | // read JS Files 55 | var app_js = fs.readFileSync('app/scripts/app.js', 'utf8'); 56 | var main_js = fs.readFileSync('app/scripts/controllers/main.js', 'utf8'); 57 | var main_test_js = fs.readFileSync('test/spec/controllers/main.js', 'utf8'); 58 | 59 | // Test JS Files 60 | var regex_js = new RegExp('module\\(\'' + expectedAppName + '\''); 61 | assert.ok(regex_js.test(app_js), 'app.js template using a wrong appName'); 62 | assert.ok(regex_js.test(main_js), 'main.js template using a wrong appName'); 63 | assert.ok(regex_js.test(main_test_js), 'controller spec template using a wrong appName'); 64 | 65 | // read HTML file 66 | var index_html = fs.readFileSync('app/index.html', 'utf8'); 67 | 68 | // Test HTML File 69 | var regex_html = new RegExp('ng-app=\"' + expectedAppName + '\"'); 70 | assert.ok(regex_html.test(index_html), 'index.html template using a wrong appName'); 71 | done(); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /test/test-file-creation.js: -------------------------------------------------------------------------------- 1 | /*global describe, before, it, beforeEach */ 2 | 'use strict'; 3 | var fs = require('fs'); 4 | var assert = require('assert'); 5 | var path = require('path'); 6 | var util = require('util'); 7 | var generators = require('yeoman-generator'); 8 | var helpers = require('yeoman-generator').test; 9 | 10 | 11 | describe('Angular generator', function () { 12 | var angular; 13 | 14 | beforeEach(function (done) { 15 | var deps = [ 16 | '../../app', 17 | '../../common', 18 | '../../controller', 19 | '../../main', [ 20 | helpers.createDummyGenerator(), 21 | 'karma:app' 22 | ] 23 | ]; 24 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 25 | if (err) { 26 | done(err); 27 | } 28 | angular = helpers.createGenerator('angular:app', deps); 29 | angular.options['skip-install'] = true; 30 | done(); 31 | }); 32 | }); 33 | 34 | it('should generate dotfiles', function (done) { 35 | helpers.mockPrompt(angular, { 36 | bootstrap: true, 37 | compassBoostrap: true, 38 | modules: [] 39 | }); 40 | 41 | angular.run({}, function () { 42 | helpers.assertFiles(['.bowerrc', '.gitignore', '.editorconfig', '.jshintrc']); 43 | done(); 44 | }); 45 | }); 46 | 47 | it('creates expected files', function (done) { 48 | var expected = ['app/.htaccess', 49 | 'app/404.html', 50 | 'app/favicon.ico', 51 | 'app/robots.txt', 52 | 'app/styles/main.css', 53 | 'app/views/main.html', 54 | ['.bowerrc', /"directory": "app\/bower_components"/], 55 | 'Gruntfile.js', 56 | 'package.json', 57 | ['bower.json', /"name":\s+"temp"/], 58 | 'app/scripts/app.js', 59 | 'app/index.html', 60 | 'app/scripts/controllers/main.js', 61 | 'test/spec/controllers/main.js' 62 | ]; 63 | helpers.mockPrompt(angular, { 64 | bootstrap: true, 65 | compassBoostrap: true, 66 | modules: [] 67 | }); 68 | 69 | angular.run({}, function() { 70 | helpers.assertFiles(expected); 71 | done(); 72 | }); 73 | }); 74 | 75 | it('creates coffeescript files', function (done) { 76 | var expected = ['app/.htaccess', 77 | 'app/404.html', 78 | 'app/favicon.ico', 79 | 'app/robots.txt', 80 | 'app/styles/main.css', 81 | 'app/views/main.html', 82 | ['.bowerrc', /"directory": "app\/bower_components"/], 83 | 'Gruntfile.js', 84 | 'package.json', 85 | ['bower.json', /"name":\s+"temp"/], 86 | 'app/scripts/app.coffee', 87 | 'app/index.html', 88 | 'app/scripts/controllers/main.coffee', 89 | 'test/spec/controllers/main.coffee' 90 | ]; 91 | helpers.mockPrompt(angular, { 92 | bootstrap: true, 93 | compassBoostrap: true, 94 | modules: [] 95 | }); 96 | 97 | angular.env.options.coffee = true; 98 | angular.run([], function () { 99 | helpers.assertFiles(expected); 100 | done(); 101 | }); 102 | }); 103 | 104 | describe('Controller', function () { 105 | it('should generate a new controller', function (done) { 106 | var angularCtrl; 107 | var deps = ['../../controller']; 108 | angularCtrl = helpers.createGenerator('angular:controller', deps, ['foo']); 109 | 110 | helpers.mockPrompt(angular, { 111 | bootstrap: true, 112 | compassBoostrap: true, 113 | modules: [] 114 | }); 115 | angular.run([], function () { 116 | angularCtrl.run([], function () { 117 | helpers.assertFiles([ 118 | ['app/scripts/controllers/foo.js', /controller\('FooCtrl'/], 119 | ['test/spec/controllers/foo.js', /describe\('Controller: FooCtrl'/] 120 | ]); 121 | done(); 122 | }); 123 | }); 124 | }); 125 | }); 126 | 127 | describe('View', function () { 128 | it('should generate a new view', function (done) { 129 | var angularView; 130 | var deps = ['../../view']; 131 | angularView = helpers.createGenerator('angular:view', deps, ['foo']); 132 | 133 | helpers.mockPrompt(angular, { 134 | bootstrap: true, 135 | compassBoostrap: true, 136 | modules: [] 137 | }); 138 | angular.run([], function (){ 139 | angularView.run([], function () { 140 | helpers.assertFiles([ 141 | ['app/views/foo.html'] 142 | ]); 143 | done(); 144 | }); 145 | }); 146 | }); 147 | }); 148 | }); 149 | -------------------------------------------------------------------------------- /util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | 5 | 6 | module.exports = { 7 | rewrite: rewrite, 8 | rewriteFile: rewriteFile 9 | }; 10 | 11 | function rewriteFile (args) { 12 | args.path = args.path || process.cwd(); 13 | var fullPath = path.join(args.path, args.file); 14 | 15 | args.haystack = fs.readFileSync(fullPath, 'utf8'); 16 | var body = rewrite(args); 17 | 18 | fs.writeFileSync(fullPath, body); 19 | } 20 | 21 | function escapeRegExp (str) { 22 | return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); 23 | } 24 | 25 | function rewrite (args) { 26 | // check if splicable is already in the body text 27 | var re = new RegExp(args.splicable.map(function (line) { 28 | return '\s*' + escapeRegExp(line); 29 | }).join('\n')); 30 | 31 | if (re.test(args.haystack)) { 32 | return args.haystack; 33 | } 34 | 35 | var lines = args.haystack.split('\n'); 36 | 37 | var otherwiseLineIndex = 0; 38 | lines.forEach(function (line, i) { 39 | if (line.indexOf(args.needle) !== -1) { 40 | otherwiseLineIndex = i; 41 | } 42 | }); 43 | 44 | var spaces = 0; 45 | while (lines[otherwiseLineIndex].charAt(spaces) === ' ') { 46 | spaces += 1; 47 | } 48 | 49 | var spaceStr = ''; 50 | while ((spaces -= 1) >= 0) { 51 | spaceStr += ' '; 52 | } 53 | 54 | lines.splice(otherwiseLineIndex, 0, args.splicable.map(function (line) { 55 | return spaceStr + line; 56 | }).join('\n')); 57 | 58 | return lines.join('\n'); 59 | } 60 | -------------------------------------------------------------------------------- /value/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS service. 3 | Docs: http://docs.angularjs.org/guide/dev_guide.services.creating_services 4 | 5 | Example: 6 | yo angular:value thing [--coffee] [--minsafe] 7 | 8 | This will create: 9 | app/scripts/services/thing.js 10 | -------------------------------------------------------------------------------- /value/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var ScriptBase = require('../script-base.js'); 5 | var angularUtils = require('../util.js'); 6 | 7 | 8 | module.exports = Generator; 9 | 10 | function Generator() { 11 | ScriptBase.apply(this, arguments); 12 | } 13 | 14 | util.inherits(Generator, ScriptBase); 15 | 16 | Generator.prototype.createServiceFiles = function createServiceFiles() { 17 | this.appTemplate('service/value'); 18 | this.testTemplate('spec/service'); 19 | }; 20 | -------------------------------------------------------------------------------- /view/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new AngularJS view 3 | 4 | Example: 5 | yo angular:view thing 6 | 7 | This will create: 8 | app/scripts/views/thing.html 9 | -------------------------------------------------------------------------------- /view/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | 7 | module.exports = Generator; 8 | 9 | function Generator() { 10 | yeoman.generators.NamedBase.apply(this, arguments); 11 | this.sourceRoot(path.join(__dirname, '../templates')); 12 | 13 | if (typeof this.env.options.appPath === 'undefined') { 14 | try { 15 | this.env.options.appPath = require(path.join(process.cwd(), 'bower.json')).appPath; 16 | } catch (e) {} 17 | this.env.options.appPath = this.env.options.appPath || 'app'; 18 | } 19 | } 20 | 21 | util.inherits(Generator, yeoman.generators.NamedBase); 22 | 23 | Generator.prototype.createViewFiles = function createViewFiles() { 24 | var targetPath = this.name; 25 | if (this.name.indexOf('/') === -1) { 26 | targetPath = 'views/' + targetPath; 27 | } 28 | this.template('common/view.html', path.join(this.env.options.appPath, this.name + '.html')); 29 | }; 30 | --------------------------------------------------------------------------------