diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/.jscsrc b/.jscsrc
new file mode 100644
index 0000000..649296c
--- /dev/null
+++ b/.jscsrc
@@ -0,0 +1,81 @@
+{
+ "disallowKeywords": ["with"],
+ "disallowKeywordsOnNewLine": ["else"],
+ "disallowMixedSpacesAndTabs": true,
+ "disallowNewlineBeforeBlockStatements": true,
+ "disallowQuotedKeysInObjects": true,
+ "disallowTrailingWhitespace": true,
+
+ "requireCapitalizedConstructors": true,
+ "requireCurlyBraces": [
+ "if",
+ "else",
+ "for",
+ "while",
+ "do",
+ "try",
+ "catch",
+ "function",
+ "switch"
+ ],
+ "requireMultipleVarDecl": true,
+ "requirePaddingNewLineAfterVariableDeclaration": true,
+ "requirePaddingNewLinesAfterBlocks": true,
+ "requirePaddingNewlinesBeforeKeywords": [
+ "if",
+ "for",
+ "while",
+ "do",
+ "switch",
+ "return",
+ "try",
+ "function"
+ ],
+ "requireSpaceBeforeKeywords": [
+ "else",
+ "catch",
+ "while"
+ ],
+ "requireSpaceAfterKeywords": [
+ "if",
+ "else",
+ "for",
+ "while",
+ "do",
+ "switch",
+ "case",
+ "return",
+ "try",
+ "catch",
+ "typeof",
+ "function"
+ ],
+ "requireSpaceAfterLineComment": true,
+ "requireSpaceAfterBinaryOperators": true,
+ "requireSpaceBeforeBinaryOperators": true,
+ "requireOperatorBeforeLineBreak": [
+ "?",
+ "=",
+ "+",
+ "-",
+ "/",
+ "*",
+ "==",
+ "===",
+ "!=",
+ "!==",
+ ">",
+ ">=",
+ "<",
+ "<="
+ ],
+
+ "requireSpaceBeforeBlockStatements": true,
+ "requireSpaceBeforeObjectValues": true,
+ "requireSpacesInFunction": {
+ "beforeOpeningRoundBrace": true,
+ "beforeOpeningCurlyBrace": true
+ },
+ "validateIndentation": 4,
+ "validateLineBreaks": "LF"
+}
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..3b40835
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,56 @@
+{
+ "bitwise" : false,
+ "curly" : true,
+ "eqeqeq" : true,
+ "es3" : false,
+ "forin" : true,
+ "iterator" : true,
+ "latedef" : "nofunc",
+ "maxerr" : 100,
+ "noarg" : true,
+ "nonew" : true,
+ "regexp" : true,
+ "smarttabs" : true,
+ "shadow" : true,
+ "singleGroups" : true,
+ "strict" : false,
+ "undef" : true,
+ "unused" : true,
+ "varstmt" : false,
+
+ "asi" : false,
+ "boss" : false,
+ "debug" : false,
+ "eqnull" : false,
+ "esnext" : true,
+ "evil" : false,
+ "expr" : false,
+ "funcscope" : false,
+ "globalstrict" : false,
+ "lastsemic" : false,
+ "loopfunc" : false,
+ "onecase" : false,
+ "plusplus" : false,
+ "proto" : false,
+ "scripturl" : false,
+ "supernew" : false,
+ "validthis" : false,
+
+ "laxbreak" : true,
+ "laxcomma" : true,
+ "sub" : true,
+ "camelcase" : false,
+ "indent" : false,
+ "immed" : false,
+ "maxlen" : false,
+ "multistr" : false,
+ "newcap" : false,
+ "noempty" : false,
+ "quotmark" : false,
+
+ "browser" : true,
+ "devel" : false,
+ "jasmine" : false,
+ "jquery" : false,
+ "node" : true
+}
diff --git a/README.md b/README.md
index 13ebd74..3757aa2 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,18 @@
# angular-bro
Angular app scaffolding and build chain
+
+## Generators
+```
+yo angular-bro
+yo angular-bro:controller name
+yo angular-bro:directive name
+yo angular-bro:factory name
+yo angular-bro:mock path/to/url
+yo angular-bro:module name
+yo angular-bro:provider name
+yo angular-bro:proxy path/to/url http://domain.com/path/to/proxy
+yo angular-bro:server
+yo angular-bro:service name
+yo angular-bro:state name
+yo angular-bro:template name
+```
diff --git a/generators/app/index.js b/generators/app/index.js
new file mode 100644
index 0000000..8b9a316
--- /dev/null
+++ b/generators/app/index.js
@@ -0,0 +1,146 @@
+var generators = require('yeoman-generator'),
+ _ = require('underscore.string');
+
+module.exports = generators.Base.extend({
+ constructor: function () {
+ generators.Base.apply(this, arguments);
+
+ this.appName = _.camelize(this.appname);
+ this.hyphenName = _.dasherize(this.appName);
+ this.friendlyAppName = _.titleize(_.humanize(this.appName));
+ },
+
+ ask: function () {
+ var done = this.async(),
+ prompts = [{
+ type: 'input',
+ name: 'appName',
+ message: 'name',
+ default: this.hyphenName
+ }];
+
+ this.prompt(prompts, function (props) {
+ this.appName = props.appName;
+
+ done();
+ }.bind(this));
+ },
+
+ writing: {
+ root: function () {
+ this.fs.copy(
+ this.templatePath('.jscsrc'),
+ this.destinationPath('.jscsrc')
+ );
+
+ this.fs.copyTpl(
+ this.templatePath('bower.json'),
+ this.destinationPath('bower.json'),
+ this
+ );
+
+ this.fs.copyTpl(
+ this.templatePath('Brocfile.js'),
+ this.destinationPath('Brocfile.js'),
+ this
+ );
+
+ this.fs.copy(
+ this.templatePath('circle.yml'),
+ this.destinationPath('circle.yml')
+ );
+
+ this.fs.copy(
+ this.templatePath('Gruntfile.js'),
+ this.destinationPath('Gruntfile.js')
+ );
+
+ this.fs.copyTpl(
+ this.templatePath('index.html'),
+ this.destinationPath('index.html'),
+ this
+ );
+
+ this.fs.copy(
+ this.templatePath('karma.conf.js'),
+ this.destinationPath('karma.conf.js')
+ );
+
+ this.fs.copyTpl(
+ this.templatePath('package.json'),
+ this.destinationPath('package.json'),
+ this
+ );
+ },
+
+ app: function () {
+ this.fs.copyTpl(
+ this.templatePath('app/app.js'),
+ this.destinationPath('app/app.js'),
+ this
+ );
+ },
+
+ assets: function () {
+ this.fs.copy(
+ this.templatePath('assets/.gitkeep'),
+ this.destinationPath('assets/.gitkeep')
+ );
+ },
+
+ config: function () {
+ this.fs.copy(
+ this.templatePath('config/environment.js'),
+ this.destinationPath('config/environment.js')
+ );
+ },
+
+ styles: function () {
+ this.fs.copy(
+ this.templatePath('styles/app.less'),
+ this.destinationPath('styles/app.less')
+ );
+
+ this.fs.copy(
+ this.templatePath('styles/_colors.less'),
+ this.destinationPath('styles/_colors.less')
+ );
+
+ this.fs.copy(
+ this.templatePath('styles/_mixins.less'),
+ this.destinationPath('styles/_mixins.less')
+ );
+
+ this.fs.copy(
+ this.templatePath('styles/_variables.less'),
+ this.destinationPath('styles/_variables.less')
+ );
+ },
+
+ tests: function () {
+ this.fs.copy(
+ this.templatePath('tests/e2e/.gitkeep'),
+ this.destinationPath('tests/e2e/.gitkeep')
+ );
+
+ this.fs.copy(
+ this.templatePath('tests/helpers/afterAll.js'),
+ this.destinationPath('tests/helpers/afterAll.js')
+ );
+
+ this.fs.copy(
+ this.templatePath('tests/helpers/beforeAll.js'),
+ this.destinationPath('tests/helpers/beforeAll.js')
+ );
+
+ this.fs.copy(
+ this.templatePath('tests/unit/.gitkeep'),
+ this.destinationPath('tests/unit/.gitkeep')
+ );
+ }
+ },
+
+ end: function () {
+ this.installDependencies();
+ }
+});
diff --git a/generators/app/templates/.jscsrc b/generators/app/templates/.jscsrc
new file mode 100644
index 0000000..89faa8b
--- /dev/null
+++ b/generators/app/templates/.jscsrc
@@ -0,0 +1,17 @@
+{
+ "disallowMixedSpacesAndTabs": true,
+ "disallowTrailingWhitespace": true,
+ "validateIndentation": 4,
+ "validateLineBreaks": "LF",
+ "requireCurlyBraces": [
+ "if",
+ "else",
+ "for",
+ "while",
+ "do",
+ "try",
+ "catch",
+ "function",
+ "switch"
+ ]
+}
diff --git a/generators/app/templates/Brocfile.js b/generators/app/templates/Brocfile.js
new file mode 100644
index 0000000..b289101
--- /dev/null
+++ b/generators/app/templates/Brocfile.js
@@ -0,0 +1,8 @@
+var AngularApp = require('angular-bro-app'),
+ app = new AngularApp();
+
+// Use `app.importScript` or `app.importStyle` to add additional
+// libraries to the generated output files.
+
+
+module.exports = app.toTree();
diff --git a/generators/app/templates/Gruntfile.js b/generators/app/templates/Gruntfile.js
new file mode 100644
index 0000000..9eb5073
--- /dev/null
+++ b/generators/app/templates/Gruntfile.js
@@ -0,0 +1,102 @@
+module.exports = function (grunt) {
+ "use strict";
+
+ var environment = grunt.option('environment') || 'development';
+
+ switch (environment) {
+ case 'production':
+ break;
+ case 'development':
+ break;
+ default:
+ console.log('Could not map environment `' + environment + '`');
+ console.log('Defaulting to `development`');
+ environment = 'development';
+ break;
+ }
+ process.env.ANGULAR_ENV = environment;
+
+ grunt.task.loadNpmTasks('grunt-contrib-clean');
+ grunt.task.loadNpmTasks('grunt-broccoli');
+ grunt.task.loadNpmTasks('grunt-bump');
+ grunt.task.loadNpmTasks('grunt-exec');
+ grunt.task.loadNpmTasks('grunt-express-server');
+
+ grunt.initConfig({
+ config: {
+ destDir: 'dist/'
+ },
+ clean: {
+ options : { force: true },
+ dist : [ '<%= config.destDir %>' ],
+ tmp : [ 'tmp' ]
+ },
+ broccoli: {
+ dist: {
+ dest: '<%= config.destDir %>',
+ }
+ },
+ bump: {
+ options: {
+ files : [ 'bower.json', 'package.json' ],
+ commitFiles : [ 'bower.json', 'package.json' ],
+ commitMessage : 'Bumped version to: %VERSION%',
+ createTag : false,
+ push : false,
+
+ }
+ },
+ exec: {
+ updateWebdriver: {
+ cmd: 'npm run update-webdriver'
+ },
+ broccoliTest: {
+ cmd: 'npm test'
+ }
+ },
+ express: {
+ options: {
+ port : 4200,
+ script : 'node_modules/angular-bro-app/lib/server.js'
+ },
+ e2e: {
+ options: {
+ background: true
+ }
+ },
+ server: {
+ options: {
+ background: false,
+ }
+ }
+ }
+ });
+
+ grunt.registerTask('default', 'Builds the angular app.', 'build');
+
+ grunt.registerTask('build', 'Builds the angular app', 'broccoli:dist:build');
+
+ grunt.registerTask('serve', 'Builds and launches a server for the app.', 'server');
+ grunt.registerTask('server', 'Builds and launches a server for the app.', function () {
+ process.env.ANGULAR_SERVER = true;
+ process.env.ANGULAR_DEST_DIR = grunt.config('config').destDir;
+
+ grunt.task.run([
+ 'clean',
+ 'express:server'
+ ]);
+ });
+
+ grunt.registerTask('test', 'Builds and runs unit tests.', function () {
+ var broccoliType = 'build';
+
+ process.env.ANGULAR_TEST = true;
+
+ if (!!grunt.option('server')) {
+ broccoliType = 'server';
+ process.env.ANGULAR_SERVER = true;
+ }
+
+ grunt.task.run(broccoliType);
+ });
+};
diff --git a/generators/app/templates/app/app.js b/generators/app/templates/app/app.js
new file mode 100644
index 0000000..144fac3
--- /dev/null
+++ b/generators/app/templates/app/app.js
@@ -0,0 +1,20 @@
+import angular from 'angular';
+import config from 'config/environment';
+import 'app/scripts/templates';
+
+var app = angular.module('<%= appName %>', [
+ 'templates-app'
+]).config(function ($locationProvider) {
+ "ngInject";
+ "use strict";
+
+ $locationProvider.html5Mode(config.html5Mode);
+});
+
+angular.element(document).ready(function () {
+ angular.bootstrap(document, [
+ app.name
+ ], {
+ strictDi: true
+ });
+});
diff --git a/generators/app/templates/assets/.gitkeep b/generators/app/templates/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/generators/app/templates/bower.json b/generators/app/templates/bower.json
new file mode 100644
index 0000000..b5acd1b
--- /dev/null
+++ b/generators/app/templates/bower.json
@@ -0,0 +1,25 @@
+{
+ "name": "<%= hyphenName %>",
+ "version": "0.0.0",
+ "description": "",
+ "main": "app/app.js",
+ "authors": [],
+ "license": "MIT",
+ "moduleType": [],
+ "homepage": "",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "dependencies": {
+ "angular": "1.5.0",
+ "angular-shim": "2.0.0",
+ "loader.js": "4.0.1"
+ },
+ "devDependencies": {
+ "angular-mocks": "1.5.0"
+ }
+}
diff --git a/generators/app/templates/circle.yml b/generators/app/templates/circle.yml
new file mode 100644
index 0000000..f9473bb
--- /dev/null
+++ b/generators/app/templates/circle.yml
@@ -0,0 +1,11 @@
+machine:
+ node:
+ version: 5.1.0
+
+dependencies:
+ override:
+ - npm install
+
+test:
+ override:
+ - npm test
diff --git a/generators/app/templates/config/environment.js b/generators/app/templates/config/environment.js
new file mode 100644
index 0000000..68a06b0
--- /dev/null
+++ b/generators/app/templates/config/environment.js
@@ -0,0 +1,24 @@
+module.exports = function (environment) {
+ 'use strict';
+
+ var ENV = {
+ environment: environment,
+ html5Mode: true,
+ routes: {}
+ };
+
+ if (environment === 'development') {
+
+ }
+
+ if (environment === 'test') {
+ // Karma prefers this
+ ENV.html5Mode = false;
+ }
+
+ if (environment === 'production') {
+
+ }
+
+ return ENV;
+};
diff --git a/generators/app/templates/index.html b/generators/app/templates/index.html
new file mode 100644
index 0000000..69cb922
--- /dev/null
+++ b/generators/app/templates/index.html
@@ -0,0 +1,20 @@
+
+
+
+ <%= friendlyAppName %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/generators/app/templates/karma.conf.js b/generators/app/templates/karma.conf.js
new file mode 100644
index 0000000..43724fc
--- /dev/null
+++ b/generators/app/templates/karma.conf.js
@@ -0,0 +1,20 @@
+module.exports = function (config) {
+ 'use strict';
+ /**
+ * WARNING: No not set the following properties. They will be
+ * overwritten in the execution of the karma tests:
+ * - files
+ * - exclude
+ * - autoWatch
+ * - singleRun
+ */
+ var configuration = {
+ browsers : [ 'PhantomJS' ],
+ frameworks : [ 'jasmine' ],
+ reporters : [ 'dots', 'coverage'],
+ preprocessors : { 'app/**/*.js': 'coverage' },
+ coverageReporter : { type: 'text' }
+ };
+
+ config.set(configuration);
+};
diff --git a/generators/app/templates/package.json b/generators/app/templates/package.json
new file mode 100644
index 0000000..68c869b
--- /dev/null
+++ b/generators/app/templates/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "<%= hyphenName %>",
+ "version": "0.0.0",
+ "description": "",
+ "main": "app/app.js",
+ "scripts": {
+ "pretest": "rm -rf .tmp",
+ "test": "ANGULAR_TEST=true broccoli build .tmp"
+ },
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "angular-bro-app": "0.4.1",
+ "grunt": "0.4.5",
+ "grunt-broccoli": "0.4.1",
+ "grunt-bump": "0.7.0",
+ "grunt-contrib-clean": "1.0.0",
+ "grunt-exec": "0.4.6",
+ "grunt-express-server": "0.5.2"
+ }
+}
diff --git a/generators/app/templates/styles/_colors.less b/generators/app/templates/styles/_colors.less
new file mode 100644
index 0000000..e69de29
diff --git a/generators/app/templates/styles/_mixins.less b/generators/app/templates/styles/_mixins.less
new file mode 100644
index 0000000..e69de29
diff --git a/generators/app/templates/styles/_variables.less b/generators/app/templates/styles/_variables.less
new file mode 100644
index 0000000..e69de29
diff --git a/generators/app/templates/styles/app.less b/generators/app/templates/styles/app.less
new file mode 100644
index 0000000..e883d40
--- /dev/null
+++ b/generators/app/templates/styles/app.less
@@ -0,0 +1,7 @@
+@import '_variables.less';
+@import '_colors.less';
+@import '_mixins.less';
+
+html {
+ font-size: 62.5%;
+}
diff --git a/generators/app/templates/tests/e2e/.gitkeep b/generators/app/templates/tests/e2e/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/generators/app/templates/tests/helpers/afterAll.js b/generators/app/templates/tests/helpers/afterAll.js
new file mode 100644
index 0000000..3c69cc8
--- /dev/null
+++ b/generators/app/templates/tests/helpers/afterAll.js
@@ -0,0 +1,10 @@
+afterAll(function () {
+ "use strict";
+
+ /**
+ * Testing Teardown happens here
+ *
+ * Usually this would be used to remove anything persistent
+ * that was added during testing.
+ */
+});
diff --git a/generators/app/templates/tests/helpers/beforeAll.js b/generators/app/templates/tests/helpers/beforeAll.js
new file mode 100644
index 0000000..8676ed3
--- /dev/null
+++ b/generators/app/templates/tests/helpers/beforeAll.js
@@ -0,0 +1,12 @@
+beforeAll(function () {
+ "use strict";
+
+ /**
+ * Testing setup happens here.
+ *
+ * Usually you will put anything that needs to be shared between tests,
+ * such as registering helpers with angular, or mock servers. These might
+ * require cleanup after all testing has completed by using the `afterAll`
+ * helper.
+ */
+});
diff --git a/generators/app/templates/tests/unit/.gitkeep b/generators/app/templates/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/generators/controller/index.js b/generators/controller/index.js
new file mode 100644
index 0000000..8bd84ce
--- /dev/null
+++ b/generators/controller/index.js
@@ -0,0 +1,27 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Controller',
+ fromDirective: false,
+ fromState: false,
+
+ writing: {
+ module: function () {
+ this.composeWith('angular-bro:module', {
+ args: [this.componentPath],
+ options: {
+ fromController: true,
+ fromState: this.fromState,
+ fromDirective: this.fromDirective
+ }
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/controller/templates/controller.js b/generators/controller/templates/controller.js
new file mode 100644
index 0000000..0c3ed37
--- /dev/null
+++ b/generators/controller/templates/controller.js
@@ -0,0 +1,7 @@
+function Controller () {
+ 'use strict';
+ 'ngInject';
+
+}
+
+exports.controller = Controller;
diff --git a/generators/controller/templates/controller.spec.js b/generators/controller/templates/controller.spec.js
new file mode 100644
index 0000000..b919e4b
--- /dev/null
+++ b/generators/controller/templates/controller.spec.js
@@ -0,0 +1,21 @@
+import 'app/<%= componentPath %>/module';
+
+describe('<%= classComponentName %> <%= componentType %>', function () {
+ 'use strict';
+
+ var $controller;
+
+ beforeEach(module('<%= componentName %>'));
+
+ beforeEach(inject(function (_$controller_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $controller = _$controller_;
+ }));
+
+ it('exists', inject(function ($controller) {
+ var controller = $controller('<%= classComponentName %>Ctrl', {
+ });
+
+ expect(controller).toBeDefined();
+ }));
+});
diff --git a/generators/directive/index.js b/generators/directive/index.js
new file mode 100644
index 0000000..685cbba
--- /dev/null
+++ b/generators/directive/index.js
@@ -0,0 +1,116 @@
+var generators = require('yeoman-generator'),
+ parseComponentName = require('../../lib/parse-component-name'),
+ _ = require('underscore.string');
+
+module.exports = generators.Base.extend({
+ componentType: 'Directive',
+
+ constructor: function (componentPath, options) {
+ generators.Base.apply(this, arguments);
+
+ this.argument('componentPath', {
+ type : String,
+ desc : this.componentType + ' path and name (e.g. `user` or a nested `account/user`)',
+ required : false
+ });
+
+ if (this.componentPath !== undefined) {
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+
+ this.hyphenComponentName = _.dasherize(this.componentName);
+
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+ }
+ },
+
+ ask: function () {
+ var prompts = [{
+ type : 'input',
+ name : 'componentPath',
+ message : this.componentType + ' name',
+ validate : function (componentPath) {
+ if (!componentPath) {
+ return this.componentType + ' name is required';
+ }
+
+ return true;
+ }.bind(this)
+ }],
+ done;
+
+ if (this.componentName !== undefined) {
+ return;
+ }
+
+ done = this.async();
+ this.prompt(prompts, function (props) {
+ this.componentPath = props.componentPath;
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+
+ this.hyphenComponentName = _.dasherize(this.componentName);
+
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+
+ done();
+ }.bind(this));
+ },
+
+ writing: {
+ component: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.js'),
+ this.destinationPath('app/' + this.componentPath + '/' + componentLowerCase + '.js'),
+ this
+ );
+ },
+
+ componentTest: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ if (this.generateTest === false) {
+ return;
+ }
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.spec.js'),
+ this.destinationPath('tests/unit/' + this.componentPath + '/' + componentLowerCase + '.spec.js'),
+ this
+ );
+ },
+
+ // module: function () {
+ // this.composeWith('angular-bro:module', {
+ // args: [this.componentPath]
+ // }, {
+ // link: 'weak'
+ // });
+ // },
+
+ controller: function () {
+ this.composeWith('angular-bro:controller', {
+ args: [this.componentPath],
+ options: {
+ fromDirective: true
+ }
+ }, {
+ link: 'weak'
+ });
+ },
+
+ template: function () {
+ this.composeWith('angular-bro:template', {
+ args: [this.componentPath]
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
diff --git a/generators/directive/templates/directive.js b/generators/directive/templates/directive.js
new file mode 100644
index 0000000..04ddedc
--- /dev/null
+++ b/generators/directive/templates/directive.js
@@ -0,0 +1,16 @@
+import { controller } from 'app/<%= componentPath %>/controller';
+
+function Directive () {
+ 'use strict';
+ 'ngInject';
+
+ return {
+
+ restrict: 'AECM',
+ templateUrl: '<%= componentPath %>/template.html',
+ controller: controller
+
+ };
+}
+
+exports.directive = Directive;
diff --git a/generators/directive/templates/directive.spec.js b/generators/directive/templates/directive.spec.js
new file mode 100644
index 0000000..eaa1018
--- /dev/null
+++ b/generators/directive/templates/directive.spec.js
@@ -0,0 +1,37 @@
+import 'app/scripts/templates';
+import 'app/<%= componentPath %>/module';
+
+describe('<%= componentName %> <%= componentType %>', function () {
+ 'use strict';
+
+ var $compile, $rootScope;
+
+ beforeEach(module('templates-app'));
+ beforeEach(module('<%= componentName %>'));
+
+ beforeEach(inject(function (_$compile_, _$rootScope_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $compile = _$compile_;
+ $rootScope = _$rootScope_.$new();
+ }));
+
+ it('exists', inject(function () {
+ var element = $compile("<<%= hyphenComponentName %>><%= hyphenComponentName %>>")($rootScope);
+
+ // fire all the watches, so the scope expressions will be evaluated
+ $rootScope.$digest();
+
+ // Check that the compiled element contains the templated content
+ expect(element.html()).not.toContain('<<%= hyphenComponentName %>><%= hyphenComponentName %>>');
+ }));
+
+ it('replaces html', inject(function () {
+ var element = $compile("<<%= hyphenComponentName %>><%= hyphenComponentName %>>")($rootScope);
+
+ // fire all the watches, so the scope expressions will be evaluated
+ $rootScope.$digest();
+
+ expect(element.find('div')).toBeDefined();
+ expect(element.find('div').text()).toEqual('<%= componentName %>');
+ }));
+});
diff --git a/generators/factory/index.js b/generators/factory/index.js
new file mode 100644
index 0000000..25840dd
--- /dev/null
+++ b/generators/factory/index.js
@@ -0,0 +1,23 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Factory',
+
+ writing: {
+ module: function () {
+ this.composeWith('angular-bro:module', {
+ args: [this.componentPath],
+ options: {
+ fromFactory: true,
+ }
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/factory/templates/factory.js b/generators/factory/templates/factory.js
new file mode 100644
index 0000000..1bb6d8c
--- /dev/null
+++ b/generators/factory/templates/factory.js
@@ -0,0 +1,8 @@
+function Factory () {
+ 'use strict';
+ 'ngInject';
+
+ return {};
+}
+
+exports.factory = Factory;
diff --git a/generators/factory/templates/factory.spec.js b/generators/factory/templates/factory.spec.js
new file mode 100644
index 0000000..f1d3b9e
--- /dev/null
+++ b/generators/factory/templates/factory.spec.js
@@ -0,0 +1,18 @@
+import 'app/<%= componentPath %>/module';
+
+describe('<%= classComponentName %> <%= componentType %>', function () {
+ 'use strict';
+
+ var $factory;
+
+ beforeEach(module('<%= componentName %>'));
+
+ beforeEach(inject(function (_<%= componentName %>_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $factory = _<%= componentName %>_;
+ }));
+
+ it('exists', inject(function () {
+ expect($factory).toBeDefined();
+ }));
+});
diff --git a/generators/mock/index.js b/generators/mock/index.js
new file mode 100644
index 0000000..2578e5c
--- /dev/null
+++ b/generators/mock/index.js
@@ -0,0 +1,20 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Mock',
+
+ writing: {
+ component: function () {
+ this.fs.copyTpl(
+ this.templatePath('mock.js'),
+ this.destinationPath('server/mocks/' + this.componentPath + '.js'),
+ this
+ );
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/mock/templates/mock.js b/generators/mock/templates/mock.js
new file mode 100644
index 0000000..9dd6e54
--- /dev/null
+++ b/generators/mock/templates/mock.js
@@ -0,0 +1,46 @@
+module.exports = function (app) {
+ var express = require('express'),
+ router = express.Router();
+
+ router.get('/', function (req, res) {
+ res.send({
+ '<%= componentName %>': []
+ });
+ });
+
+ router.post('/', function (req, res) {
+ res.status(201).end();
+ });
+
+ router.get('/:id', function (req, res) {
+ res.send({
+ '<%= componentName %>': {
+ id: req.params.id
+ }
+ });
+ });
+
+ router.put('/:id', function (req, res) {
+ res.send({
+ '<%= componentName %>': {
+ id: req.params.id
+ }
+ });
+ });
+
+ router.delete('/:id', function (req, res) {
+ res.status(204).end();
+ });
+
+ // The POST and PUT call will not contain a request body
+ // because the body-parser is not included by default.
+ // To use req.body, run:
+
+ // npm install --save-dev body-parser
+
+ // After installing, you need to `use` the body-parser for
+ // this mock uncommenting the following line:
+ //
+ // app.use('/api/<%= componentName %>', require('body-parser').json());
+ app.use('/api/<%= componentName %>', router);
+};
diff --git a/generators/module/index.js b/generators/module/index.js
new file mode 100644
index 0000000..8af036f
--- /dev/null
+++ b/generators/module/index.js
@@ -0,0 +1,14 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Module',
+ generateTest: false,
+ fromState: false,
+ fromDirective: false,
+ fromController: false
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/module/templates/module.js b/generators/module/templates/module.js
new file mode 100644
index 0000000..2c5b749
--- /dev/null
+++ b/generators/module/templates/module.js
@@ -0,0 +1,40 @@
+import angular from 'angular';
+<% if (fromState === true) { -%>
+import { state } from 'app/<%= componentPath %>/state';
+<% } -%>
+<% if (fromDirective === true) { -%>
+import { directive } from 'app/<%= componentPath %>/directive';
+<% } -%>
+<% if (fromController === true) { -%>
+import { controller } from 'app/<%= componentPath %>/controller';
+<% } -%>
+<% if (fromService === true) { -%>
+import { service } from 'app/<%= componentPath %>/service';
+<% } -%>
+<% if (fromFactory === true) { -%>
+import { factory } from 'app/<%= componentPath %>/factory';
+<% } -%>
+<% if (fromProvider === true) { -%>
+import { provider } from 'app/<%= componentPath %>/provider';
+<% } -%>
+
+export default angular.module('<%= componentName %>', [])
+<% if (fromState === true) { -%>
+ .config(state)
+<% } -%>
+<% if (fromDirective === true) { -%>
+ .directive('<%= componentName %>', directive)
+<% } -%>
+<% if (fromController === true) { -%>
+ .controller('<%= classComponentName %>Ctrl', controller)
+<% } -%>
+<% if (fromService === true) { -%>
+ .service('<%= classComponentName %>', service)
+<% } -%>
+<% if (fromFactory === true) { -%>
+ .factory('<%= componentName %>', factory)
+<% } -%>
+<% if (fromProvider === true) { -%>
+ .provider('<%= componentName %>', provider)
+<% } -%>
+; // Ends the module declaration
diff --git a/generators/provider/index.js b/generators/provider/index.js
new file mode 100644
index 0000000..50413c5
--- /dev/null
+++ b/generators/provider/index.js
@@ -0,0 +1,23 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Provider',
+
+ writing: {
+ module: function () {
+ this.composeWith('angular-bro:module', {
+ args: [this.componentPath],
+ options: {
+ fromProvider: true,
+ }
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/provider/templates/provider.js b/generators/provider/templates/provider.js
new file mode 100644
index 0000000..03bb0af
--- /dev/null
+++ b/generators/provider/templates/provider.js
@@ -0,0 +1,10 @@
+function Provider () {
+ 'use strict';
+ 'ngInject';
+
+ this.$get = function () {
+
+ };
+}
+
+exports.provider = Provider;
diff --git a/generators/provider/templates/provider.spec.js b/generators/provider/templates/provider.spec.js
new file mode 100644
index 0000000..1179951
--- /dev/null
+++ b/generators/provider/templates/provider.spec.js
@@ -0,0 +1,19 @@
+import 'app/<%= componentPath %>/module';
+
+describe('<%= classComponentName %> <%= componentType %>', function () {
+ 'use strict';
+
+ var $provider;
+
+ beforeEach(module('<%= componentName %>'));
+
+ beforeEach(inject(function (_<%= componentName %>_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $provider = _<%= componentName %>_;
+ console.log($provider);
+ }));
+
+ it('exists', inject(function () {
+ expect($provider).toBeDefined();
+ }));
+});
diff --git a/generators/proxy/index.js b/generators/proxy/index.js
new file mode 100644
index 0000000..3b420b7
--- /dev/null
+++ b/generators/proxy/index.js
@@ -0,0 +1,65 @@
+var generators = require('yeoman-generator'),
+ parseComponentName = require('../../lib/parse-component-name');
+
+module.exports = generators.Base.extend({
+ componentType: 'Proxy',
+
+ constructor: function () {
+ generators.Base.apply(this, arguments);
+
+ this.argument('proxyPath', {
+ type : String,
+ desc : this.componentType + ' relative path and name (e.g. `/user` or a nested `/account/user`)',
+ required : false
+ });
+
+ this.argument('proxyTarget', {
+ type : String,
+ desc : this.componentType + ' target path and name (e.g. `http://localhost/api/v1/user/`)',
+ required : false
+ });
+
+ if (this.componentPath !== undefined) {
+ this.componentName = parseComponentName.call(this, this.componentPath);
+ }
+ },
+
+ ask: function () {
+ var prompts = [{
+ type : 'input',
+ name : 'componentPath',
+ message : this.componentType + ' name',
+ validate : function (componentPath) {
+ if (!componentPath) {
+ return this.componentType + ' name is required';
+ }
+
+ return true;
+ }.bind(this)
+ }],
+ done;
+
+ if (this.componentName !== undefined) {
+ return;
+ }
+
+ done = this.async();
+ this.prompt(prompts, function (props) {
+ this.componentPath = props.componentPath;
+ this.componentName = parseComponentName.call(this, props.componentPath);
+ done();
+ }.bind(this));
+ },
+
+ writing: {
+ component: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.js'),
+ this.destinationPath('app/' + this.componentPath + '/' + componentLowerCase + '.js'),
+ this
+ );
+ }
+ }
+});
diff --git a/generators/proxy/templates/proxy.js b/generators/proxy/templates/proxy.js
new file mode 100644
index 0000000..df254b5
--- /dev/null
+++ b/generators/proxy/templates/proxy.js
@@ -0,0 +1,17 @@
+var proxyPath = '<%= componentPath %>';
+
+module.exports = function (app) {
+ // For options, see:
+ // https://github.com/nodejitsu/node-http-proxy
+ var proxy = require('http-proxy').createProxyServer({});
+
+ proxy.on('error', function (err, req) {
+ console.error(err, req.url);
+ });
+
+ app.use(proxyPath, function (req, res/*, next*/) {
+ // include root path in proxied request
+ req.url = proxyPath + '/' + req.url;
+ proxy.web(req, res, { target: '<%= proxyTarget %>' });
+ });
+};
diff --git a/generators/server/index.js b/generators/server/index.js
new file mode 100644
index 0000000..a656159
--- /dev/null
+++ b/generators/server/index.js
@@ -0,0 +1,30 @@
+var generators = require('yeoman-generator');
+
+module.exports = generators.Base.extend({
+ constructor: function () {
+ generators.Base.apply(this, arguments);
+ },
+
+ writing: {
+ server: function () {
+ this.fs.copy(
+ this.templatePath('index.js'),
+ this.destinationPath('server/index.js')
+ );
+
+ this.fs.copy(
+ this.templatePath('.gitkeep'),
+ this.destinationPath('server/mocks/.gitkeep')
+ );
+
+ this.fs.copy(
+ this.templatePath('.gitkeep'),
+ this.destinationPath('server/proxies/.gitkeep')
+ );
+ }
+ },
+
+ end: function () {
+ this.npmInstall(['morgan@1.7.0'], { saveDev: true });
+ }
+});
diff --git a/generators/server/templates/.gitkeep b/generators/server/templates/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/generators/server/templates/index.js b/generators/server/templates/index.js
new file mode 100644
index 0000000..487f52e
--- /dev/null
+++ b/generators/server/templates/index.js
@@ -0,0 +1,22 @@
+// To use it create some files under `routes/`
+// e.g. `server/routes/users.js`
+//
+// module.exports = function(app) {
+// app.get('/users', function(req, res) {
+// res.send('hello');
+// });
+// };
+
+module.exports = function (app, config) {
+ var globSync = require('glob').sync,
+ mocks = globSync('./mocks/**/*.js', { cwd: __dirname }).map(require),
+ proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map(require),
+ morgan = require('morgan');
+
+ app.use(morgan('dev'));
+
+ // Enable mock data
+ mocks.forEach(function (route) { route(app); });
+ // Enable proxies
+ proxies.forEach(function (route) { route(app); });
+};
diff --git a/generators/service/index.js b/generators/service/index.js
new file mode 100644
index 0000000..4dfbd12
--- /dev/null
+++ b/generators/service/index.js
@@ -0,0 +1,23 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Service',
+
+ writing: {
+ module: function () {
+ this.composeWith('angular-bro:module', {
+ args: [this.componentPath],
+ options: {
+ fromService: true,
+ }
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/service/templates/service.js b/generators/service/templates/service.js
new file mode 100644
index 0000000..ee385ce
--- /dev/null
+++ b/generators/service/templates/service.js
@@ -0,0 +1,7 @@
+function Service () {
+ 'use strict';
+ 'ngInject';
+
+}
+
+exports.service = Service;
diff --git a/generators/service/templates/service.spec.js b/generators/service/templates/service.spec.js
new file mode 100644
index 0000000..3ef74d3
--- /dev/null
+++ b/generators/service/templates/service.spec.js
@@ -0,0 +1,18 @@
+import 'app/<%= componentPath %>/module';
+
+describe('<%= classComponentName %> <%= componentType %>', function () {
+ 'use strict';
+
+ var $service;
+
+ beforeEach(module('<%= componentName %>'));
+
+ beforeEach(inject(function (_<%= classComponentName %>_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $service = _<%= classComponentName %>_;
+ }));
+
+ it('exists', inject(function () {
+ expect($service).toBeDefined();
+ }));
+});
diff --git a/generators/state/index.js b/generators/state/index.js
new file mode 100644
index 0000000..a050863
--- /dev/null
+++ b/generators/state/index.js
@@ -0,0 +1,96 @@
+var generators = require('yeoman-generator'),
+ parseComponentName = require('../../lib/parse-component-name'),
+ _ = require('underscore.string');
+
+module.exports = generators.Base.extend({
+ componentType: 'State',
+
+ constructor: function () {
+ generators.Base.apply(this, arguments);
+
+ this.argument('componentPath', {
+ type : String,
+ desc : this.componentType + ' relative path and name (e.g. `user` or a nested `account/user`)',
+ required : false
+ });
+
+ if (this.componentPath !== undefined) {
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+ }
+ },
+
+ ask: function () {
+ var prompts = [{
+ type : 'input',
+ name : 'componentPath',
+ message : this.componentType + ' name',
+ validate : function (componentPath) {
+ if (!componentPath) {
+ return this.componentType + ' name is required';
+ }
+
+ return true;
+ }.bind(this)
+ }],
+ done;
+
+ if (this.componentName !== undefined) {
+ return;
+ }
+
+ done = this.async();
+ this.prompt(prompts, function (props) {
+ this.componentPath = props.componentPath;
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+
+ done();
+ }.bind(this));
+ },
+
+ writing: {
+ component: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.js'),
+ this.destinationPath('app/' + this.componentPath + '/' + componentLowerCase + '.js'),
+ this
+ );
+ },
+
+ // module: function () {
+ // this.composeWith('angular-bro:module', {
+ // args: [this.componentPath]
+ // }, {
+ // link: 'weak'
+ // });
+ // },
+
+ controller: function () {
+ this.composeWith('angular-bro:controller', {
+ args: [this.componentPath],
+ options: {
+ fromState: true
+ }
+ }, {
+ link: 'weak'
+ });
+ },
+
+ template: function () {
+ this.composeWith('angular-bro:template', {
+ args: [this.componentPath]
+ }, {
+ link: 'weak'
+ });
+ }
+ }
+});
diff --git a/generators/state/templates/state.js b/generators/state/templates/state.js
new file mode 100644
index 0000000..5c06ee4
--- /dev/null
+++ b/generators/state/templates/state.js
@@ -0,0 +1,14 @@
+import { controller } from 'app/<%= componentPath %>/controller';
+
+function State ($stateProvider) {
+ 'use strict';
+ 'ngInject';
+
+ $stateProvider.state('<%= componentPath %>', {
+ url: '/<%= componentPath %>',
+ templateUrl: '<%= componentPath %>/template.html',
+ controller: controller
+ });
+}
+
+exports.state = State;
diff --git a/generators/state/templates/state.spec.js b/generators/state/templates/state.spec.js
new file mode 100644
index 0000000..e69de29
diff --git a/generators/template/index.js b/generators/template/index.js
new file mode 100644
index 0000000..fcfdab9
--- /dev/null
+++ b/generators/template/index.js
@@ -0,0 +1,22 @@
+var baseComponent = require('../../lib/base-component'),
+ generators = require('yeoman-generator'),
+ extend = require('extend'),
+ generator;
+
+generator = extend(true, {}, baseComponent, {
+ componentType: 'Template',
+ generateTest: false,
+ writing: {
+ component: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.html'),
+ this.destinationPath('app/' + this.componentPath + '/' + componentLowerCase + '.html'),
+ this
+ );
+ }
+ }
+});
+
+module.exports = generators.Base.extend(generator);
diff --git a/generators/template/templates/template.html b/generators/template/templates/template.html
new file mode 100644
index 0000000..5c18d8b
--- /dev/null
+++ b/generators/template/templates/template.html
@@ -0,0 +1 @@
+<%= componentName %>
diff --git a/lib/base-component.js b/lib/base-component.js
new file mode 100644
index 0000000..284a832
--- /dev/null
+++ b/lib/base-component.js
@@ -0,0 +1,102 @@
+var generators = require('yeoman-generator'),
+ parseComponentName = require('./parse-component-name'),
+ _ = require('underscore.string');
+
+module.exports = {
+ generateTest: true,
+ fromState: false,
+ fromDirective: false,
+ fromController: false,
+ fromService: false,
+ fromFactory: false,
+ fromProvider: false,
+
+ constructor: function (componentPath, options) {
+ generators.Base.apply(this, arguments);
+
+ this.fromState = options.fromState;
+ this.fromDirective = options.fromDirective;
+ this.fromController = options.fromController;
+ this.fromService = options.fromService;
+ this.fromFactory = options.fromFactory;
+ this.fromProvider = options.fromProvider;
+
+ this.argument('componentPath', {
+ type : String,
+ desc : this.componentType + ' path and name (e.g. `user` or a nested `account/user`)',
+ required : false
+ });
+
+ if (this.componentPath !== undefined) {
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+
+ this.hyphenComponentName = _.dasherize(this.componentName);
+
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+ }
+ },
+
+ ask: function () {
+ var prompts = [{
+ type : 'input',
+ name : 'componentPath',
+ message : this.componentType + ' name',
+ validate : function (componentPath) {
+ if (!componentPath) {
+ return this.componentType + ' name is required';
+ }
+
+ return true;
+ }.bind(this)
+ }],
+ done;
+
+ if (this.componentName !== undefined) {
+ return;
+ }
+
+ done = this.async();
+ this.prompt(prompts, function (props) {
+ this.componentPath = props.componentPath;
+ this.componentPath = _.dasherize(this.componentPath);
+
+ this.componentName = parseComponentName.call(this, this.componentPath);
+
+ this.hyphenComponentName = _.dasherize(this.componentName);
+
+ this.classComponentName = _.classify(this.componentName);
+ this.componentName = _.camelize(this.componentName);
+
+ done();
+ }.bind(this));
+ },
+
+ writing: {
+ component: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.js'),
+ this.destinationPath('app/' + this.componentPath + '/' + componentLowerCase + '.js'),
+ this
+ );
+ },
+
+ componentTest: function () {
+ var componentLowerCase = this.componentType.toLowerCase();
+
+ if (this.generateTest === false) {
+ return;
+ }
+
+ this.fs.copyTpl(
+ this.templatePath(componentLowerCase + '.spec.js'),
+ this.destinationPath('tests/unit/' + this.componentPath + '/' + componentLowerCase + '.spec.js'),
+ this
+ );
+ }
+ }
+};
diff --git a/lib/parse-component-name.js b/lib/parse-component-name.js
new file mode 100644
index 0000000..1c7a88b
--- /dev/null
+++ b/lib/parse-component-name.js
@@ -0,0 +1,16 @@
+/**
+ * To be called in context of a generator instance.
+ *
+ * @param {String} componentPath path to parse name from
+ *
+ * @returns {String} component name
+ */
+module.exports = function (componentPath) {
+ var pieces = componentPath.split('/');
+
+ if (!componentPath || typeof componentPath !== 'string') {
+ this.env.error('Must provide the name of the ' + this.componentType.toLowerCase() + ' to be created');
+ }
+
+ return pieces.pop();
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..4c9bca0
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "generator-angular-bro",
+ "version": "0.1.0",
+ "description": "Angular app scaffolding and build chain",
+ "main": "generators/app/index.js",
+ "files": [
+ "generators/app",
+ "generators/controller",
+ "generators/directive",
+ "generators/factory",
+ "generators/mock",
+ "generators/module",
+ "generators/provider",
+ "generators/proxy",
+ "generators/server",
+ "generators/service",
+ "generators/state",
+ "generators/template"
+ ],
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/adambullmer/generator-angular-bro.git"
+ },
+ "keywords": [
+ "yeoman-generator",
+ "angular",
+ "broccoli",
+ "es6"
+ ],
+ "author": "Adam Bullmer ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/adambullmer/generator-angular-bro/issues"
+ },
+ "homepage": "https://github.com/adambullmer/generator-angular-bro#readme",
+ "dependencies": {
+ "extend": "^3.0.0",
+ "generator-node": "^1.10.0",
+ "underscore.string": "^3.3.4",
+ "yeoman-generator": "^0.22.5"
+ }
+}