├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── index.js └── templates │ ├── Gruntfile.js │ ├── _App.sln │ ├── _App │ ├── App.config │ ├── Models │ │ ├── Mappings │ │ │ ├── _IMappable.cs │ │ │ └── _MappingConfig.cs │ │ └── _CustomDateTimeConverter.cs │ ├── Modules │ │ └── _IndexModule.cs │ ├── NLog.config │ ├── _App.csproj │ ├── _AssemblyInfo.cs │ ├── _Bootstrapper.cs │ ├── _Main.cs │ ├── _packages.config │ ├── x64 │ │ └── SQLite.Interop.dll │ └── x86 │ │ └── SQLite.Interop.dll │ ├── _bower.json │ ├── _generator.json │ ├── _package.json │ ├── bowerrc │ ├── editorconfig │ ├── gitignore │ ├── jshintrc │ └── public │ ├── _index.html │ ├── css │ └── app.css │ ├── js │ ├── _app.js │ └── home │ │ └── _home-controller.js │ └── views │ └── home │ └── _home.html ├── entity ├── index.js └── templates │ ├── _App │ ├── Models │ │ ├── Mappings │ │ │ └── _EntityMapping.cs │ │ ├── _AttrEnum.cs │ │ ├── _Entity.cs │ │ └── _Entity_NHibernate.cs │ └── Modules │ │ └── _EntityModule.cs │ ├── _generator.json │ └── public │ ├── js │ └── entity │ │ ├── _entity-controller.js │ │ ├── _entity-router.js │ │ └── _entity-service.js │ └── views │ └── entity │ └── _entities.html ├── package.json └── test ├── test-creation.js └── test-load.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 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 | temp/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 4, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.8' 5 | before_install: 6 | - currentfolder=${PWD##*/} 7 | - if [ "$currentfolder" != 'generator-angular-nancy' ]; then cd .. && eval "mv $currentfolder generator-angular-nancy" && cd generator-angular-nancy; fi 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Robert Yokota 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Angular-Nancy generator 2 | 3 | A [Yeoman](http://yeoman.io) generator for [AngularJS](http://angularjs.org) and [Nancy](http://nancyfx.org/). 4 | 5 | Nancy is a C#-based micro-framework. For AngularJS integration with other micro-frameworks, see https://github.com/rayokota/MicroFrameworkRosettaStone. 6 | 7 | ## Installation 8 | 9 | Install [Git](http://git-scm.com), [node.js](http://nodejs.org), [NuGet](http://www.nuget.org/), and [Visual Studio](http://www.visualstudio.com/) for Windows or [Mono](http://mono-project.com/) for Linux/Mac OS X. The development mode also requires [SQLite](http://www.sqlite.org). 10 | 11 | Install Yeoman: 12 | 13 | npm install -g yo 14 | 15 | Install the Angular-Nancy generator: 16 | 17 | npm install -g generator-angular-nancy 18 | 19 | The above prerequisites can be installed to a VM using the [Angular-Nancy provisioner](https://github.com/rayokota/provision-angular-nancy). 20 | 21 | ## Creating a Nancy service 22 | 23 | In a new directory, generate the service: 24 | 25 | yo angular-nancy 26 | 27 | Install dependencies for Windows: 28 | 29 | nuget.exe restore 30 | 31 | or for Mono: 32 | 33 | mono --runtime=v4.0 nuget.exe restore 34 | 35 | Build and run the service for Windows: 36 | 37 | MSBuild.exe 38 | [Myapp]\bin\Debug\[Myapp].exe 39 | 40 | or for Mono: 41 | 42 | xbuild 43 | mono [Myapp]/bin/Debug/[Myapp].exe 44 | 45 | Your service will run at [http://localhost:8080](http://localhost:8080). 46 | 47 | 48 | ## Creating a persistent entity 49 | 50 | Generate the entity: 51 | 52 | yo angular-nancy:entity [myentity] 53 | 54 | You will be asked to specify attributes for the entity, where each attribute has the following: 55 | 56 | - a name 57 | - a type (String, Integer, Float, Boolean, Date, Enum) 58 | - for a String attribute, an optional minimum and maximum length 59 | - for a numeric attribute, an optional minimum and maximum value 60 | - for a Date attribute, an optional constraint to either past values or future values 61 | - for an Enum attribute, a list of enumerated values 62 | - whether the attribute is required 63 | 64 | Files that are regenerated will appear as conflicts. Allow the generator to overwrite these files as long as no custom changes have been made. 65 | 66 | Build and run the service for Windows: 67 | 68 | MSBuild.exe 69 | [Myapp]\bin\Debug\[Myapp].exe 70 | 71 | or for Mono: 72 | 73 | xbuild 74 | mono [Myapp]/bin/Debug/[Myapp].exe 75 | 76 | A client-side AngularJS application will now be available by running 77 | 78 | grunt server 79 | 80 | The Grunt server will run at [http://localhost:9000](http://localhost:9000). It will proxy REST requests to the Nancy service running at [http://localhost:8080](http://localhost:8080). 81 | 82 | At this point you should be able to navigate to a page to manage your persistent entities. 83 | 84 | The Grunt server supports hot reloading of client-side HTML/CSS/Javascript file changes. 85 | 86 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'), 3 | path = require('path'), 4 | yeoman = require('yeoman-generator'), 5 | _ = require('lodash'), 6 | _s = require('underscore.string'), 7 | pluralize = require('pluralize'), 8 | asciify = require('asciify'); 9 | 10 | var AngularNancyGenerator = module.exports = function AngularNancyGenerator(args, options, config) { 11 | yeoman.generators.Base.apply(this, arguments); 12 | 13 | this.on('end', function () { 14 | this.installDependencies({ skipInstall: options['skip-install'] }); 15 | }); 16 | 17 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 18 | }; 19 | 20 | util.inherits(AngularNancyGenerator, yeoman.generators.Base); 21 | 22 | AngularNancyGenerator.prototype.askFor = function askFor() { 23 | 24 | var cb = this.async(); 25 | 26 | console.log('\n' + 27 | '+-+-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+\n' + 28 | '|a|n|g|u|l|a|r| |n|a|n|c|y| |g|e|n|e|r|a|t|o|r|\n' + 29 | '+-+-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+\n' + 30 | '\n'); 31 | 32 | var prompts = [{ 33 | type: 'input', 34 | name: 'baseName', 35 | message: 'What is the name of your application?', 36 | default: 'myapp' 37 | }, 38 | { 39 | type: 'list', 40 | name: 'platform', 41 | message: 'Which platform would you like to target?', 42 | choices: ['Mono', 'Windows'], 43 | default: 'Windows' 44 | }, 45 | { 46 | type: 'list', 47 | name: 'orm', 48 | message: 'Which object-relational mapper would you like to use?', 49 | choices: ['NHibernate', 'OrmLite'], 50 | default: 'NHibernate' 51 | }]; 52 | 53 | this.prompt(prompts, function (props) { 54 | this.baseName = props.baseName; 55 | this.platform = props.platform; 56 | this.orm = props.orm; 57 | 58 | cb(); 59 | }.bind(this)); 60 | }; 61 | 62 | AngularNancyGenerator.prototype.app = function app() { 63 | 64 | this.entities = []; 65 | this.resources = []; 66 | this.generatorConfig = { 67 | "baseName": this.baseName, 68 | "platform": this.platform, 69 | "orm": this.orm, 70 | "entities": this.entities, 71 | "resources": this.resources 72 | }; 73 | this.generatorConfigStr = JSON.stringify(this.generatorConfig, null, '\t'); 74 | 75 | this.template('_generator.json', 'generator.json'); 76 | this.template('_package.json', 'package.json'); 77 | this.template('_bower.json', 'bower.json'); 78 | this.template('bowerrc', '.bowerrc'); 79 | this.template('Gruntfile.js', 'Gruntfile.js'); 80 | this.copy('gitignore', '.gitignore'); 81 | 82 | var appDir = _s.capitalize(this.baseName) + '/' 83 | var x64Dir = appDir + 'x64/' 84 | var x86Dir = appDir + 'x86/' 85 | var modelsDir = appDir + 'Models/' 86 | var mappingsDir = modelsDir + 'Mappings/' 87 | var modulesDir = appDir + 'Modules/' 88 | var publicDir = appDir + 'Content/' 89 | this.mkdir(x64Dir); 90 | this.mkdir(x86Dir); 91 | this.mkdir(appDir); 92 | this.mkdir(modelsDir); 93 | this.mkdir(mappingsDir); 94 | this.mkdir(modulesDir); 95 | this.mkdir(publicDir); 96 | 97 | this.template('_App.sln', _s.capitalize(this.baseName) + '.sln'); 98 | this.copy('_App/x64/SQLite.Interop.dll', x64Dir + 'SQLite.Interop.dll'); 99 | this.copy('_App/x86/SQLite.Interop.dll', x86Dir + 'SQLite.Interop.dll'); 100 | this.copy('_App/App.config', appDir + 'App.config'); 101 | this.copy('_App/NLog.config', appDir + 'NLog.config'); 102 | this.copy('_App/_packages.config', appDir + 'packages.config'); 103 | this.template('_App/_App.csproj', appDir + _s.capitalize(this.baseName) + '.csproj'); 104 | this.template('_App/_AssemblyInfo.cs', appDir + 'AssemblyInfo.cs'); 105 | this.template('_App/_Bootstrapper.cs', appDir + 'Bootstrapper.cs'); 106 | this.template('_App/Modules/_IndexModule.cs', modulesDir + 'IndexModule.cs'); 107 | this.template('_App/_Main.cs', appDir + 'Main.cs'); 108 | this.template('_App/Models/_CustomDateTimeConverter.cs', modelsDir + 'CustomDateTimeConverter.cs'); 109 | if (this.orm == 'NHibernate') { 110 | this.template('_App/Models/Mappings/_IMappable.cs', mappingsDir + 'IMappable.cs'); 111 | this.template('_App/Models/Mappings/_MappingConfig.cs', mappingsDir + 'MappingConfig.cs'); 112 | } 113 | 114 | var publicCssDir = publicDir + 'css/'; 115 | var publicJsDir = publicDir + 'js/'; 116 | var publicViewDir = publicDir + 'views/'; 117 | this.mkdir(publicCssDir); 118 | this.mkdir(publicJsDir); 119 | this.mkdir(publicViewDir); 120 | this.template('public/_index.html', publicDir + 'index.html'); 121 | this.copy('public/css/app.css', publicCssDir + 'app.css'); 122 | this.template('public/js/_app.js', publicJsDir + 'app.js'); 123 | this.template('public/js/home/_home-controller.js', publicJsDir + 'home/home-controller.js'); 124 | this.template('public/views/home/_home.html', publicViewDir + 'home/home.html'); 125 | }; 126 | 127 | AngularNancyGenerator.prototype.projectfiles = function projectfiles() { 128 | this.copy('editorconfig', '.editorconfig'); 129 | this.copy('jshintrc', '.jshintrc'); 130 | }; 131 | -------------------------------------------------------------------------------- /app/templates/Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest; 4 | 5 | module.exports = function (grunt) { 6 | require('load-grunt-tasks')(grunt); 7 | require('time-grunt')(grunt); 8 | 9 | grunt.initConfig({ 10 | yeoman: { 11 | // configurable paths 12 | app: require('./bower.json').appPath || '<%= _.capitalize(baseName) %>/Content', 13 | dist: '<%= _.capitalize(baseName) %>/Content' 14 | }, 15 | sync: { 16 | dist: { 17 | files: [{ 18 | cwd: '<%%= yeoman.app %>', 19 | dest: '<%%= yeoman.dist %>', 20 | src: '**' 21 | }] 22 | } 23 | }, 24 | watch: { 25 | options: { 26 | livereload: 35729 27 | }, 28 | src: { 29 | files: [ 30 | '<%%= yeoman.app %>/*.html', 31 | '<%%= yeoman.app %>/css/**/*', 32 | '<%%= yeoman.app %>/js/**/*', 33 | '<%%= yeoman.app %>/views/**/*' 34 | ], 35 | //tasks: ['sync:dist'] 36 | } 37 | }, 38 | connect: { 39 | proxies: [ 40 | { 41 | context: '/<%= baseName %>', 42 | host: 'localhost', 43 | port: 8080, 44 | https: false, 45 | changeOrigin: false 46 | } 47 | ], 48 | options: { 49 | port: 9000, 50 | // Change this to '0.0.0.0' to access the server from outside. 51 | hostname: 'localhost', 52 | livereload: 35729 53 | }, 54 | livereload: { 55 | options: { 56 | open: true, 57 | base: [ 58 | '<%%= yeoman.app %>' 59 | ], 60 | middleware: function (connect) { 61 | return [ 62 | proxySnippet, 63 | connect.static(require('path').resolve('<%= _.capitalize(baseName) %>/Content')) 64 | ]; 65 | } 66 | } 67 | }, 68 | /* 69 | dist: { 70 | options: { 71 | base: '<%%= yeoman.dist %>' 72 | } 73 | } 74 | */ 75 | }, 76 | // Put files not handled in other tasks here 77 | copy: { 78 | dist: { 79 | files: [{ 80 | expand: true, 81 | dot: true, 82 | cwd: '<%%= yeoman.app %>', 83 | dest: '<%%= yeoman.dist %>', 84 | src: '**' 85 | }] 86 | }, 87 | }, 88 | // Test settings 89 | karma: { 90 | unit: { 91 | configFile: 'test/config/karma.conf.js', 92 | singleRun: true 93 | } 94 | }, 95 | bowercopy: { 96 | options: { 97 | destPrefix: '<%%= yeoman.app %>' 98 | }, 99 | test: { 100 | files: { 101 | 'test/lib/angular-mocks': 'angular-mocks', 102 | 'test/lib/angular-scenario': 'angular-scenario' 103 | } 104 | } 105 | } 106 | }); 107 | 108 | grunt.registerTask('server', function (target) { 109 | grunt.task.run([ 110 | //'copy:dist', 111 | 'configureProxies', 112 | 'connect:livereload', 113 | 'watch' 114 | ]); 115 | }); 116 | }; 117 | -------------------------------------------------------------------------------- /app/templates/_App.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "<%= _.capitalize(baseName) %>", "<%= _.capitalize(baseName) %>\<%= _.capitalize(baseName) %>.csproj", "{ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(MonoDevelopProperties) = preSolution 18 | StartupItem = <%= _.capitalize(baseName) %>\<%= _.capitalize(baseName) %>.csproj 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /app/templates/_App/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/templates/_App/Models/Mappings/_IMappable.cs: -------------------------------------------------------------------------------- 1 | namespace <%= _.capitalize(baseName) %>.Models.Mappings 2 | { 3 | public interface IMappable 4 | { 5 | } 6 | } 7 | 8 | -------------------------------------------------------------------------------- /app/templates/_App/Models/Mappings/_MappingConfig.cs: -------------------------------------------------------------------------------- 1 | using FluentNHibernate.Automapping; 2 | using System; 3 | 4 | namespace <%= _.capitalize(baseName) %>.Models.Mappings 5 | { 6 | public class MappingConfig : DefaultAutomappingConfiguration 7 | { 8 | public override bool ShouldMap(Type type) 9 | { 10 | return typeof(IMappable).IsAssignableFrom(type); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/templates/_App/Models/_CustomDateTimeConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System; 4 | 5 | namespace <%= _.capitalize(baseName) %>.Models 6 | { 7 | public class CustomDateTimeConverter : IsoDateTimeConverter 8 | { 9 | public CustomDateTimeConverter() { 10 | base.DateTimeFormat = "yyyy-MM-dd"; 11 | } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /app/templates/_App/Modules/_IndexModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using Nancy; 6 | 7 | namespace <%= _.capitalize(baseName) %>.Modules 8 | { 9 | public class IndexModule : Nancy.NancyModule 10 | { 11 | public IndexModule() 12 | { 13 | Get["/"] = parameters => 14 | { 15 | return Response.AsRedirect("Content/index.html"); 16 | }; 17 | 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /app/templates/_App/NLog.config: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/templates/_App/_App.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 2.0 8 | {ACF7B6A6-76D1-46C8-AC58-CE04AD208E9F} 9 | Exe 10 | <%= _.capitalize(baseName) %> 11 | <%= _.capitalize(baseName) %> 12 | 13 | 14 | True 15 | full 16 | False 17 | bin\Debug 18 | DEBUG; 19 | prompt 20 | 4 21 | AnyCPU 22 | True 23 | 24 | 25 | none 26 | True 27 | bin\Release 28 | prompt 29 | 4 30 | AnyCPU 31 | True 32 | 33 | 34 | 35 | 36 | 37 | <% if (orm == 'NHibernate') { %> 38 | 39 | ..\packages\FluentNHibernate.1.4.0.0\lib\net35\FluentNHibernate.dll 40 | 41 | 42 | ..\packages\Iesi.Collections.3.2.0.4000\lib\Net35\Iesi.Collections.dll 43 | 44 | 45 | ..\packages\NHibernate.3.3.3.4001\lib\Net35\NHibernate.dll 46 | <% }; %> 47 | 48 | ..\packages\Nancy.0.22.2\lib\net40\Nancy.dll 49 | 50 | 51 | ..\packages\Nancy.Hosting.Self.0.22.2\lib\net40\Nancy.Hosting.Self.dll 52 | 53 | 54 | ..\packages\Nancy.Serialization.JsonNet.0.22.2\lib\net40\Nancy.Serialization.JsonNet.dll 55 | 56 | 57 | ..\packages\Newtonsoft.Json.6.0.1\lib\net40\Newtonsoft.Json.dll 58 | 59 | 60 | ..\packages\NLog.2.1.0\lib\net40\NLog.dll 61 | 62 | 63 | ..\packages\ServiceStack.Interfaces.4.0.12\lib\net40\ServiceStack.Interfaces.dll 64 | 65 | 66 | ..\packages\ServiceStack.Text.4.0.12\lib\net40\ServiceStack.Text.dll 67 | 68 | 69 | ..\packages\ServiceStack.Common.4.0.12\lib\net40\ServiceStack.Common.dll 70 | 71 | <% if (orm == 'OrmLite') { %> 72 | 73 | ..\packages\ServiceStack.OrmLite.4.0.12\lib\net40\ServiceStack.OrmLite.dll 74 | 75 | <% if (platform == 'Mono') { %> 76 | 77 | ..\packages\ServiceStack.OrmLite.Sqlite.Mono.4.0.12\lib\net40\ServiceStack.OrmLite.Sqlite.dll 78 | <% } else { %> 79 | 80 | ..\packages\ServiceStack.OrmLite.Sqlite.Windows.4.0.12\lib\net40\ServiceStack.OrmLite.Sqlite.Windows.dll 81 | <% }}; %> 82 | <% if (platform == 'Mono') { %> 83 | 84 | ..\packages\ServiceStack.OrmLite.Sqlite.Mono.4.0.12\lib\net40\Mono.Data.Sqlite.dll 85 | <% } else { %> 86 | 87 | ..\packages\System.Data.SQLite.1.0.91.0\lib\net40\System.Data.SQLite.dll 88 | <% }; %> 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | Always 106 | 107 | 108 | Always 109 | 110 | 111 | Always 112 | 113 | 114 | Always 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/templates/_App/_AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("<%= _.capitalize(baseName) %>")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("<%= _.capitalize(baseName) %>")] 12 | [assembly: AssemblyCopyright("Copyright © 2013")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | 28 | -------------------------------------------------------------------------------- /app/templates/_App/_Bootstrapper.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using NLog.Config; 3 | using NLog.Targets; 4 | using NLog.Targets.Wrappers; 5 | <% if (orm == 'NHibernate') { %>using FluentNHibernate.Automapping; 6 | using FluentNHibernate.Cfg; 7 | using FluentNHibernate.Cfg.Db; 8 | using NHibernate; 9 | using NHibernate.Cfg; 10 | using NHibernate.Tool.hbm2ddl;<% }; %> 11 | using ServiceStack.Data; 12 | <% if (orm == 'OrmLite') { %>using ServiceStack.OrmLite; 13 | using ServiceStack.OrmLite.Sqlite;<% }; %> 14 | using System; 15 | using System.Configuration; 16 | using Nancy; 17 | using Nancy.Diagnostics; 18 | using Nancy.Bootstrapper; 19 | using Nancy.TinyIoc; 20 | using Nancy.Conventions; 21 | using <%= _.capitalize(baseName) %>.Models; 22 | <% if (orm == 'NHibernate') { %>using <%= _.capitalize(baseName) %>.Models.Mappings; 23 | <% }; %> 24 | 25 | namespace <%= _.capitalize(baseName) %> 26 | { 27 | public class Bootstrapper : DefaultNancyBootstrapper 28 | { 29 | private Logger log = LogManager.GetLogger("RequestLogger"); 30 | 31 | protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) 32 | { 33 | base.ApplicationStartup(container, pipelines); 34 | 35 | StaticConfiguration.DisableErrorTraces = false; 36 | 37 | LogAllRequests(pipelines); 38 | LogAllResponseCodes(pipelines); 39 | LogUnhandledExceptions(pipelines); 40 | } 41 | 42 | private void LogAllRequests(IPipelines pipelines) 43 | { 44 | pipelines.BeforeRequest += ctx => 45 | { 46 | log.Info("Handling request {0} \"{1}\"", ctx.Request.Method, ctx.Request.Path); 47 | return null; 48 | }; 49 | } 50 | 51 | private void LogAllResponseCodes(IPipelines pipelines) 52 | { 53 | pipelines.AfterRequest += ctx => 54 | log.Info("Responding {0} to {1} \"{2}\"", ctx.Response.StatusCode, ctx.Request.Method, ctx.Request.Path); 55 | } 56 | 57 | private void LogUnhandledExceptions(IPipelines pipelines) 58 | { 59 | pipelines.OnError.AddItemToStartOfPipeline((ctx, err) => 60 | { 61 | log.ErrorException(string.Format("Request {0} \"{1}\" failed", ctx.Request.Method, ctx.Request.Path), err); 62 | return null; 63 | }); 64 | } 65 | 66 | <% if (orm == 'NHibernate') { %> 67 | protected override void ConfigureApplicationContainer(TinyIoCContainer container) 68 | { 69 | base.ConfigureApplicationContainer(container); 70 | 71 | <% if (entities.length > 0) { %> 72 | container.Register(CreateSessionFactory());<% }; %> 73 | } 74 | 75 | protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context) 76 | { 77 | base.ConfigureRequestContainer(container, context); 78 | 79 | <% if (entities.length > 0) { %> 80 | container.Register(container.Resolve().OpenSession());<% }; %> 81 | } 82 | 83 | <% if (entities.length > 0) { %> 84 | private static ISessionFactory CreateSessionFactory() 85 | { 86 | return Fluently 87 | .Configure() 88 | .Database(SQLiteConfiguration 89 | .Standard 90 | <% if (platform == 'Mono') { %>.Driver()<% }; %> 91 | .UsingFile("my.db")) 92 | .Mappings(m => { 93 | <% _.each(entities, function(entity) { %> 94 | m.AutoMappings.Add(AutoMap.AssemblyOf<<%= _.capitalize(entity.name) %>>(new MappingConfig()).UseOverridesFromAssemblyOf<<%= _.capitalize(entity.name) %>Mapping>());<% }); %> 95 | } 96 | ) 97 | .ExposeConfiguration(BuildSchema) 98 | .BuildSessionFactory(); 99 | } 100 | 101 | private static void BuildSchema(Configuration config) 102 | { 103 | // this NHibernate tool takes a configuration (with mapping info in) 104 | // and exports a database schema from it 105 | new SchemaUpdate(config) 106 | .Execute(false, true); 107 | } 108 | <% }; %> 109 | <% } else { %> 110 | protected override void ConfigureApplicationContainer(TinyIoCContainer container) 111 | { 112 | base.ConfigureApplicationContainer(container); 113 | 114 | var dbFactory = new OrmLiteConnectionFactory("my.db", SqliteDialect.Provider); 115 | 116 | CreateDatabase(dbFactory); 117 | container.Register(dbFactory); 118 | } 119 | 120 | private void CreateDatabase(OrmLiteConnectionFactory dbFactory) 121 | { 122 | <% if (entities.length > 0) { %> 123 | using (var db = dbFactory.OpenDbConnection()) 124 | { 125 | <% _.each(entities, function (entity) { %> 126 | db.CreateTable<<%= _.capitalize(entity.name) %>>(false);<% }); %> 127 | } 128 | <% }; %> 129 | } 130 | <% }; %> 131 | } 132 | 133 | <% if (orm == 'NHibernate' && platform == 'Mono') { %> 134 | public class MonoSqliteDriver : NHibernate.Driver.ReflectionBasedDriver 135 | { 136 | public MonoSqliteDriver() 137 | : base( 138 | "Mono.Data.Sqlite", 139 | "Mono.Data.Sqlite", 140 | "Mono.Data.Sqlite.SqliteConnection", 141 | "Mono.Data.Sqlite.SqliteCommand") 142 | { 143 | } 144 | 145 | public override bool UseNamedPrefixInParameter { 146 | get { 147 | return true; 148 | } 149 | } 150 | 151 | public override bool UseNamedPrefixInSql { 152 | get { 153 | return true; 154 | } 155 | } 156 | 157 | public override string NamedPrefix { 158 | get { 159 | return "@"; 160 | } 161 | } 162 | 163 | public override bool SupportsMultipleOpenReaders { 164 | get { 165 | return false; 166 | } 167 | } 168 | } 169 | <% }; %> 170 | } 171 | -------------------------------------------------------------------------------- /app/templates/_App/_Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Nancy.Hosting.Self; 3 | using System.Diagnostics; 4 | using System.Threading; 5 | 6 | namespace <%= _.capitalize(baseName) %> 7 | { 8 | class MainClass 9 | { 10 | public static void Main (string[] args) 11 | { 12 | var hostConfiguration = new HostConfiguration 13 | { 14 | UrlReservations = new UrlReservations() { CreateAutomatically = true } 15 | }; 16 | 17 | var nancyHost = new NancyHost(hostConfiguration, 18 | new Uri("http://localhost:8080/")); 19 | 20 | nancyHost.Start(); 21 | 22 | Console.WriteLine("Nancy now listening at http://localhost:8080/. Press enter to stop"); 23 | ConsoleKeyInfo key = Console.ReadKey(); 24 | if ((int)key.Key == 0) 25 | { 26 | // Mono returns a ConsoleKeyInfo with a Key value of 0 when stdin is redirected 27 | // See https://bugzilla.xamarin.com/show_bug.cgi?id=12551 28 | // For now, just sleep, so that we can run in background with nohup 29 | Thread.Sleep(Timeout.Infinite); 30 | } 31 | 32 | nancyHost.Stop(); 33 | Console.WriteLine("Stopped. Good bye!"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/templates/_App/_packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | <% if (orm == 'NHibernate') { %> 4 | 5 | <% }; %> 6 | 7 | 8 | 9 | 10 | 11 | <% if (orm == 'NHibernate') { %> 12 | <% }; %> 13 | 14 | 15 | <% if (orm == 'OrmLite') { %> 16 | 17 | <% }; %> 18 | <% if (platform == 'Windows') { %> 19 | <% }; %> 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/templates/_App/x64/SQLite.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rayokota/generator-angular-nancy/ed123032244b564cf497e1ee51b462a2dfe6c9cf/app/templates/_App/x64/SQLite.Interop.dll -------------------------------------------------------------------------------- /app/templates/_App/x86/SQLite.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rayokota/generator-angular-nancy/ed123032244b564cf497e1ee51b462a2dfe6c9cf/app/templates/_App/x86/SQLite.Interop.dll -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.camelize(baseName) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular-bootstrap": "~0.10.0", 6 | "angular-resource": "~1.2.13", 7 | "angular-route": "~1.2.13", 8 | "angular-ui-date": "~0.0.3", 9 | "angular": "~1.2.13", 10 | "bootstrap-css": "~3.0.0", 11 | "jquery": "~2.1.0", 12 | "lodash": "~2.4.1" 13 | }, 14 | "devDependencies": { 15 | "angular-mocks": "~1.2.13", 16 | "angular-scenario": "~1.2.13" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/templates/_generator.json: -------------------------------------------------------------------------------- 1 | <%= generatorConfigStr %> 2 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(baseName) %>", 3 | "version": "0.0.0", 4 | "description": "Description for <%= baseName %>", 5 | "dependencies": {}, 6 | "devDependencies": { 7 | "grunt": "~0.4.2", 8 | "grunt-autoprefixer": "~0.4.2", 9 | "grunt-bowercopy": "~0.4.1", 10 | "grunt-bower-install": "~0.7.0", 11 | "grunt-concurrent": "~0.4.2", 12 | "grunt-connect-proxy": "~0.2.0", 13 | "grunt-contrib-clean": "~0.5.0", 14 | "grunt-contrib-concat": "~0.3.0", 15 | "grunt-contrib-connect": "~0.5.0", 16 | "grunt-contrib-copy": "~0.4.1", 17 | "grunt-contrib-cssmin": "~0.7.0", 18 | "grunt-contrib-htmlmin": "~0.1.3", 19 | "grunt-contrib-imagemin": "~0.4.0", 20 | "grunt-contrib-jshint": "~0.7.2", 21 | "grunt-contrib-uglify": "~0.2.7", 22 | "grunt-contrib-watch": "~0.5.3", 23 | "grunt-karma": "~0.6.2", 24 | "grunt-modernizr": "~0.4.1", 25 | "grunt-ngmin": "~0.0.3", 26 | "grunt-rev": "~0.1.0", 27 | "grunt-svgmin": "~0.3.0", 28 | "grunt-sync": "~0.0.5", 29 | "grunt-usemin": "~2.0.2", 30 | "load-grunt-tasks": "~0.2.0", 31 | "time-grunt": "0.2.3", 32 | "karma" : "~0.10.8", 33 | "karma-junit-reporter" : "~0.1.0", 34 | "karma-jasmine" : "~0.1.0", 35 | "karma-ng-scenario" : "~0.1.0" 36 | }, 37 | "engines": { 38 | "node": ">=0.8.15" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/templates/bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "<%= _.capitalize(baseName) %>/Content/lib", 3 | "json": "bower.json" 4 | } 5 | -------------------------------------------------------------------------------- /app/templates/editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 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 | -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *~ 4 | node_modules 5 | -------------------------------------------------------------------------------- /app/templates/jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 4, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /app/templates/public/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= _.capitalize(baseName) %> 8 | 9 | 10 | 11 | 12 | 13 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | <% _.each(entities, function (entity) { %> 52 | 53 | 54 | 55 | <% }); %> 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/templates/public/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 60px; 3 | padding: 10px; 4 | background-color: #ECF0F1; 5 | } 6 | -------------------------------------------------------------------------------- /app/templates/public/js/_app.js: -------------------------------------------------------------------------------- 1 | // Declare app level module which depends on filters, and services 2 | angular.module('<%= baseName %>', ['ngResource', 'ngRoute', 'ui.bootstrap', 'ui.date']) 3 | .config(['$routeProvider', function ($routeProvider) { 4 | $routeProvider 5 | .when('/', { 6 | templateUrl: 'views/home/home.html', 7 | controller: 'HomeController'}) 8 | .otherwise({redirectTo: '/'}); 9 | }]); 10 | -------------------------------------------------------------------------------- /app/templates/public/js/home/_home-controller.js: -------------------------------------------------------------------------------- 1 | angular.module('<%= baseName %>') 2 | .controller('HomeController', ['$scope', function ($scope) { 3 | }]); 4 | -------------------------------------------------------------------------------- /app/templates/public/views/home/_home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Welcome to <%= _.capitalize(baseName) %>!

5 |

This is your homepage, ready for editing

6 | 7 |

8 | If you like this Angular-Nancy generator, please give us a star at  Github! 9 |

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /entity/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'), 3 | yeoman = require('yeoman-generator'), 4 | fs = require('fs'), 5 | _ = require('lodash'), 6 | _s = require('underscore.string'), 7 | pluralize = require('pluralize'); 8 | 9 | var EntityGenerator = module.exports = function EntityGenerator(args, options, config) { 10 | // By calling `NamedBase` here, we get the argument to the subgenerator call 11 | // as `this.name`. 12 | yeoman.generators.NamedBase.apply(this, arguments); 13 | 14 | console.log('You called the entity subgenerator with the argument ' + this.name + '.'); 15 | 16 | fs.readFile('generator.json', 'utf8', function (err, data) { 17 | if (err) { 18 | console.log('Error: ' + err); 19 | return; 20 | } 21 | this.generatorConfig = JSON.parse(data); 22 | }.bind(this)); 23 | }; 24 | 25 | util.inherits(EntityGenerator, yeoman.generators.NamedBase); 26 | 27 | EntityGenerator.prototype.askFor = function askFor() { 28 | var cb = this.async(); 29 | 30 | console.log('\nPlease specify an attribute:'); 31 | 32 | var prompts = [{ 33 | type: 'input', 34 | name: 'attrName', 35 | message: 'What is the name of the attribute?', 36 | default: 'myattr' 37 | }, 38 | { 39 | type: 'list', 40 | name: 'attrType', 41 | message: 'What is the type of the attribute?', 42 | choices: ['String', 'Integer', 'Long', 'Float', 'Double', 'Boolean', 'Date', 'Enum'], 43 | default: 'String' 44 | }, 45 | { 46 | when: function (props) { return (/String/).test(props.attrType); }, 47 | type: 'input', 48 | name: 'minLength', 49 | message: 'Enter the minimum length for the String attribute, or hit enter:', 50 | validate: function (input) { 51 | if (input && isNaN(input)) { 52 | return "Please enter a number."; 53 | } 54 | return true; 55 | } 56 | }, 57 | { 58 | when: function (props) { return (/String/).test(props.attrType); }, 59 | type: 'input', 60 | name: 'maxLength', 61 | message: 'Enter the maximum length for the String attribute, or hit enter:', 62 | validate: function (input) { 63 | if (input && isNaN(input)) { 64 | return "Please enter a number."; 65 | } 66 | return true; 67 | } 68 | }, 69 | { 70 | when: function (props) { return (/Integer|Long|Float|Double/).test(props.attrType); }, 71 | type: 'input', 72 | name: 'min', 73 | message: 'Enter the minimum value for the numeric attribute, or hit enter:', 74 | validate: function (input) { 75 | if (input && isNaN(input)) { 76 | return "Please enter a number."; 77 | } 78 | return true; 79 | } 80 | }, 81 | { 82 | when: function (props) { return (/Integer|Long|Float|Double/).test(props.attrType); }, 83 | type: 'input', 84 | name: 'max', 85 | message: 'Enter the maximum value for the numeric attribute, or hit enter:', 86 | validate: function (input) { 87 | if (input && isNaN(input)) { 88 | return "Please enter a number."; 89 | } 90 | return true; 91 | } 92 | }, 93 | { 94 | when: function (props) { return (/Date/).test(props.attrType); }, 95 | type: 'list', 96 | name: 'dateConstraint', 97 | message: 'Constrain the date as follows:', 98 | choices: ['None', 'Past dates only', 'Future dates only'], 99 | filter: function (input) { 100 | if (/Past/.test(input)) return 'Past'; 101 | if (/Future/.test(input)) return 'Future'; 102 | return ''; 103 | }, 104 | default: 'None' 105 | }, 106 | { 107 | when: function (props) { return (/Enum/).test(props.attrType); }, 108 | type: 'input', 109 | name: 'enumValues', 110 | message: 'Enter an enumeration of values, separated by commas' 111 | }, 112 | { 113 | type: 'confirm', 114 | name: 'required', 115 | message: 'Is the attribute required to have a value?', 116 | default: true 117 | }, 118 | { 119 | type: 'confirm', 120 | name: 'again', 121 | message: 'Would you like to enter another attribute or reenter a previous attribute?', 122 | default: true 123 | }]; 124 | 125 | this.prompt(prompts, function (props) { 126 | this.attrs = this.attrs || []; 127 | var attrType = props.attrType; 128 | var attrImplType = props.attrType; 129 | if (attrType === 'String') { 130 | attrImplType = 'string'; 131 | } else if (attrType === 'Integer') { 132 | attrImplType = 'int'; 133 | } else if (attrType === 'Long') { 134 | attrImplType = 'long'; 135 | } else if (attrType === 'Float') { 136 | attrImplType = 'float'; 137 | } else if (attrType === 'Double') { 138 | attrImplType = 'double'; 139 | } else if (attrType === 'Boolean') { 140 | attrImplType = 'bool'; 141 | } else if (attrType === 'Date') { 142 | attrImplType = 'DateTime'; 143 | } else if (attrType === 'Enum') { 144 | attrImplType = 'Enum'; 145 | } 146 | this.attrs = _.reject(this.attrs, function (attr) { return attr.attrName === props.attrName; }); 147 | this.attrs.push({ 148 | attrName: props.attrName, 149 | attrType: attrType, 150 | attrImplType: attrImplType, 151 | minLength: props.minLength, 152 | maxLength: props.maxLength, 153 | min: props.min, 154 | max: props.max, 155 | dateConstraint: props.dateConstraint, 156 | enumValues: props.enumValues ? props.enumValues.split(',') : [], 157 | required: props.required 158 | }); 159 | 160 | if (props.again) { 161 | this.askFor(); 162 | } else { 163 | cb(); 164 | } 165 | }.bind(this)); 166 | }; 167 | 168 | EntityGenerator.prototype.files = function files() { 169 | 170 | this.baseName = this.generatorConfig.baseName; 171 | this.platform = this.generatorConfig.platform; 172 | this.orm = this.generatorConfig.orm; 173 | this.entities = this.generatorConfig.entities; 174 | this.entities = _.reject(this.entities, function (entity) { return entity.name === this.name; }.bind(this)); 175 | this.entities.push({ name: this.name, attrs: this.attrs}); 176 | this.pluralize = pluralize; 177 | this.generatorConfig.entities = this.entities; 178 | this.generatorConfigStr = JSON.stringify(this.generatorConfig, null, '\t'); 179 | 180 | var appDir = _s.capitalize(this.baseName) + '/' 181 | var modelsDir = appDir + 'Models/' 182 | var mappingsDir = modelsDir + 'Mappings/' 183 | var modulesDir = appDir + 'Modules/' 184 | var publicDir = appDir + 'Content/' 185 | this.template('_generator.json', 'generator.json'); 186 | this.template('../../app/templates/_App/_Bootstrapper.cs', appDir + 'Bootstrapper.cs'); 187 | this.template('_App/Models/_Entity.cs', modelsDir + _s.capitalize(this.name) + '.cs'); 188 | this.template('_App/Modules/_EntityModule.cs', modulesDir + _s.capitalize(this.name) + 'Module.cs'); 189 | _.each(this.attrs, function (attr) { 190 | if (attr.attrType === 'Enum') { 191 | this.attr = attr; 192 | this.template('_App/Models/_AttrEnum.cs', modelsDir + _s.capitalize(attr.attrName) + 'Enum.cs'); 193 | } 194 | }.bind(this)); 195 | if (this.orm == 'NHibernate') { 196 | this.template('_App/Models/Mappings/_EntityMapping.cs', mappingsDir + _s.capitalize(this.name) + 'Mapping.cs'); 197 | } 198 | 199 | var publicCssDir = publicDir + 'css/'; 200 | var publicJsDir = publicDir + 'js/'; 201 | var publicViewDir = publicDir + 'views/'; 202 | var publicEntityJsDir = publicJsDir + this.name + '/'; 203 | var publicEntityViewDir = publicViewDir + this.name + '/'; 204 | this.mkdir(publicEntityJsDir); 205 | this.mkdir(publicEntityViewDir); 206 | this.template('../../app/templates/public/_index.html', publicDir + 'index.html'); 207 | this.template('public/js/entity/_entity-controller.js', publicEntityJsDir + this.name + '-controller.js'); 208 | this.template('public/js/entity/_entity-router.js', publicEntityJsDir + this.name + '-router.js'); 209 | this.template('public/js/entity/_entity-service.js', publicEntityJsDir + this.name + '-service.js'); 210 | this.template('public/views/entity/_entities.html', publicEntityViewDir + pluralize(this.name) + '.html'); 211 | }; 212 | -------------------------------------------------------------------------------- /entity/templates/_App/Models/Mappings/_EntityMapping.cs: -------------------------------------------------------------------------------- 1 | using FluentNHibernate.Automapping; 2 | using FluentNHibernate.Automapping.Alterations; 3 | using System; 4 | 5 | namespace <%= _.capitalize(baseName) %>.Models.Mappings 6 | { 7 | public class <%= _.capitalize(name) %>Mapping : IAutoMappingOverride<<%= _.capitalize(name) %>> 8 | { 9 | public void Override(AutoMapping<<%= _.capitalize(name) %>> mapping) 10 | { 11 | mapping.Table("<%= _.capitalize(pluralize(name)) %>"); 12 | 13 | mapping.Id(x => x.Id, "Id").GeneratedBy.Identity(); 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /entity/templates/_App/Models/_AttrEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace <%= _.capitalize(baseName) %>.Models 4 | { 5 | public enum <%= _.capitalize(attr.attrName) %>Enum 6 | { 7 | <% var delim = ''; _.each(attr.enumValues, function (value) { %><%= delim %><%= value %><% delim = ', '; }); %> 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /entity/templates/_App/Models/_Entity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System; 4 | <% if (orm == 'NHibernate') { %>using <%= _.capitalize(baseName) %>.Models.Mappings; 5 | <% } else { %>using ServiceStack.DataAnnotations;<% }; %> 6 | 7 | namespace <%= _.capitalize(baseName) %>.Models 8 | { 9 | public class <%= _.capitalize(name) %><% if (orm == 'NHibernate') { %> : IMappable<% }; %> 10 | { 11 | <% if (orm == 'OrmLite') { %>[AutoIncrement]<% }; %> 12 | [JsonProperty(PropertyName = "id")] 13 | public virtual long? Id { get; set; } 14 | <% _.each(attrs, function (attr) { %> 15 | <% if (attr.attrType == 'Enum') { %>[JsonConverter(typeof(StringEnumConverter))]<% } else if (attr.attrType == 'Date') { %>[JsonConverter(typeof(CustomDateTimeConverter))]<% }; %> 16 | [JsonProperty(PropertyName = "<%= attr.attrName %>")] 17 | public virtual <% if (attr.attrType == 'Enum') { %><%= _.capitalize(attr.attrName) %><% } %><%= attr.attrImplType %><% if (!attr.required) { %>?<% } %> <%= _.capitalize(attr.attrName) %> { get; set; }<% }); %> 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /entity/templates/_App/Models/_Entity_NHibernate.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System; 4 | using <%= _.capitalize(baseName) %>.Models.Mappings; 5 | 6 | namespace <%= _.capitalize(baseName) %>.Models 7 | { 8 | public class <%= _.capitalize(name) %> : IMappable 9 | { 10 | [JsonProperty(PropertyName = "id")] 11 | public long? Id { get; set; } 12 | <% _.each(attrs, function (attr) { %> 13 | <% if (attr.attrType == 'Enum') { %>[JsonConverter(typeof(StringEnumConverter))]<% } else if (attr.attrType == 'Date') { %>[JsonConverter(typeof(CustomDateTimeConverter))]<% }; %> 14 | [JsonProperty(PropertyName = "<%= attr.attrName %>")] 15 | public <% if (attr.attrType == 'Enum') { %><%= _.capitalize(attr.attrName) %><% } %><%= attr.attrImplType %><% if (!attr.required) { %>?<% } %> <%= _.capitalize(attr.attrName) %> { get; set; }<% }); %> 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /entity/templates/_App/Modules/_EntityModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using Nancy; 6 | using Nancy.ModelBinding; 7 | using ServiceStack.Data; 8 | <% if (orm == 'NHibernate') { %>using NHibernate; 9 | <% } else { %>using ServiceStack.OrmLite;<% }; %> 10 | using System.Data; 11 | using <%= _.capitalize(baseName) %>.Models; 12 | 13 | namespace <%= _.capitalize(baseName) %>.Modules 14 | { 15 | public class <%= _.capitalize(name) %>Module : Nancy.NancyModule 16 | { 17 | <% if (orm == 'NHibernate') { %> 18 | private readonly ISession _session; 19 | 20 | public <%= _.capitalize(name) %>Module(ISession session) 21 | : this() 22 | { 23 | _session = session; 24 | } 25 | 26 | public <%= _.capitalize(name) %>Module() 27 | : base("/<%= baseName %>/<%= pluralize(name) %>") 28 | { 29 | Get["/"] = parameters => 30 | { 31 | IList<<%= _.capitalize(name) %>> rows = null; 32 | using (var tx = _session.BeginTransaction()) 33 | { 34 | rows = _session.CreateCriteria(typeof(<%= _.capitalize(name) %>)).List<<%= _.capitalize(name) %>>(); 35 | tx.Commit(); 36 | } 37 | return Response.AsJson(rows); 38 | }; 39 | 40 | Get["/{id}"] = parameters => 41 | { 42 | <%= _.capitalize(name) %> row = null; 43 | long rowId = parameters.id; 44 | using (var tx = _session.BeginTransaction()) 45 | { 46 | row = (<%= _.capitalize(name) %>)_session.Get(typeof(<%= _.capitalize(name) %>), rowId); 47 | if (row == null) 48 | { 49 | return HttpStatusCode.NotFound; 50 | } 51 | tx.Commit(); 52 | } 53 | return Response.AsJson(row); 54 | }; 55 | 56 | Post["/"] = parameters => 57 | { 58 | <%= _.capitalize(name) %> row = this.Bind<<%= _.capitalize(name) %>>(); 59 | using (var tx = _session.BeginTransaction()) 60 | { 61 | _session.SaveOrUpdate(row); 62 | tx.Commit(); 63 | } 64 | return Response.AsJson(row, HttpStatusCode.Created); 65 | }; 66 | 67 | Put["/{id}"] = parameters => 68 | { 69 | <%= _.capitalize(name) %> row = this.Bind<<%= _.capitalize(name) %>>(); 70 | row.Id = parameters.id; 71 | using (var tx = _session.BeginTransaction()) 72 | { 73 | <%= _.capitalize(name) %> oldRow = (<%= _.capitalize(name) %>)_session.Get(typeof(<%= _.capitalize(name) %>), row.Id); 74 | if (oldRow == null) 75 | { 76 | return HttpStatusCode.NotFound; 77 | } 78 | _session.Merge(row); 79 | tx.Commit(); 80 | } 81 | return Response.AsJson(row); 82 | }; 83 | 84 | Delete["/{id}"] = parameters => 85 | { 86 | long rowId = parameters.id; 87 | using (var tx = _session.BeginTransaction()) 88 | { 89 | <%= _.capitalize(name) %> oldRow = (<%= _.capitalize(name) %>)_session.Get(typeof(<%= _.capitalize(name) %>), rowId); 90 | if (oldRow == null) 91 | { 92 | return HttpStatusCode.NotFound; 93 | } 94 | _session.Delete(oldRow); 95 | tx.Commit(); 96 | } 97 | return HttpStatusCode.NoContent; 98 | }; 99 | } 100 | <% } else { %> 101 | private readonly IDbConnectionFactory _dbFactory; 102 | 103 | public <%= _.capitalize(name) %>Module(IDbConnectionFactory dbFactory) 104 | : this() 105 | { 106 | _dbFactory = dbFactory; 107 | } 108 | 109 | public <%= _.capitalize(name) %>Module() 110 | : base("/<%= baseName %>/<%= pluralize(name) %>") 111 | { 112 | Get["/"] = parameters => 113 | { 114 | List<<%= _.capitalize(name) %>> rows = null; 115 | using (IDbConnection db = _dbFactory.OpenDbConnection()) 116 | { 117 | rows = db.Select<<%= _.capitalize(name) %>>(); 118 | } 119 | return Response.AsJson(rows); 120 | }; 121 | 122 | Get["/{id}"] = parameters => 123 | { 124 | <%= _.capitalize(name) %> row = null; 125 | long rowId = parameters.id; 126 | using (IDbConnection db = _dbFactory.OpenDbConnection()) 127 | { 128 | row = db.Single<<%= _.capitalize(name) %>>(r => r.Id == rowId); 129 | if (row == null) 130 | { 131 | return HttpStatusCode.NotFound; 132 | } 133 | } 134 | return Response.AsJson(row); 135 | }; 136 | 137 | Post["/"] = parameters => 138 | { 139 | <%= _.capitalize(name) %> row = this.Bind<<%= _.capitalize(name) %>>(); 140 | using (IDbConnection db = _dbFactory.OpenDbConnection()) 141 | { 142 | db.Insert(row); 143 | row.Id = db.LastInsertId(); 144 | } 145 | return Response.AsJson(row, HttpStatusCode.Created); 146 | }; 147 | 148 | Put["/{id}"] = parameters => 149 | { 150 | <%= _.capitalize(name) %> row = this.Bind<<%= _.capitalize(name) %>>(); 151 | row.Id = parameters.id; 152 | using (IDbConnection db = _dbFactory.OpenDbConnection()) 153 | { 154 | <%= _.capitalize(name) %> oldRow = db.Single<<%= _.capitalize(name) %>>(r => r.Id == row.Id); 155 | if (oldRow == null) 156 | { 157 | return HttpStatusCode.NotFound; 158 | } 159 | db.Update(row); 160 | } 161 | return Response.AsJson(row); 162 | }; 163 | 164 | Delete["/{id}"] = parameters => 165 | { 166 | long rowId = parameters.id; 167 | using (IDbConnection db = _dbFactory.OpenDbConnection()) 168 | { 169 | db.Delete<<%= _.capitalize(name) %>>(r => r.Id == rowId); 170 | } 171 | return HttpStatusCode.NoContent; 172 | }; 173 | } 174 | <% }; %> 175 | } 176 | } 177 | 178 | -------------------------------------------------------------------------------- /entity/templates/_generator.json: -------------------------------------------------------------------------------- 1 | <%= generatorConfigStr %> 2 | -------------------------------------------------------------------------------- /entity/templates/public/js/entity/_entity-controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= baseName %>') 4 | .controller('<%= _.capitalize(name) %>Controller', ['$scope', '$modal', 'resolved<%= _.capitalize(name) %>', '<%= _.capitalize(name) %>', 5 | function ($scope, $modal, resolved<%= _.capitalize(name) %>, <%= _.capitalize(name) %>) { 6 | 7 | $scope.<%= pluralize(name) %> = resolved<%= _.capitalize(name) %>; 8 | 9 | $scope.create = function () { 10 | $scope.clear(); 11 | $scope.open(); 12 | }; 13 | 14 | $scope.update = function (id) { 15 | $scope.<%= name %> = <%= _.capitalize(name) %>.get({id: id}); 16 | $scope.open(id); 17 | }; 18 | 19 | $scope.delete = function (id) { 20 | <%= _.capitalize(name) %>.delete({id: id}, 21 | function () { 22 | $scope.<%= pluralize(name) %> = <%= _.capitalize(name) %>.query(); 23 | }); 24 | }; 25 | 26 | $scope.save = function (id) { 27 | if (id) { 28 | <%= _.capitalize(name) %>.update({id: id}, $scope.<%= name %>, 29 | function () { 30 | $scope.<%= pluralize(name) %> = <%= _.capitalize(name) %>.query(); 31 | $scope.clear(); 32 | }); 33 | } else { 34 | <%= _.capitalize(name) %>.save($scope.<%= name %>, 35 | function () { 36 | $scope.<%= pluralize(name) %> = <%= _.capitalize(name) %>.query(); 37 | $scope.clear(); 38 | }); 39 | } 40 | }; 41 | 42 | $scope.clear = function () { 43 | $scope.<%= name %> = { 44 | <% _.each(attrs, function (attr) { %> 45 | "<%= attr.attrName %>": "", 46 | <% }); %> 47 | "id": "" 48 | }; 49 | }; 50 | 51 | $scope.open = function (id) { 52 | var <%= name %>Save = $modal.open({ 53 | templateUrl: '<%= name %>-save.html', 54 | controller: '<%= _.capitalize(name) %>SaveController', 55 | resolve: { 56 | <%= name %>: function () { 57 | return $scope.<%= name %>; 58 | } 59 | } 60 | }); 61 | 62 | <%= name %>Save.result.then(function (entity) { 63 | $scope.<%= name %> = entity; 64 | $scope.save(id); 65 | }); 66 | }; 67 | }]) 68 | .controller('<%= _.capitalize(name) %>SaveController', ['$scope', '$modalInstance', '<%= name %>', 69 | function ($scope, $modalInstance, <%= name %>) { 70 | $scope.<%= name %> = <%= name %>; 71 | 72 | <% _.each(attrs, function (attr) { if (attr.attrType === 'Date') { %> 73 | $scope.<%= attr.attrName %>DateOptions = { 74 | dateFormat: 'yy-mm-dd', 75 | <% if (attr.dateConstraint === 'Past') { %>maxDate: -1<% } %> 76 | <% if (attr.dateConstraint === 'Future') { %>minDate: 1<% } %> 77 | };<% }}); %> 78 | 79 | $scope.ok = function () { 80 | $modalInstance.close($scope.<%= name %>); 81 | }; 82 | 83 | $scope.cancel = function () { 84 | $modalInstance.dismiss('cancel'); 85 | }; 86 | }]); 87 | -------------------------------------------------------------------------------- /entity/templates/public/js/entity/_entity-router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= baseName %>') 4 | .config(['$routeProvider', function ($routeProvider) { 5 | $routeProvider 6 | .when('/<%= pluralize(name) %>', { 7 | templateUrl: 'views/<%= name %>/<%= pluralize(name) %>.html', 8 | controller: '<%= _.capitalize(name) %>Controller', 9 | resolve:{ 10 | resolved<%= _.capitalize(name) %>: ['<%= _.capitalize(name) %>', function (<%= _.capitalize(name) %>) { 11 | return <%= _.capitalize(name) %>.query(); 12 | }] 13 | } 14 | }) 15 | }]); 16 | -------------------------------------------------------------------------------- /entity/templates/public/js/entity/_entity-service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= baseName %>') 4 | .factory('<%= _.capitalize(name) %>', ['$resource', function ($resource) { 5 | return $resource(':url/<%= baseName %>/<%= pluralize(name) %>/:id', {}, { 6 | 'query': { method: 'GET', isArray: true}, 7 | 'get': { method: 'GET'}, 8 | 'update': { method: 'PUT'} 9 | }); 10 | }]); 11 | -------------------------------------------------------------------------------- /entity/templates/public/views/entity/_entities.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

<%= _.capitalize(pluralize(name)) %>

4 | 5 | 64 | 65 | 68 | 69 |
70 | 71 | 72 | 73 | 74 | <% _.each(attrs, function (attr) { %> 75 | 76 | <% }); %> 77 | 78 | 79 | 80 | 81 | 82 | <% _.each(attrs, function (attr) { %> 83 | 84 | <% }); %> 85 | 97 | 98 | 99 |
ID<%= attr.attrName %>
{{<%= name %>.id}}{{<%= name %>.<%= attr.attrName %> <% if (attr.attrType === 'Date') { %> | date:'yyyy-MM-dd'<% } %>}} 86 | 91 | 96 |
100 |
101 |
102 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-angular-nancy", 3 | "version": "0.1.12", 4 | "description": "A Yeoman generator for AngularJS + Nancy", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "C#", 8 | "Nancy", 9 | "OrmLite", 10 | "AngularJS", 11 | "Bootstrap" 12 | ], 13 | "homepage": "https://github.com/rayokota/generator-angular-nancy", 14 | "bugs": "https://github.com/rayokota/generator-angular-nancy/issues", 15 | "author": { 16 | "name": "Robert Yokota", 17 | "email": "", 18 | "url": "https://github.com/rayokota" 19 | }, 20 | "main": "app/index.js", 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/rayokota/generator-angular-nancy.git" 24 | }, 25 | "scripts": { 26 | "test": "mocha" 27 | }, 28 | "dependencies": { 29 | "yeoman-generator": "~0.14.0", 30 | "URIjs": "~1.11.2", 31 | "lodash": "~2.4.1", 32 | "underscore.string": "~2.3.3", 33 | "pluralize": "~0.0.6", 34 | "asciify": "~1.3.3" 35 | }, 36 | "devDependencies": { 37 | "mocha": "~1.14.0" 38 | }, 39 | "peerDependencies": { 40 | "yo": ">=1.0.0" 41 | }, 42 | "engines": { 43 | "node": ">=0.8.0", 44 | "npm": ">=1.2.10" 45 | }, 46 | "licenses": [ 47 | { 48 | "type": "MIT" 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /test/test-creation.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | 4 | var path = require('path'); 5 | var helpers = require('yeoman-generator').test; 6 | 7 | 8 | describe('angular-nancy generator', function () { 9 | beforeEach(function (done) { 10 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 11 | if (err) { 12 | return done(err); 13 | } 14 | 15 | this.app = helpers.createGenerator('angular-nancy:app', [ 16 | '../../app' 17 | ]); 18 | done(); 19 | }.bind(this)); 20 | }); 21 | 22 | it('creates expected files', function (done) { 23 | var expected = [ 24 | // add files you expect to exist here. 25 | '.jshintrc', 26 | '.editorconfig' 27 | ]; 28 | 29 | helpers.mockPrompt(this.app, { 30 | 'someOption': true 31 | }); 32 | this.app.options['skip-install'] = true; 33 | this.app.run({}, function () { 34 | helpers.assertFiles(expected); 35 | done(); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/test-load.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | describe('angular-nancy generator', function () { 7 | it('can be imported without blowing up', function () { 8 | var app = require('../app'); 9 | assert(app !== undefined); 10 | }); 11 | }); 12 | --------------------------------------------------------------------------------