├── .gitignore ├── .idea ├── .name ├── encodings.xml ├── generator-express-rest-api.iml ├── jsLibraryMappings.xml ├── libraries │ └── generator_express_rest_api_node_modules.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml ├── vcs.xml └── workspace.xml ├── .travis.yml ├── LICENSE ├── README.md ├── generators ├── app │ ├── index.js │ └── templates │ │ ├── _package.json │ │ ├── app │ │ └── config │ │ │ ├── route-config.js │ │ │ ├── route.config.json │ │ │ ├── settings │ │ │ ├── settings-config.js │ │ │ ├── settings.config.dev.json │ │ │ ├── settings.config.prod.json │ │ │ └── settings.config.test.json │ │ │ └── worker-config.js │ │ ├── server.js │ │ └── test │ │ ├── mocha.opts │ │ └── tests.initialize.js ├── controller │ ├── index.js │ └── templates │ │ ├── app │ │ └── controllers │ │ │ └── _controller.js │ │ └── test │ │ └── spec │ │ └── controllers │ │ └── _controller.tests.js ├── repository │ ├── index.js │ └── templates │ │ ├── app │ │ └── repositories │ │ │ └── _repository.js │ │ └── test │ │ └── spec │ │ └── repositories │ │ └── _repository.tests.js └── service │ ├── index.js │ └── templates │ ├── app │ └── services │ │ └── _service.js │ └── test │ └── spec │ └── services │ └── _service.tests.js ├── package.json ├── projectFilesBackup └── .idea │ └── workspace.xml └── test ├── app └── index.tests.js ├── mocha.opts └── tests.initialize.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | generator-express-rest-api -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/generator-express-rest-api.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/libraries/generator_express_rest_api_node_modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 135 | 136 | 163 | 164 | 165 | 166 | true 167 | 168 | 169 | 170 | 171 | 172 | $PROJECT_DIR$/node_modules/mocha 173 | 174 | 175 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 213 | 214 | 215 | 216 | 219 | 220 | 223 | 224 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 239 | 240 | 243 | 244 | 247 | 248 | 251 | 252 | 255 | 256 | 257 | 258 | 261 | 262 | 265 | 266 | 269 | 270 | 273 | 274 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 329 | 330 | 331 | 332 | 333 | 334 | true 335 | 336 | 337 | 338 | 339 | 340 | $PROJECT_DIR$ 341 | true 342 | 343 | bdd 344 | 345 | 346 | false 347 | 348 | 349 | 350 | 351 | $PROJECT_DIR$ 352 | true 353 | 354 | bdd 355 | 356 | $PROJECT_DIR$/test 357 | false 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 1412338391155 372 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 404 | 405 | 408 | 411 | 412 | 413 | 415 | 416 | 417 | 418 | 419 | file://$PROJECT_DIR$/test/app/index.tests.js 420 | 6 421 | 423 | 424 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "0.11" 5 | - "0.10" 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tim Walker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/trwalker/generator-express-rest-api.svg)](https://travis-ci.org/trwalker/generator-express-rest-api) 2 | 3 | generator-express-rest-api 4 | ========================== 5 | 6 | ### Summary 7 | This is a Yeoman generator to quick scaffold a RESTful API using expresss, cluter-service, mocha, chai, sinon, and istanbul. The structure generated follows the MVC controller/service/repository pattern. 8 | 9 | ### Installing Yeoman 10 | http://yeoman.io/learning/index.html 11 | 12 | ### Windows Pre-Requisites 13 | Python 2.7.x: https://www.python.org/downloads/ 14 | 15 | ### Installing Generator 16 | `> npm install -g generator-express-rest-api` 17 | 18 | ### Scaffolding Application 19 | `> yo express-rest-api` 20 | 21 | ### Scaffolding Controller, Controller Test, and Updates Route Config 22 | `> yo express-rest-api:controller` 23 | 24 | ### Scaffolding Service and Service Test 25 | `> yo express-rest-api:service` 26 | 27 | ### Scaffolding Repository and Repository Test 28 | `> yo express-rest-api:repository` 29 | 30 | ### Application NPM Commands ### 31 | ``` 32 | // installs everything that is required to run your new application 33 | > npm run install-local 34 | ``` 35 | ``` 36 | // runs application 37 | > npm start 38 | ``` 39 | ``` 40 | // runs application in debug mode 41 | > npm run debug 42 | ``` 43 | ``` 44 | // runs mocha tests 45 | > npm test 46 | ``` 47 | ``` 48 | // runs istanbul code coverage 49 | > npm run test-coverage 50 | ``` 51 | 52 | ### Application Folder Structure Example 53 | ``` 54 | package.json 55 | server.js 56 | \app 57 | \..\config 58 | \..\settings 59 | \..\..\settings-config.js 60 | \..\route.config.json 61 | \..\route-config.js 62 | \..\worker-config.js 63 | 64 | \..\controllers 65 | \..\..\v1 66 | \..\..\..\users 67 | \..\..\..\..\users-controller.js 68 | 69 | \..\services 70 | \..\..\users 71 | \..\..\..\user-service.js 72 | 73 | \..\repositories 74 | \..\..\users 75 | \..\..\..\user-repository.js 76 | \test 77 | \..\spec 78 | \..\mocha.opts 79 | \..\tests.initialize.js 80 | 81 | \..\..\controllers 82 | \..\..\..\v1 83 | \..\..\..\..\users 84 | \..\..\..\..\..\users-controller.tests.js 85 | 86 | \..\..\services 87 | \..\..\..\users 88 | \..\..\..\..\user-service.tests.js 89 | 90 | \..\..\repositories 91 | \..\..\..\users 92 | \..\..\..\..\user-repository.tests.js 93 | ``` 94 | 95 | ### Example Application: Marvel Node API 96 | https://github.com/trwalker/marvel-node 97 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | var yeoman = require('yeoman-generator'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | 5 | module.exports = yeoman.generators.Base.extend({ 6 | initializingStep: function() { 7 | this.questions = []; 8 | this.applicationName = path.basename(process.cwd()); 9 | this.version = '1.0.0'; 10 | this.applicationDescription = ''; 11 | this.author = ''; 12 | this.gitRepository = ''; 13 | this.license = ''; 14 | }, 15 | 16 | promptingStep: function() { 17 | this.questions.push({ type : 'input', 18 | name : 'applicationName', 19 | message : 'Application Name', 20 | default : this.applicationName }); 21 | 22 | this.questions.push({ type : 'input', 23 | name : 'version', 24 | message : 'Version', 25 | default : this.version }); 26 | 27 | this.questions.push({ type : 'input', 28 | name : 'applicationDescription', 29 | message : 'Application Description', 30 | default : this.applicationDescription }); 31 | 32 | this.questions.push({ type : 'input', 33 | name : 'author', 34 | message : 'Author', 35 | default : this.author }); 36 | 37 | this.questions.push({ type : 'input', 38 | name : 'gitRepository', 39 | message : 'Git Repository', 40 | default : this.gitRepository }); 41 | 42 | this.questions.push({ type : 'input', 43 | name : 'license', 44 | message : 'License', 45 | default : this.license }); 46 | 47 | var done = this.async(); 48 | 49 | var generator = this; 50 | 51 | var handleAnswers = function(answers) { 52 | generator.applicationName = answers.applicationName; 53 | generator.version = answers.version; 54 | generator.applicationDescription = answers.applicationDescription; 55 | generator.author = answers.author; 56 | generator.gitRepository = answers.gitRepository; 57 | generator.license = answers.license; 58 | 59 | done(); 60 | }; 61 | 62 | this.prompt(this.questions, handleAnswers.bind(this)); 63 | }, 64 | 65 | configuringStep: function() { 66 | copyTemplate(this, '_package.json', 'package.json'); 67 | }, 68 | 69 | defaultStep: function() { 70 | }, 71 | 72 | writingStep: function() { 73 | copyTemplate(this, 'server.js', 'server.js'); 74 | 75 | copyTemplate(this, 'app/config/route.config.json', 'app/config/route.config.json'); 76 | copyTemplate(this, 'app/config/route-config.js', 'app/config/route-config.js'); 77 | copyTemplate(this, 'app/config/worker-config.js', 'app/config/worker-config.js'); 78 | 79 | copyTemplate(this, 'app/config/settings/settings-config.js', 'app/config/settings/settings-config.js'); 80 | copyTemplate(this, 'app/config/settings/settings.config.dev.json', 'app/config/settings/settings.config.dev.json'); 81 | copyTemplate(this, 'app/config/settings/settings.config.test.json', 'app/config/settings/settings.config.test.json'); 82 | copyTemplate(this, 'app/config/settings/settings.config.prod.json', 'app/config/settings/settings.config.prod.json'); 83 | 84 | copyTemplate(this, 'test/mocha.opts', 'test/mocha.opts'); 85 | copyTemplate(this, 'test/tests.initialize.js', 'test/tests.initialize.js'); 86 | }, 87 | 88 | conflictsStep: function() { 89 | }, 90 | 91 | installStep: function() { 92 | }, 93 | 94 | endStep: function() { 95 | this.npmInstall(['express', 'cluster-service', 'body-parser'], { 'save': true }); 96 | this.npmInstall(['mocha', 'chai', 'sinon', 'istanbul'], { 'saveDev': true }); 97 | } 98 | }); 99 | 100 | var copyTemplate = function(generator, template, path) { 101 | if(fs.existsSync(path)) { 102 | console.log('The file "' + path + '" already exists!'); 103 | } 104 | else { 105 | generator.template(template, path); 106 | } 107 | }; 108 | -------------------------------------------------------------------------------- /generators/app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= applicationName %>", 3 | "version": "<%= version %>", 4 | "description": "<%= applicationDescription %>", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "mocha", 8 | "test-coverage": "npm test && istanbul cover node_modules/mocha/bin/_mocha -- -R spec", 9 | "install-local": "npm install -g mocha & npm install -g node-inspector & npm install", 10 | "start": "node server.js 1 prod 127.0.0.1 3000 9000", 11 | "debug": "node-debug server.js 0 dev 127.0.0.1 3000 9000" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "<%= gitRepository %>" 16 | }, 17 | "keywords": [ 18 | "none" 19 | ], 20 | "author": "<%= author %>", 21 | "license": "<%= license %>", 22 | "devDependencies": { 23 | }, 24 | "dependencies": { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/route-config.js: -------------------------------------------------------------------------------- 1 | var settingsConfig = require('./settings/settings-config'); 2 | 3 | function RouteConfig() { 4 | } 5 | 6 | function registerRoutes(application) { 7 | var config = loadRouteConfig(); 8 | 9 | for(var i = 0, length = config.routes.length; i < length; i++) { 10 | var routeItem = config.routes[i]; 11 | 12 | var controller = loadController(routeItem); 13 | var route = getRoute(routeItem); 14 | var method = getMethod(routeItem); 15 | var action = getAction(routeItem); 16 | 17 | registerRoute(application, controller, route, method, action); 18 | } 19 | 20 | createConfigRoute(application); 21 | } 22 | 23 | function loadRouteConfig() { 24 | var config; 25 | 26 | try { 27 | config = require('./route.config.json'); 28 | 29 | if(!config.routes || config.routes.length === 0) { 30 | throw '"routes" not defined'; 31 | } 32 | } 33 | catch(e) { 34 | throw 'Unable to parse "lib/config/route.config.json": ' + e; 35 | } 36 | 37 | return config; 38 | } 39 | 40 | function loadController(routeItem) { 41 | var controller; 42 | 43 | if(!routeItem || !routeItem.controller) { 44 | throw 'Undefined "controller" property in "lib/config/route.config.json"'; 45 | } 46 | 47 | try { 48 | controller = require(routeItem.controller); 49 | } 50 | catch(e) { 51 | throw 'Unable to load ' + routeItem.controller + ": " + e; 52 | } 53 | 54 | return controller; 55 | } 56 | 57 | function getRoute(routeItem) { 58 | if(!routeItem || !routeItem.route || routeItem.route.length === 0) { 59 | throw 'Undefined or empty "route" property in "lib/config/route.config.json"'; 60 | } 61 | 62 | return routeItem.route; 63 | } 64 | 65 | function getMethod(routeItem) { 66 | if(!routeItem || !routeItem.method || routeItem.method.length === 0) { 67 | throw 'Undefined or empty "method" property in "lib/config/route.config.json"'; 68 | } 69 | 70 | var method = routeItem.method.toLowerCase(); 71 | 72 | switch(method) { 73 | case 'get': 74 | case 'put': 75 | case 'post': 76 | case 'delete': 77 | return method; 78 | break; 79 | default: 80 | throw 'Invalid REST "method" property in "lib/config/route.config.json": ' + method; 81 | } 82 | } 83 | 84 | function getAction(routeItem) { 85 | if(!routeItem || !routeItem.action || routeItem.action.length === 0) { 86 | return getMethod(routeItem); 87 | } 88 | return routeItem.action; 89 | } 90 | 91 | 92 | function registerRoute(application, controller, route, method, action) { 93 | application.route(route)[method](function(req, res, next) { 94 | controller[action](req, res, next); 95 | }); 96 | } 97 | 98 | function createConfigRoute(application) { 99 | application.route('/config').get(function(req, res, next) { 100 | res.status(200).json(settingsConfig.settings); 101 | }); 102 | } 103 | 104 | RouteConfig.prototype = { 105 | registerRoutes: registerRoutes 106 | }; 107 | 108 | var routeConfig = new RouteConfig(); 109 | 110 | module.exports = routeConfig; 111 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/route.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/settings/settings-config.js: -------------------------------------------------------------------------------- 1 | var os = require('os'); 2 | var commandLineArgs = process.argv; 3 | 4 | function SettingsConfig() { 5 | this.settings = {}; 6 | 7 | initializeSettings(this.settings); 8 | } 9 | 10 | function initializeSettings(settings) { 11 | createArgumentSettings(settings); 12 | loadConfigSettings(settings); 13 | loadServerSettings(settings); 14 | } 15 | 16 | function createArgumentSettings(settings) { 17 | settings.clusterEnabled = commandLineArgs[2] ? parseInt(commandLineArgs[2]) : 0; 18 | settings.environment = commandLineArgs[3] ? commandLineArgs[3].toLowerCase() : 'prod'; 19 | settings.hostName = commandLineArgs[4] ? commandLineArgs[4] : '127.0.0.1'; 20 | settings.masterPort = commandLineArgs[5] ? parseInt(commandLineArgs[5]) : 3000; 21 | settings.workerPort = commandLineArgs[6] ? parseInt(commandLineArgs[6]) : 9000; 22 | } 23 | 24 | function loadConfigSettings(settings) { 25 | var config = loadEnvironmentConfigFile(settings); 26 | 27 | var settingsLength = config.settings.length; 28 | 29 | for(var i = 0; i < settingsLength; i++) { 30 | var configSetting = config.settings[i]; 31 | 32 | if(configSetting.name && configSetting.value) { 33 | settings[configSetting.name] = configSetting.value; 34 | } 35 | } 36 | } 37 | 38 | function loadServerSettings(settings) { 39 | settings.serverName = os.hostname().toLowerCase(); 40 | settings.serverCores = os.cpus().length; 41 | } 42 | 43 | function loadEnvironmentConfigFile(settings) { 44 | var config; 45 | 46 | var configLocation = './settings.config.prod.json'; 47 | 48 | switch(settings.environment) { 49 | case 'dev': 50 | configLocation = './settings.config.dev.json'; 51 | break; 52 | case 'test': 53 | configLocation = './settings.config.test.json'; 54 | break; 55 | } 56 | 57 | try { 58 | config = require(configLocation); 59 | } 60 | catch(e) { 61 | throw 'Unable to parse "lib/config/settings/"' + configLocation + ': ' + e; 62 | } 63 | 64 | if(!config.settings) { 65 | throw 'Property "settings" is no defined: ' + configLocation; 66 | } 67 | 68 | return config; 69 | } 70 | 71 | var settingsConfig = new SettingsConfig(); 72 | 73 | module.exports = settingsConfig; 74 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/settings/settings.config.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": [ 3 | { "name": "queueLength", "value": 10 } 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/settings/settings.config.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": [ 3 | { "name": "queueLength", "value": 511 } 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/settings/settings.config.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": [ 3 | { "name": "queueLength", "value": 10 } 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /generators/app/templates/app/config/worker-config.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var express = require('express'); 3 | var application = express(); 4 | var bodyParser = require('body-parser'); 5 | var routeConfig = require('./route-config'); 6 | var settingsConfig = require('./settings/settings-config'); 7 | 8 | function configureWorker(application) { 9 | configureApplication(application); 10 | configureRoutes(application); 11 | 12 | startServer(application); 13 | } 14 | 15 | function configureApplication(application) { 16 | application.use(bodyParser.json()); 17 | 18 | application.use(function(req, res, next) { 19 | res.set('Cache-Control', 'no-cache, no-store, must-revalidate'); 20 | res.set('Pragma', 'no-cache'); 21 | res.set('Expires', '0'); 22 | res.type('application/json'); 23 | next(); 24 | }); 25 | } 26 | 27 | function configureRoutes(application) { 28 | routeConfig.registerRoutes(application); 29 | } 30 | 31 | function startServer(application) { 32 | var server = http.createServer(application); 33 | 34 | server.listen(settingsConfig.settings.workerPort, settingsConfig.settings.hostName, settingsConfig.settings.queueLength, function() { 35 | console.log('listening at http://%s:%s', settingsConfig.settings.hostName, settingsConfig.settings.workerPort); 36 | }); 37 | } 38 | 39 | configureWorker(application); 40 | -------------------------------------------------------------------------------- /generators/app/templates/server.js: -------------------------------------------------------------------------------- 1 | var settingsConfig = require('./app/config/settings/settings-config'); 2 | 3 | if(settingsConfig.settings.clusterEnabled === 1) { 4 | require('cluster-service').start({ workers: './app/config/worker-config.js', 5 | accessKey: settingsConfig.settings.clusterAccessKey, 6 | host: settingsConfig.settings.hostName, 7 | port: settingsConfig.settings.masterPort }); 8 | } 9 | else { 10 | require('./app/config/worker-config.js'); 11 | } 12 | -------------------------------------------------------------------------------- /generators/app/templates/test/mocha.opts: -------------------------------------------------------------------------------- 1 | -R spec 2 | -u bdd 3 | --recursive -------------------------------------------------------------------------------- /generators/app/templates/test/tests.initialize.js: -------------------------------------------------------------------------------- 1 | 2 | beforeEach(function() { 3 | global.expect = require('chai').expect; 4 | global.sinon = require('sinon'); 5 | }); -------------------------------------------------------------------------------- /generators/controller/index.js: -------------------------------------------------------------------------------- 1 | var yeoman = require('yeoman-generator'); 2 | var fs = require('fs'); 3 | 4 | const routeConfigRequirePath = '/app/config/route.config.json'; 5 | 6 | module.exports = yeoman.generators.Base.extend({ 7 | initializingStep: function() { 8 | this.questions = []; 9 | this.controllerName = 'clowns'; 10 | this.controllerClassName = 'Clowns'; 11 | this.controllerInstanceName = 'clowns'; 12 | this.controllerVersion = 'v1'; 13 | this.controllerFolderPath = 'circus'; 14 | this.controllerRequirePathFromTest = ''; 15 | this.controllerRoute = '/clowns/:clownid'; 16 | this.controllerMethod = 'GET'; 17 | this.httpMethods = [ 'GET', 'PUT', 'POST', 'DELETE' ]; 18 | }, 19 | 20 | promptingStep: function() { 21 | this.questions.push({ type : 'input', 22 | name : 'controllerName', 23 | message : 'Controller Name (dash delimited, leave off -controller)', 24 | default : this.controllerName }); 25 | 26 | this.questions.push({ type : 'input', 27 | name : 'controllerVersion', 28 | message : 'Controller Version', 29 | default : this.controllerVersion }); 30 | 31 | this.questions.push({ type : 'input', 32 | name : 'controllerFolderPath', 33 | message : 'Controller Folder Path (relative path after the version folder, no starting or training slashes)', 34 | default : this.controllerFolderPath }); 35 | 36 | this.questions.push({ type : 'input', 37 | name : 'controllerRoute', 38 | message : 'Controller Route (HTTP request route without the version)', 39 | default : this.controllerRoute }); 40 | 41 | this.questions.push({ type : 'list', 42 | name : 'controllerMethod', 43 | message : 'Controller Method', 44 | choices : this.httpMethods, 45 | default : 0 }); 46 | 47 | var done = this.async(); 48 | 49 | var generator = this; 50 | 51 | var handleAnswers = function(answers) { 52 | generator.controllerName = answers.controllerName.toLowerCase(); 53 | generator.controllerClassName = generator._.classify(answers.controllerName); 54 | generator.controllerInstanceName = generator._.camelize(generator.controllerName); 55 | generator.controllerVersion = answers.controllerVersion; 56 | generator.controllerFolderPath = answers.controllerFolderPath.toLowerCase(); 57 | generator.controllerRequirePathFromTest = getTestRequirePrefix(generator.controllerFolderPath) + 'app/controllers/' + generator.controllerVersion + '/' + generator.controllerFolderPath + '/' + generator.controllerName + "-controller"; 58 | generator.controllerRoute = answers.controllerRoute.toLowerCase(); 59 | generator.controllerMethod = answers.controllerMethod; 60 | 61 | done(); 62 | }; 63 | 64 | this.prompt(this.questions, handleAnswers.bind(this)); 65 | }, 66 | 67 | configuringStep: function() { 68 | }, 69 | 70 | defaultStep: function() { 71 | }, 72 | 73 | writingStep: function() { 74 | if(tryUpdateRouteConfig(this)) { 75 | copyController(this); 76 | copyControllerTest(this); 77 | } 78 | }, 79 | 80 | conflictsStep: function() { 81 | }, 82 | 83 | installStep: function() { 84 | }, 85 | 86 | endStep: function() { 87 | } 88 | }); 89 | 90 | function getTestRequirePrefix(controllerFolderPath) { 91 | var requirePrefix = '../../../../'; 92 | 93 | if(controllerFolderPath.length !== 0) { 94 | var folderCount = (controllerFolderPath.match(/\//g) || []).length + 1; 95 | 96 | for(var i = 0; i < folderCount; i++) { 97 | requirePrefix = '../' + requirePrefix; 98 | } 99 | } 100 | 101 | return requirePrefix; 102 | } 103 | 104 | function copyController(generator) { 105 | var controllerDestination = generator.destinationRoot() + 106 | '/app/controllers/' + 107 | generator.controllerVersion + 108 | '/' + 109 | generator.controllerFolderPath + 110 | '/' + 111 | generator.controllerName.toLowerCase() + 112 | '-controller.js'; 113 | 114 | copyTemplate(generator, 'app/controllers/_controller.js', controllerDestination); 115 | } 116 | 117 | function copyControllerTest(generator) { 118 | var controllerTestDestination = generator.destinationRoot() + 119 | '/test/spec/controllers/' + 120 | generator.controllerVersion + 121 | '/' + 122 | generator.controllerFolderPath + 123 | '/' + 124 | generator.controllerName.toLowerCase() + 125 | '-controller.tests.js'; 126 | 127 | copyTemplate(generator, 'test/spec/controllers/_controller.tests.js', controllerTestDestination); 128 | } 129 | 130 | function tryUpdateRouteConfig(generator) { 131 | var success = false; 132 | 133 | var routeConfigPath = generator.destinationRoot() + routeConfigRequirePath; 134 | 135 | try { 136 | var routeConfig = require(routeConfigPath); 137 | 138 | if (routeConfig && routeConfig.routes) { 139 | var controllerRoute = '/' + generator.controllerVersion + generator.controllerRoute; 140 | 141 | if(doesRouteExistInConfig(routeConfig, controllerRoute)) { 142 | console.log('Route already exists in route.config.json. Route: ' + controllerRoute); 143 | console.log('If you want to add a new http method to an existing controller you must modify ' + routeConfigRequirePath + ' and add the method to the controller.'); 144 | } 145 | else { 146 | writeToRouteConfig(generator, routeConfig, routeConfigPath, controllerRoute); 147 | success = true; 148 | } 149 | } 150 | else { 151 | console.log('Badly formatted route config "' + routeConfigPath + '", routes array is not defined'); 152 | } 153 | } 154 | catch (e) { 155 | var message = 'Error parsing and updating route config "' + routeConfigPath + '":' + e; 156 | console.log(message); 157 | } 158 | 159 | return success; 160 | } 161 | 162 | function doesRouteExistInConfig(routeConfig, controllerRoute) { 163 | var i, routesLength; 164 | 165 | for(i = 0, routesLength = routeConfig.routes.length; i < routesLength; i++) { 166 | var routeItem = routeConfig.routes[i]; 167 | if(routeItem.route === controllerRoute) { 168 | return true; 169 | } 170 | } 171 | 172 | return false; 173 | } 174 | 175 | function writeToRouteConfig(generator, routeConfig, routeConfigPath, controllerRoute) { 176 | var controllerRequirePath = getControllerRequirePath(generator); 177 | 178 | routeConfig.routes.push({ route: controllerRoute, 179 | method: generator.controllerMethod, 180 | controller: controllerRequirePath }); 181 | 182 | fs.writeFileSync(routeConfigPath, JSON.stringify(routeConfig, null, 2)); 183 | } 184 | 185 | function getControllerRequirePath(generator) { 186 | return '../controllers/' + 187 | generator.controllerVersion + 188 | '/' + 189 | generator.controllerFolderPath + 190 | '/' + 191 | generator.controllerName.toLowerCase() + 192 | '-controller'; 193 | } 194 | 195 | function copyTemplate(generator, template, path) { 196 | if(fs.existsSync(path)) { 197 | console.log('The file "' + path + '" already exists!'); 198 | } 199 | else { 200 | generator.template(template, path); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /generators/controller/templates/app/controllers/_controller.js: -------------------------------------------------------------------------------- 1 | 2 | function <%= controllerClassName %>Controller() { 3 | } 4 | 5 | function <%= controllerMethod.toLowerCase() %>(req, res, next) { 6 | res.status(200).json({ hello: 'world' }); 7 | } 8 | 9 | <%= controllerClassName %>Controller.prototype = { 10 | <%= controllerMethod.toLowerCase() %>: <%= controllerMethod.toLowerCase() %> 11 | }; 12 | 13 | var <%= controllerInstanceName %>Controller = new <%= controllerClassName %>Controller(); 14 | 15 | module.exports = <%= controllerInstanceName %>Controller; 16 | -------------------------------------------------------------------------------- /generators/controller/templates/test/spec/controllers/_controller.tests.js: -------------------------------------------------------------------------------- 1 | 2 | describe('<%= controllerClassName %>Controller Tests', function() { 3 | 4 | var <%= controllerInstanceName %>Controller; 5 | var req; 6 | var res; 7 | var next; 8 | 9 | beforeEach(function() { 10 | req = {}; 11 | res = { status: function(code) { return { json: function(obj) {} }} }; 12 | 13 | sinon.spy(res, "status"); 14 | 15 | <%= controllerInstanceName %>Controller = require('<%= controllerRequirePathFromTest %>'); 16 | }); 17 | 18 | describe('<%= controllerMethod.toLowerCase() %>()', function() { 19 | 20 | it('should be a function', function(done) { 21 | expect(<%= controllerInstanceName %>Controller.<%= controllerMethod.toLowerCase() %>).to.be.a('function'); 22 | done(); 23 | }); 24 | 25 | it('should call res.status() one time', function(done) { 26 | <%= controllerInstanceName %>Controller.<%= controllerMethod.toLowerCase() %>(req, res, next); 27 | 28 | expect(res.status.callCount).to.equal(1); 29 | done(); 30 | }); 31 | 32 | it('should call res.status() with 200', function(done) { 33 | <%= controllerInstanceName %>Controller.<%= controllerMethod.toLowerCase() %>(req, res, next); 34 | 35 | expect(res.status.calledWith(200)).to.equal(true); 36 | done(); 37 | }); 38 | 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /generators/repository/index.js: -------------------------------------------------------------------------------- 1 | var yeoman = require('yeoman-generator'); 2 | var fs = require('fs'); 3 | 4 | module.exports = yeoman.generators.Base.extend({ 5 | initializingStep: function() { 6 | this.questions = []; 7 | this.repositoryName = 'clown'; 8 | this.repositoryClassName = 'Clown'; 9 | this.repositoryInstanceName = 'clown'; 10 | this.repositoryFolderPath = 'circus'; 11 | this.repositoryRequirePathFromTest = ''; 12 | }, 13 | 14 | promptingStep: function() { 15 | this.questions.push({ type : 'input', 16 | name : 'repositoryName', 17 | message : 'Repository Name (dash delimited, leave off -repository)', 18 | default : this.repositoryName }); 19 | 20 | this.questions.push({ type : 'input', 21 | name : 'repositoryFolderPath', 22 | message : 'Repository Folder Path (relative path, no starting or training slashes)', 23 | default : this.repositoryFolderPath }); 24 | 25 | var done = this.async(); 26 | 27 | var generator = this; 28 | 29 | var handleAnswers = function(answers) { 30 | generator.repositoryName = answers.repositoryName.toLowerCase(); 31 | generator.repositoryClassName = generator._.classify(answers.repositoryName); 32 | generator.repositoryInstanceName = generator._.camelize(generator.repositoryName); 33 | generator.repositoryFolderPath = answers.repositoryFolderPath.toLowerCase(); 34 | generator.repositoryRequirePathFromTest = getTestRequirePrefix(generator.repositoryFolderPath) + 'app/repositories/' + generator.repositoryFolderPath + '/' + generator.repositoryName + '-repository'; 35 | 36 | done(); 37 | }; 38 | 39 | this.prompt(this.questions, handleAnswers.bind(this)); 40 | }, 41 | 42 | configuringStep: function() { 43 | }, 44 | 45 | defaultStep: function() { 46 | }, 47 | 48 | writingStep: function() { 49 | copyRepository(this); 50 | copyRepositoryTest(this); 51 | }, 52 | 53 | conflictsStep: function() { 54 | }, 55 | 56 | installStep: function() { 57 | }, 58 | 59 | endStep: function() { 60 | } 61 | }); 62 | 63 | function getTestRequirePrefix(repositoryFolderPath) { 64 | var requirePrefix = '../../../'; 65 | 66 | if(repositoryFolderPath.length !== 0) { 67 | var folderCount = (repositoryFolderPath.match(/\//g) || []).length + 1; 68 | 69 | for(var i = 0; i < folderCount; i++) { 70 | requirePrefix = '../' + requirePrefix; 71 | } 72 | } 73 | 74 | return requirePrefix; 75 | } 76 | 77 | function copyRepository(generator) { 78 | var repositoryDestination = generator.destinationRoot() + 79 | '/app/repositories/' + 80 | generator.repositoryFolderPath + 81 | '/' + 82 | generator.repositoryName.toLowerCase() + 83 | '-repository.js'; 84 | 85 | copyTemplate(generator, 'app/repositories/_repository.js', repositoryDestination); 86 | } 87 | 88 | function copyRepositoryTest(generator) { 89 | var repositoryTestDestination = generator.destinationRoot() + 90 | '/test/spec/repositories/' + 91 | generator.repositoryFolderPath + 92 | '/' + 93 | generator.repositoryName.toLowerCase() + 94 | '-repository.tests.js'; 95 | 96 | copyTemplate(generator, 'test/spec/repositories/_repository.tests.js', repositoryTestDestination); 97 | } 98 | 99 | function copyTemplate(generator, template, path) { 100 | if(fs.existsSync(path)) { 101 | console.log('The file "' + path + '" already exists!'); 102 | } 103 | else { 104 | generator.template(template, path); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /generators/repository/templates/app/repositories/_repository.js: -------------------------------------------------------------------------------- 1 | 2 | function <%= repositoryClassName %>Repository() { 3 | } 4 | 5 | function get<%= repositoryClassName %>Data(id) { 6 | return { id: id }; 7 | } 8 | 9 | <%= repositoryClassName %>Repository.prototype = { 10 | get<%= repositoryClassName %>Data: get<%= repositoryClassName %>Data 11 | }; 12 | 13 | var <%= repositoryInstanceName %>Repository = new <%= repositoryClassName %>Repository(); 14 | 15 | module.exports = <%= repositoryInstanceName %>Repository; 16 | -------------------------------------------------------------------------------- /generators/repository/templates/test/spec/repositories/_repository.tests.js: -------------------------------------------------------------------------------- 1 | 2 | describe('<%= repositoryClassName %>Repository Tests', function() { 3 | 4 | var <%= repositoryInstanceName %>Repository; 5 | 6 | beforeEach(function() { 7 | <%= repositoryInstanceName %>Repository = require('<%= repositoryRequirePathFromTest %>'); 8 | }); 9 | 10 | describe('get<%= repositoryClassName %>Data()', function() { 11 | 12 | it('should be a function', function(done) { 13 | expect(<%= repositoryInstanceName %>Repository.get<%= repositoryClassName %>Data).to.be.a('function'); 14 | done(); 15 | }); 16 | 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /generators/service/index.js: -------------------------------------------------------------------------------- 1 | var yeoman = require('yeoman-generator'); 2 | var fs = require('fs'); 3 | 4 | module.exports = yeoman.generators.Base.extend({ 5 | initializingStep: function() { 6 | this.questions = []; 7 | this.serviceName = 'clown'; 8 | this.serviceClassName = 'Clown'; 9 | this.serviceInstanceName = 'clown'; 10 | this.serviceFolderPath = 'circus'; 11 | this.serviceRequirePathFromTest = ''; 12 | }, 13 | 14 | promptingStep: function() { 15 | this.questions.push({ type : 'input', 16 | name : 'serviceName', 17 | message : 'Service Name (dash delimited, leave off -service)', 18 | default : this.serviceName }); 19 | 20 | this.questions.push({ type : 'input', 21 | name : 'serviceFolderPath', 22 | message : 'Service Folder Path (relative path, no starting or training slashes)', 23 | default : this.serviceFolderPath }); 24 | 25 | var done = this.async(); 26 | 27 | var generator = this; 28 | 29 | var handleAnswers = function(answers) { 30 | generator.serviceName = answers.serviceName.toLowerCase(); 31 | generator.serviceClassName = generator._.classify(answers.serviceName); 32 | generator.serviceInstanceName = generator._.camelize(generator.serviceName); 33 | generator.serviceFolderPath = answers.serviceFolderPath.toLowerCase(); 34 | generator.serviceRequirePathFromTest = getTestRequirePrefix(generator.serviceFolderPath) + 'app/services/' + generator.serviceFolderPath + '/' + generator.serviceName + '-service'; 35 | 36 | done(); 37 | }; 38 | 39 | this.prompt(this.questions, handleAnswers.bind(this)); 40 | }, 41 | 42 | configuringStep: function() { 43 | }, 44 | 45 | defaultStep: function() { 46 | }, 47 | 48 | writingStep: function() { 49 | copyService(this); 50 | copyServiceTest(this); 51 | }, 52 | 53 | conflictsStep: function() { 54 | }, 55 | 56 | installStep: function() { 57 | }, 58 | 59 | endStep: function() { 60 | } 61 | }); 62 | 63 | function getTestRequirePrefix(serviceFolderPath) { 64 | var requirePrefix = '../../../'; 65 | 66 | if(serviceFolderPath.length !== 0) { 67 | var folderCount = (serviceFolderPath.match(/\//g) || []).length + 1; 68 | 69 | for(var i = 0; i < folderCount; i++) { 70 | requirePrefix = '../' + requirePrefix; 71 | } 72 | } 73 | 74 | return requirePrefix; 75 | } 76 | 77 | function copyService(generator) { 78 | var serviceDestination = generator.destinationRoot() + 79 | '/app/services/' + 80 | generator.serviceFolderPath + 81 | '/' + 82 | generator.serviceName.toLowerCase() + 83 | '-service.js'; 84 | 85 | copyTemplate(generator, 'app/services/_service.js', serviceDestination); 86 | } 87 | 88 | function copyServiceTest(generator) { 89 | var serviceTestDestination = generator.destinationRoot() + 90 | '/test/spec/services/' + 91 | generator.serviceFolderPath + 92 | '/' + 93 | generator.serviceName.toLowerCase() + 94 | '-service.tests.js'; 95 | 96 | copyTemplate(generator, 'test/spec/services/_service.tests.js', serviceTestDestination); 97 | } 98 | 99 | function copyTemplate(generator, template, path) { 100 | if(fs.existsSync(path)) { 101 | console.log('The file "' + path + '" already exists!'); 102 | } 103 | else { 104 | generator.template(template, path); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /generators/service/templates/app/services/_service.js: -------------------------------------------------------------------------------- 1 | 2 | function <%= serviceClassName %>Service() { 3 | } 4 | 5 | function lookup<%= serviceClassName %>(id) { 6 | return { id: id }; 7 | } 8 | 9 | <%= serviceClassName %>Service.prototype = { 10 | lookup<%= serviceClassName %>: lookup<%= serviceClassName %> 11 | }; 12 | 13 | var <%= serviceInstanceName %>Service = new <%= serviceClassName %>Service(); 14 | 15 | module.exports = <%= serviceInstanceName %>Service; 16 | -------------------------------------------------------------------------------- /generators/service/templates/test/spec/services/_service.tests.js: -------------------------------------------------------------------------------- 1 | 2 | describe('<%= serviceClassName %>Service Tests', function() { 3 | 4 | var <%= serviceInstanceName %>Service; 5 | 6 | beforeEach(function() { 7 | <%= serviceInstanceName %>Service = require('<%= serviceRequirePathFromTest %>'); 8 | }); 9 | 10 | describe('lookup<%= serviceClassName %>', function() { 11 | 12 | it('should be a function', function(done) { 13 | expect(<%= serviceInstanceName %>Service.lookup<%= serviceClassName %>).to.be.a('function'); 14 | done(); 15 | }); 16 | 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-express-rest-api", 3 | "version": "1.2.1", 4 | "description": "Yeoman generator for a RESTful API using express, cluster-service, mocha, chai, sinon, and istanbul", 5 | "author": "Tim Walker ", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "mocha" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/trwalker/generator-express-rest-api.git" 13 | }, 14 | "keywords": [ 15 | "yo", 16 | "yeoman", 17 | "generator", 18 | "express", 19 | "rest", 20 | "api", 21 | "service" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/trwalker/generator-express-rest-api/issues" 25 | }, 26 | "homepage": "https://github.com/trwalker/generator-express-rest-api", 27 | "dependencies": { 28 | "yeoman-generator": "^0.17.3" 29 | }, 30 | "devDependencies": { 31 | "chai": "^1.9.1", 32 | "mocha": "^1.21.4", 33 | "sinon": "^1.10.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /projectFilesBackup/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 68 | 69 | 94 | 95 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | 136 | 139 | 140 | 143 | 144 | 145 | 146 | 149 | 150 | 153 | 154 | 157 | 158 | 159 | 160 | 163 | 164 | 167 | 168 | 171 | 172 | 175 | 176 | 177 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 223 | 224 | 233 | 234 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 1412338391155 266 | 1412338391155 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 297 | 300 | 301 | 302 | 304 | 305 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | -------------------------------------------------------------------------------- /test/app/index.tests.js: -------------------------------------------------------------------------------- 1 | 2 | describe('App Generator Tests', function() { 3 | 4 | var appGenerator; 5 | 6 | beforeEach(function() { 7 | appGenerator = require('../../generators/app/index'); 8 | }); 9 | 10 | describe('generator', function() { 11 | 12 | it('should be defined', function(done) { 13 | expect(appGenerator).to.exist; 14 | 15 | done(); 16 | }); 17 | 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | -R spec 2 | -u bdd 3 | --recursive 4 | -------------------------------------------------------------------------------- /test/tests.initialize.js: -------------------------------------------------------------------------------- 1 | 2 | beforeEach(function() { 3 | global.expect = require('chai').expect; 4 | global.sinon = require('sinon'); 5 | }); 6 | --------------------------------------------------------------------------------