├── .editorconfig ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── app ├── bootstrap.ts ├── components │ ├── about │ │ ├── about.html │ │ ├── about.ts │ │ └── about_spec.ts │ ├── app │ │ ├── app.css │ │ ├── app.html │ │ └── app.ts │ ├── home │ │ ├── home.css │ │ ├── home.html │ │ ├── home.ts │ │ └── home_spec.ts │ └── users │ │ ├── services │ │ ├── interfaces.ts │ │ └── user_service.ts │ │ ├── user_details │ │ ├── user_details.html │ │ └── user_details.ts │ │ ├── user_form │ │ ├── user_form.html │ │ └── user_form.ts │ │ ├── users.css │ │ ├── users.html │ │ ├── users.ts │ │ ├── users_home │ │ ├── users_home.html │ │ └── users_home.ts │ │ └── users_list │ │ ├── users_list.html │ │ └── users_list.ts ├── directives │ ├── loading_btn.ts │ └── set_active.ts ├── index.html └── services │ ├── component_proxy.ts │ ├── name_list.ts │ └── name_list_spec.ts ├── gulpfile.ts ├── karma.conf.js ├── package.json ├── test-main.js ├── tools ├── config.ts ├── tasks │ ├── build.bundles.ts │ ├── build.deps.ts │ ├── build.docs.ts │ ├── build.html_css.prod.ts │ ├── build.img.dev.ts │ ├── build.index.ts │ ├── build.js.dev.ts │ ├── build.js.prod.ts │ ├── build.sass.dev.ts │ ├── build.test.ts │ ├── check.versions.ts │ ├── clean.ts │ ├── karma.start.ts │ ├── npm.ts │ ├── serve.docs.ts │ ├── server.start.ts │ ├── tsd.ts │ ├── tslint.ts │ ├── watch.dev.ts │ ├── watch.serve.ts │ └── watch.test.ts ├── typings │ ├── connect-livereload.d.ts │ ├── gulp-load-plugins.d.ts │ ├── karma.d.ts │ ├── merge-stream.d.ts │ ├── open.d.ts │ ├── run-sequence.d.ts │ ├── slash.d.ts │ ├── systemjs-builder.d.ts │ ├── tiny-lr.d.ts │ └── yargs.d.ts ├── utils.ts └── utils │ ├── server.ts │ ├── tasks_tools.ts │ ├── template-injectables.ts │ └── template-locals.ts ├── tsconfig.json ├── tsd.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.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 | .tsdrc 30 | 31 | #IDE configuration files 32 | .idea 33 | .vscode 34 | 35 | dist 36 | dev 37 | docs 38 | lib 39 | test 40 | tools/typings/tsd 41 | tmp 42 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "immed": true, 4 | "newcap": true, 5 | "noarg": true, 6 | "noempty": true, 7 | "nonew": true, 8 | "trailing": true, 9 | "maxlen": 200, 10 | "boss": true, 11 | "eqnull": true, 12 | "expr": true, 13 | "globalstrict": true, 14 | "laxbreak": true, 15 | "loopfunc": true, 16 | "sub": true, 17 | "undef": true, 18 | "indent": 2, 19 | "unused": true, 20 | 21 | "node": true, 22 | "globals": { 23 | "System": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Minko Gechev 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WARNING 2 | 3 | This project is no longer maintained. For Angular 2 starter take a look at the [angular2-seed](https://github.com/mgechev/angular2-seed), that this project is based on. 4 | 5 | # Introduction 6 | 7 | Sample application based upon [mgechev](https://github.com/mgechev)/ [angular2-seed](https://github.com/mgechev/angular2-seed). 8 | 9 | [![Join the chat at https://gitter.im/mgechev/angular2-seed](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mgechev/angular2-seed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 10 | [![Dependency Status](https://david-dm.org/mgechev/angular2-seed.svg)](https://david-dm.org/mgechev/angular2-seed) 11 | [![devDependency Status](https://david-dm.org/mgechev/angular2-seed/dev-status.svg)](https://david-dm.org/mgechev/angular2-seed#info=devDependencies) 12 | 13 | **Note:** Angular 2.0 is not production ready yet! This project is perfect for playing around with the latest versions but do not start new projects with it since a lot of new changes are going to be introduced until the framework is officially released. 14 | 15 | # Features 16 | 17 | * Component styling 18 | * Custom Directive 19 | * Router module (implementing child routes*) 20 | * Http module 21 | * Form module (using template driven form approach) 22 | 23 | # How to start 24 | 25 | **Note** that this seed project requires node v0.12.x or higher and npm 3.x.x. 26 | 27 | ```bash 28 | npm install 29 | # dev 30 | npm run serve.dev 31 | ``` 32 | _Does not rely on any global dependencies._ 33 | 34 | # Directory Structure 35 | 36 | ``` 37 | . 38 | ├── app 39 | │   ├── components 40 | │   │   ├── about 41 | │   │   │   ├── about.html 42 | │   │   │   ├── about.ts 43 | │   │   │   └── about_spec.ts 44 | │   │   └── home 45 | │   │   ├── home.css 46 | │   │   ├── home.html 47 | │   │   ├── home.ts 48 | │   │   └── home_spec.ts 49 | │   ├── services 50 | │   │   ├── name_list.ts 51 | │   │ └── name_list_spec.ts 52 | │ ├── typings 53 | │   ├── app.css 54 | │   ├── app.html 55 | │   ├── app.ts 56 | │   ├── index.html 57 | │   └── init.ts 58 | ├── dist 59 | │   ├── dev 60 | │   └── prod 61 | ├── tools 62 | │   ├── tasks 63 | │   ├── utils.js 64 | │   └── workflow.config.js 65 | ├── tsd_typings 66 | ├── gulpfile.js 67 | ├── karma.conf.js 68 | ├── package.json 69 | ├── test-main.js 70 | ├── tsconfig.json 71 | └── tsd.json 72 | ``` 73 | 74 | # Configuration 75 | 76 | Default application server configuration 77 | 78 | ```javascript 79 | var PORT = 5555; 80 | var LIVE_RELOAD_PORT = 4002; 81 | var APP_BASE = '/'; 82 | ``` 83 | 84 | Configure at runtime 85 | 86 | ```bash 87 | npm run serve.dev -- --port 8080 --reload-port 4000 --base /my-app/ 88 | ``` 89 | 90 | # Now to extend? 91 | 92 | If you want to use your custom libraries: 93 | 94 | ```bash 95 | npm install my-library --save 96 | vim gulpfile.js 97 | ``` 98 | Add reference to the installed library in `PATH.src.lib` into `./tools/workflow.config.js`. 99 | 100 | # Running test 101 | 102 | ```bash 103 | # In a single bash window 104 | npm run test 105 | 106 | # Debug - In two bash windows 107 | npm run karma # 1st window 108 | npm run test.dev # 2nd window 109 | ``` 110 | 111 | # Contributors 112 | 113 | [mgechev](https://github.com/mgechev) |[ludohenin](https://github.com/ludohenin) |[NathanWalker](https://github.com/NathanWalker) |[tarlepp](https://github.com/tarlepp) |[aboeglin](https://github.com/aboeglin) |[jerryorta-dev](https://github.com/jerryorta-dev) | 114 | :---: |:---: |:---: |:---: |:---: |:---: | 115 | [mgechev](https://github.com/mgechev) |[ludohenin](https://github.com/ludohenin) |[NathanWalker](https://github.com/NathanWalker) |[tarlepp](https://github.com/tarlepp) |[aboeglin](https://github.com/aboeglin) |[jerryorta-dev](https://github.com/jerryorta-dev) | 116 | 117 | [TuiKiken](https://github.com/TuiKiken) |[ryzy](https://github.com/ryzy) |[ultrasonicsoft](https://github.com/ultrasonicsoft) |[mjwwit](https://github.com/mjwwit) |[natarajanmca11](https://github.com/natarajanmca11) |[philipooo](https://github.com/philipooo) | 118 | :---: |:---: |:---: |:---: |:---: |:---: | 119 | [TuiKiken](https://github.com/TuiKiken) |[ryzy](https://github.com/ryzy) |[ultrasonicsoft](https://github.com/ultrasonicsoft) |[mjwwit](https://github.com/mjwwit) |[natarajanmca11](https://github.com/natarajanmca11) |[philipooo](https://github.com/philipooo) | 120 | 121 | [redian](https://github.com/redian) |[robertpenner](https://github.com/robertpenner) |[jgolla](https://github.com/jgolla) |[dstockhammer](https://github.com/dstockhammer) | 122 | :---: |:---: |:---: |:---: | 123 | [redian](https://github.com/redian) |[robertpenner](https://github.com/robertpenner) |[jgolla](https://github.com/jgolla) |[dstockhammer](https://github.com/dstockhammer) | 124 | 125 | # Change Log 126 | 127 | You can follow the [Angular 2 change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md). 128 | 129 | # License 130 | 131 | MIT 132 | -------------------------------------------------------------------------------- /app/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import {provide} from 'angular2/core'; 2 | import {bootstrap} from 'angular2/platform/browser'; 3 | import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router'; 4 | import {HTTP_PROVIDERS} from 'angular2/http'; 5 | import {AppCmp} from './components/app/app'; 6 | 7 | bootstrap(AppCmp, [ 8 | ROUTER_PROVIDERS, 9 | provide(LocationStrategy, { useClass: HashLocationStrategy }), 10 | HTTP_PROVIDERS 11 | ]); 12 | -------------------------------------------------------------------------------- /app/components/about/about.html: -------------------------------------------------------------------------------- 1 |

2 | For reward, here is a list of awesome computer scientists! 3 |

4 | 5 |

6 | You want more? Add them yourself! 7 |

8 |
9 | 10 | 11 |
12 | 15 | -------------------------------------------------------------------------------- /app/components/about/about.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core'; 2 | import {NgFor} from 'angular2/common'; 3 | import {NameList} from '../../services/name_list'; 4 | 5 | @Component({ 6 | selector: 'about', 7 | styles: [ 8 | ` 9 | ul li a { 10 | color:blue; 11 | cursor:pointer; 12 | } 13 | ` 14 | ], 15 | templateUrl: './components/about/about.html', 16 | directives: [NgFor] 17 | }) 18 | export class AboutCmp { 19 | constructor(public list: NameList) {} 20 | addName(newname): boolean { 21 | this.list.add(newname.value); 22 | newname.value = ''; 23 | // prevent default form submit behavior to refresh the page 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/components/about/about_spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | describe, 3 | expect, 4 | injectAsync, 5 | it, 6 | setBaseTestProviders, 7 | TestComponentBuilder 8 | } from 'angular2/testing'; 9 | import {Component, View} from 'angular2/core'; 10 | import {DOM} from 'angular2/src/platform/dom/dom_adapter'; 11 | import {AboutCmp} from './about'; 12 | import {NameList} from '../../services/name_list'; 13 | import {} from 'angular2/testing'; 14 | import { 15 | TEST_BROWSER_PLATFORM_PROVIDERS, 16 | TEST_BROWSER_APPLICATION_PROVIDERS 17 | } from 'angular2/platform/testing/browser'; 18 | setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, 19 | TEST_BROWSER_APPLICATION_PROVIDERS); 20 | 21 | 22 | export function main() { 23 | describe('About component', () => { 24 | it('should work', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => { 25 | return tcb.overrideTemplate(TestComponent, '
') 26 | .createAsync(TestComponent) 27 | .then((rootTC) => { 28 | rootTC.detectChanges(); 29 | 30 | let aboutInstance = rootTC.debugElement.componentViewChildren[0].componentInstance; 31 | let aboutDOMEl = rootTC.debugElement.componentViewChildren[0].nativeElement; 32 | 33 | let nameListLen = function () { 34 | return aboutInstance.list.names.length; 35 | }; 36 | 37 | expect(aboutInstance.list).toEqual(jasmine.any(NameList)); 38 | expect(nameListLen()).toEqual(4); 39 | expect(DOM.querySelectorAll(aboutDOMEl, 'li').length).toEqual(nameListLen()); 40 | 41 | aboutInstance.addName({value: 'Minko'}); 42 | rootTC.detectChanges(); 43 | 44 | expect(nameListLen()).toEqual(5); 45 | expect(DOM.querySelectorAll(aboutDOMEl, 'li').length).toEqual(nameListLen()); 46 | expect(DOM.querySelectorAll(aboutDOMEl, 'li > span')[4].textContent).toEqual('Minko'); 47 | }); 48 | })); 49 | }); 50 | } 51 | 52 | @Component({providers: [NameList], selector: 'test-cmp'}) 53 | @View({directives: [AboutCmp]}) 54 | class TestComponent {} 55 | -------------------------------------------------------------------------------- /app/components/app/app.css: -------------------------------------------------------------------------------- 1 | .sample-app-content { 2 | font-family: Verdana; 3 | } 4 | .sample-app-content h1 { 5 | color: #999; 6 | font-size: 3em; 7 | } 8 | .sample-app-content h2 { 9 | color: #990000; 10 | font-size: 2em; 11 | } 12 | .sample-app-content p, 13 | .sample-app-content nav { 14 | padding: 30px; 15 | } 16 | .sample-app-content li, 17 | .sample-app-content p { 18 | font-size: 1.2em; 19 | } 20 | .sample-app-content li { 21 | font-family: Consolas; 22 | } 23 | .sample-app-content nav a { 24 | display: inline-block; 25 | margin-right: 15px; 26 | } 27 | .sample-app-content input, 28 | .sample-app-content button { 29 | padding: 5px; 30 | font-size: 1em; 31 | outline: none; 32 | } 33 | -------------------------------------------------------------------------------- /app/components/app/app.html: -------------------------------------------------------------------------------- 1 |
2 | 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /app/components/app/app.ts: -------------------------------------------------------------------------------- 1 | import {Component, ViewEncapsulation} from 'angular2/core'; 2 | import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router'; 3 | 4 | import {HomeCmp} from '../home/home'; 5 | import {NameList} from '../../services/name_list'; 6 | import {UsersCmp} from '../users/users'; 7 | import {UserService} from '../users/services/user_service'; 8 | 9 | import {componentProxyFactory} from '../../services/component_proxy'; 10 | 11 | @Component({ 12 | selector: 'app', 13 | viewProviders: [NameList, UserService], 14 | templateUrl: './components/app/app.html', 15 | styleUrls: ['./components/app/app.css'], 16 | encapsulation: ViewEncapsulation.None, 17 | directives: [ROUTER_DIRECTIVES] 18 | }) 19 | @RouteConfig([ 20 | { path: '/home', component: HomeCmp, as: 'Home', useAsDefault: true }, 21 | { 22 | path: '/about', 23 | component: componentProxyFactory({ 24 | path: './components/about/about', 25 | provide: m => m.AboutCmp 26 | }), 27 | as: 'About' 28 | }, 29 | { path: '/users/...', component: UsersCmp, as: 'Users' } 30 | ]) 31 | export class AppCmp {} 32 | -------------------------------------------------------------------------------- /app/components/home/home.css: -------------------------------------------------------------------------------- 1 | .note { 2 | color: #a8a8a8; 3 | } 4 | -------------------------------------------------------------------------------- /app/components/home/home.html: -------------------------------------------------------------------------------- 1 |

Howdy!

2 | 3 |

4 | Gratz! 5 |

6 | 7 |

8 | Your deployment of Angular 2 Seed worked perfectly! 9 | Click about (above) to get your reward! 10 |

11 | -------------------------------------------------------------------------------- /app/components/home/home.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core'; 2 | 3 | @Component({ 4 | selector: 'home', 5 | templateUrl: './components/home/home.html', 6 | styleUrls: ['./components/home/home.css'] 7 | }) 8 | export class HomeCmp {} 9 | -------------------------------------------------------------------------------- /app/components/home/home_spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | describe, 3 | expect, 4 | injectAsync, 5 | it, 6 | setBaseTestProviders, 7 | TestComponentBuilder 8 | } from 'angular2/testing'; 9 | import {Component, View} from 'angular2/core'; 10 | import {DOM} from 'angular2/src/platform/dom/dom_adapter'; 11 | import {HomeCmp} from './home'; 12 | import { 13 | TEST_BROWSER_PLATFORM_PROVIDERS, 14 | TEST_BROWSER_APPLICATION_PROVIDERS 15 | } from 'angular2/platform/testing/browser'; 16 | setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, 17 | TEST_BROWSER_APPLICATION_PROVIDERS); 18 | 19 | 20 | export function main() { 21 | describe('Home component', () => { 22 | it('should work', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => { 23 | return tcb.overrideTemplate(TestComponent, '
') 24 | .createAsync(TestComponent) 25 | .then((rootTC) => { 26 | let homeDOMEl = rootTC.debugElement.componentViewChildren[0].nativeElement; 27 | 28 | expect(DOM.querySelectorAll(homeDOMEl, 'h1')[0].textContent).toEqual('Howdy!'); 29 | }); 30 | })); 31 | }); 32 | } 33 | 34 | @Component({selector: 'test-cmp'}) 35 | @View({directives: [HomeCmp]}) 36 | class TestComponent {} 37 | -------------------------------------------------------------------------------- /app/components/users/services/interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface IUser { 2 | HETU: string; 3 | cell: string; 4 | dob: string; 5 | email: string; 6 | gender: string; 7 | location: { 8 | city: string; 9 | region: string; 10 | street: string; 11 | zip: string; 12 | }; 13 | md5: string; 14 | name: { 15 | title: string; 16 | first: string; 17 | last: string; 18 | }; 19 | nationality: string; 20 | password: string; 21 | phone: string; 22 | picture: { 23 | large: string; 24 | medium: string; 25 | thumbnail: string; 26 | }; 27 | registered: string; 28 | salt: string; 29 | sha1: string; 30 | sha256: string; 31 | username: string; 32 | version: string; 33 | } 34 | -------------------------------------------------------------------------------- /app/components/users/services/user_service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, EventEmitter} from 'angular2/core'; 2 | import {Http} from 'angular2/http'; 3 | import 'rxjs/add/operator/map'; 4 | import {IUser} from './interfaces'; 5 | 6 | const SEED_URL = 'http://api.randomuser.me/?results=10&seed=885ad8c4404e07ea03'; 7 | const URL = 'http://api.randomuser.me/?results=10'; 8 | 9 | export {IUser} from './interfaces'; 10 | @Injectable() 11 | export class UserService { 12 | // Fetch only once and cache the initial collection. 13 | usersCache = >[]; 14 | loading = false; 15 | currentUser: IUser; 16 | currentFetches = new Map>>(); 17 | loadingStatus: EventEmitter = new EventEmitter(); 18 | constructor(private http: Http) {} 19 | getUsers(): Promise> { 20 | if (this.usersCache.length) { 21 | return new Promise((resolve) => resolve(this.usersCache)); 22 | } else { 23 | return this.fetch(SEED_URL); 24 | } 25 | } 26 | getMoreUsers(): Promise> { 27 | return this.fetch(URL); 28 | } 29 | getUser(username): Promise { 30 | return this.findUserByUsername(username) 31 | .then(user => { 32 | this.currentUser = user; 33 | return this.currentUser; 34 | }); 35 | } 36 | toggleState(force: boolean) { 37 | if (typeof force === 'undefined') { 38 | this.loading = !this.loading; 39 | } else { 40 | this.loading = force; 41 | } 42 | this.loadingStatus.emit(this.loading); 43 | } 44 | saveUser(user: IUser) { 45 | this.usersCache.push(user); 46 | this.sort(); 47 | } 48 | sort() { 49 | this.usersCache.sort((a,b) => a.name.last > b.name.last? 1 : -1); 50 | } 51 | private fetch(url: string): Promise> { 52 | if (!this.currentFetches.has(url)) { 53 | let promise = new Promise((resolve, reject) => { 54 | this.toggleState(true); 55 | this.http.get(url) 56 | // .toRx() 57 | // Cleanup what is received from the API. 58 | .map(res => res.json().results) 59 | .map(res => res.map(o => o.user)) 60 | .subscribe(res => { 61 | res.forEach(user => this.usersCache.push(user)); 62 | this.sort(); 63 | this.toggleState(false); 64 | this.currentFetches.delete(url); 65 | resolve(this.usersCache); 66 | }); 67 | }); 68 | this.currentFetches.set(url, promise); 69 | } 70 | return this.currentFetches.get(url); 71 | } 72 | private findUserByUsername(username): Promise { 73 | return new Promise(resolve => { 74 | this.getUsers().then(users => { 75 | let user = users.filter(user => user.username === username)[0]; 76 | resolve(user); 77 | }); 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/components/users/user_details/user_details.html: -------------------------------------------------------------------------------- 1 |
2 |
No user found
3 | 4 |
5 |

User Details

6 |

7 | Firstname: {{ user.name.first }} 8 |

9 |

10 | Lastname: {{ user.name.last }} 11 |

12 |

13 | 14 |

15 |

16 | Edit 17 |

18 |
19 |
20 | -------------------------------------------------------------------------------- /app/components/users/user_details/user_details.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, OnInit} from 'angular2/core'; 2 | import {RouteParams, RouterLink} from 'angular2/router'; 3 | import {UserService, IUser} from '../services/user_service'; 4 | 5 | @Component({ 6 | selector: 'user-details', 7 | templateUrl: './components/users/user_details/user_details.html', 8 | directives: [RouterLink] 9 | }) 10 | export class UserDetailsCmp implements OnInit { 11 | user: IUser; 12 | username: string; 13 | constructor(@Inject(RouteParams) routeParams, 14 | private userService: UserService) { 15 | this.username = routeParams.params.username; 16 | } 17 | ngOnInit() { 18 | this.userService 19 | .getUser(this.username) 20 | .then(user => this.user = user); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/components/users/user_form/user_form.html: -------------------------------------------------------------------------------- 1 |

User Form

2 | 3 | 4 |
5 |
6 |
7 |

8 | 9 | 13 |

14 |

15 | 16 | 20 |

21 |
22 |

23 | 25 |

26 |
27 |
28 | -------------------------------------------------------------------------------- /app/components/users/user_form/user_form.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject} from 'angular2/core'; 2 | import {RouteParams} from 'angular2/router'; 3 | import {UserService, IUser} from '../services/user_service'; 4 | 5 | @Component({ 6 | selector: 'user-form', 7 | templateUrl: './components/users/user_form/user_form.html' 8 | }) 9 | export class UserFormCmp { 10 | user: IUser; 11 | username: string = this.routeParams.params ? this.routeParams.params.username : undefined; 12 | constructor(@Inject(RouteParams) private routeParams, 13 | private userService: UserService) { 14 | if (this.username) { 15 | userService.getUser(this.username) 16 | .then(user => this.user = user); 17 | } else { 18 | // TODO: add User model 19 | this.user = { name: { first: '', last: '' } }; 20 | } 21 | } 22 | onSave(model) { 23 | if (this.username) { 24 | this.user.name.first = model.name.first; 25 | this.user.name.last = model.name.last; 26 | return; 27 | } 28 | // Fix as user-details expect a picture property. 29 | // ng2 does not fail silently when a property isn't 30 | // defined on a binding. 31 | model.picture = {}; 32 | this.userService.saveUser(model); 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/components/users/users.css: -------------------------------------------------------------------------------- 1 | users, 2 | users-list, 3 | users-home, 4 | user-details { display: block; } 5 | 6 | ul.users-list { 7 | margin: 0; 8 | padding: 0; 9 | display: block; 10 | width: 280px; 11 | float: left; 12 | } 13 | .users-list > li { 14 | list-style: none; 15 | position: relative; 16 | font-size: 14px; 17 | } 18 | .users-list > li.active { 19 | background-color: #cecece; 20 | } 21 | .users-list > li > a { 22 | display: block; 23 | text-decoration: none; 24 | padding: 3px 0; 25 | color: dimgray; 26 | } 27 | .users-list > li > a.router-link-active { 28 | background-color:#28b0ed; 29 | color:#fff; 30 | } 31 | .users-list > li:hover { 32 | background-color: slategray; 33 | color: floralwhite; 34 | } 35 | .users-list > li:hover > a { 36 | color: floralwhite; 37 | } 38 | 39 | .users-list > li > a > img { 40 | width: 50px; 41 | height: 50px; 42 | border-radius: 25px; 43 | margin: 0 5px 0 5px; 44 | vertical-align: middle; 45 | } 46 | .users-list > li > .actions { 47 | display: none; 48 | position: absolute; 49 | right: 20px; 50 | top: 15px; 51 | } 52 | .users-list > li > .actions > a { 53 | color: floralwhite; 54 | } 55 | .users-list > li:hover > .actions { 56 | display: block; 57 | } 58 | 59 | .user-details { 60 | margin-left: 280px; 61 | padding: 0 15px; 62 | } 63 | -------------------------------------------------------------------------------- /app/components/users/users.html: -------------------------------------------------------------------------------- 1 |

Users

2 | 3 |
Loading users data
4 | 5 |
6 | 12 | 13 | Create user 14 | 15 | 16 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /app/components/users/users.ts: -------------------------------------------------------------------------------- 1 | import {Component, ViewEncapsulation} from 'angular2/core'; 2 | import {RouteConfig, ROUTER_DIRECTIVES, CanActivate, OnActivate, ComponentInstruction} from 'angular2/router'; 3 | 4 | import {UsersListCmp} from './users_list/users_list'; 5 | import {UsersHomeCmp} from './users_home/users_home'; 6 | import {UserDetailsCmp} from './user_details/user_details'; 7 | import {UserFormCmp} from './user_form/user_form'; 8 | import {UserService} from './services/user_service'; 9 | 10 | import {LoadingBtn} from '../../directives/loading_btn'; 11 | 12 | @Component({ 13 | selector: 'users', 14 | templateUrl: './components/users/users.html', 15 | styleUrls: ['./components/users/users.css'], 16 | encapsulation: ViewEncapsulation.None, 17 | directives: [ROUTER_DIRECTIVES, UsersListCmp, LoadingBtn] 18 | }) 19 | @RouteConfig([ 20 | { path: '/home', component: UsersHomeCmp, as: 'Users-home', useAsDefault: true }, 21 | { path: '/show/:username', component: UserDetailsCmp, as: 'User-details' }, 22 | { path: '/edit/:username', component: UserFormCmp, as: 'User-edit' }, 23 | { path: '/create', component: UserFormCmp, as: 'User-create' } 24 | ]) 25 | @CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => { 26 | console.info('Component router CanActivate hook! - can return boolean or Promise'); 27 | return true; 28 | }) 29 | export class UsersCmp implements OnActivate { 30 | public loading:boolean = true; 31 | constructor(public userService: UserService) { 32 | this.userService 33 | .getUsers() 34 | .then(users => { 35 | // To be removed when component activation will work. 36 | this.loading = false; 37 | }); 38 | } 39 | eventHandler(value: any) { 40 | console.log(`Example of handling custom events: ${value}`); 41 | } 42 | routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) { 43 | console.info('Component routerOnActivate works!'); 44 | this.loading = false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/components/users/users_home/users_home.html: -------------------------------------------------------------------------------- 1 |

Users Home

2 | -------------------------------------------------------------------------------- /app/components/users/users_home/users_home.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core'; 2 | 3 | @Component({ 4 | selector: 'users-home', 5 | templateUrl: './components/users/users_home/users_home.html' 6 | }) 7 | export class UsersHomeCmp {} 8 | -------------------------------------------------------------------------------- /app/components/users/users_list/users_list.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /app/components/users/users_list/users_list.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core'; 2 | import {RouterLink} from 'angular2/router'; 3 | 4 | import {SetActive} from '../../../directives/set_active'; 5 | 6 | @Component({ 7 | selector: 'users-list', 8 | inputs: ['users'], 9 | templateUrl: './components/users/users_list/users_list.html', 10 | directives: [RouterLink, SetActive] 11 | }) 12 | export class UsersListCmp {} 13 | -------------------------------------------------------------------------------- /app/directives/loading_btn.ts: -------------------------------------------------------------------------------- 1 | import {Directive, ElementRef, EventEmitter, Output, Input} from 'angular2/core'; 2 | /** 3 | * Simple directive to display an action message (via [loading-text] property) in a button when clicked. 4 | * The button is then disabled until the action is completed. 5 | * It handles state via the [loading-more] property. 6 | * Shows how an example of how to emit custom events (sample-custom-event) with a value. 7 | * 8 | * @Example: 9 | * 17 | */ 18 | @Directive({ 19 | selector: 'button[loading-btn]', 20 | host: { 21 | '[disabled]': '_loading' 22 | } 23 | }) 24 | export class LoadingBtn { 25 | @Input() public loadingText: string = 'Loading...'; 26 | private _loading: boolean = false; 27 | private _originalText: string; 28 | @Output() private sampleCustomEvent = new EventEmitter(); 29 | constructor(private _elRef: ElementRef) { 30 | this._originalText = this._elRef.nativeElement.innerText; 31 | } 32 | toggleText(): void { 33 | if (this._loading) { 34 | this._elRef.nativeElement.innerText = this.loadingText; 35 | } else { 36 | this._elRef.nativeElement.innerText = this._originalText; 37 | } 38 | } 39 | @Input('loadingMore') set loading(v: boolean) { 40 | this.sampleCustomEvent.emit(`Button is ${v ? '' : 'not '}loading.`); 41 | this._loading = v; 42 | this.toggleText(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/directives/set_active.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directive, 3 | ElementRef, 4 | Inject, 5 | Renderer, 6 | QueryList, 7 | Query 8 | } from 'angular2/core'; 9 | import {Location} from 'angular2/router'; 10 | import 'rxjs/add/operator/map'; 11 | 12 | /** 13 | * Simple directive to add class active on a LI element when 14 | * its A child element is clicked or on page load. Active class 15 | * is removed from all other LI element. 16 | * Follow the same principle as nav's in Bootstrap. 17 | * 18 | * @Example: 19 | *
    20 | *
  • 21 | * link 1 22 | *
  • 23 | *
  • 24 | * link 2 25 | *
  • 26 | *
27 | */ 28 | @Directive({ selector: 'a' }) 29 | class Link { 30 | constructor (private el: ElementRef) {} 31 | get href(): string { 32 | // Rely on the DOM until there is a better option. 33 | // The problem is that the href attribute is generated by router-link 34 | // directive which is instantiated after this one. href is then not 35 | // available at that time. 36 | return this.el.nativeElement.getAttribute('href'); 37 | } 38 | } 39 | 40 | @Directive({ selector: 'li' }) 41 | class ListItem { 42 | className = 'active'; 43 | constructor(@Query(Link) public links: QueryList, 44 | @Inject(Location) public location: Location, 45 | private el: ElementRef, 46 | private renderer: Renderer) {} 47 | toggleClass() { 48 | if (this.linkHref === `#${this.location.path()}`) { 49 | this.renderer.setElementClass(this.el, this.className, true); 50 | } else { 51 | this.renderer.setElementClass(this.el, this.className, false); 52 | } 53 | } 54 | get linkHref(): string { 55 | return this.links.first.href; 56 | } 57 | } 58 | 59 | @Directive({ selector: '[set-active]', host: { '(click)': 'setActive()' } }) 60 | class List { 61 | _href; 62 | constructor(@Query(ListItem) private items: QueryList) { 63 | // _items is populated later on as it's refers to child classes. 64 | // So we wait for changes. 65 | // TODO: Figure out the changes needed here to make this work again 66 | this.items.changes.subscribe(_ => { 67 | this.setActive(); 68 | }); 69 | } 70 | setActive(): void { 71 | this.items.map(item => { 72 | item.toggleClass(); 73 | }); 74 | } 75 | } 76 | 77 | export var SetActive = [List, ListItem, Link]; 78 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= APP_TITLE %> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Loading... 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/services/component_proxy.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { 4 | Component, 5 | DynamicComponentLoader, 6 | ElementRef, 7 | Injector, 8 | provide, 9 | Type, 10 | View 11 | } from 'angular2/core'; 12 | /** 13 | * A factory for a Virtual Proxy Component 14 | * to provide a lazily loaded `Component` which will be loaded and rendered by the `DynamicComponentLoader` on entering a route when 15 | * the constructor of the Virtual Component is executed. 16 | * 17 | * @Example: 18 | * { 19 | * path: '/path-in-the-browser', 20 | * component: componentProxyFactory({ 21 | * path: './path/to/the/file', 22 | * provide: m => m.ClassNameOfComponent 23 | * }), 24 | * as: 'ComponentName' 25 | * } 26 | * 27 | */ 28 | 29 | class ComponentProvider { 30 | path: string; 31 | provide: {(module: any): any}; 32 | } 33 | 34 | export function componentProxyFactory(provider: ComponentProvider): Type { 35 | @Component({ 36 | selector: 'component-proxy', 37 | providers: [provide(ComponentProvider, {useValue: provider})] 38 | }) 39 | @View({ 40 | template: `` 41 | }) 42 | class VirtualComponent { 43 | constructor( 44 | el: ElementRef, 45 | loader: DynamicComponentLoader, 46 | inj: Injector, 47 | provider: ComponentProvider 48 | ) { 49 | System.import(provider.path) 50 | .then(m => { 51 | loader.loadIntoLocation(provider.provide(m), el, 'content'); 52 | }); 53 | } 54 | } 55 | return VirtualComponent; 56 | } 57 | -------------------------------------------------------------------------------- /app/services/name_list.ts: -------------------------------------------------------------------------------- 1 | export class NameList { 2 | names = ['Dijkstra', 'Knuth', 'Turing', 'Hopper']; 3 | 4 | get(): string[] { 5 | return this.names; 6 | } 7 | add(value: string):void { 8 | this.names.push(value); 9 | } 10 | remove(index: number):void { 11 | this.names.splice(index, 1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/services/name_list_spec.ts: -------------------------------------------------------------------------------- 1 | import {NameList} from './name_list'; 2 | 3 | export function main() { 4 | describe('NameList Service', () => { 5 | var nameList; 6 | 7 | beforeEach(() => { 8 | nameList = new NameList; 9 | }); 10 | 11 | it('should return the list of names', () => { 12 | var names = nameList.get(); 13 | expect(names).toEqual(jasmine.any(Array)); 14 | }); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /gulpfile.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import {runSequence, task} from './tools/utils'; 3 | 4 | // -------------- 5 | // Clean (override). 6 | gulp.task('clean', task('clean', 'all')); 7 | gulp.task('clean.dist', task('clean', 'dist')); 8 | gulp.task('clean.test', task('clean', 'test')); 9 | gulp.task('clean.tmp', task('clean', 'tmp')); 10 | 11 | gulp.task('check.versions', task('check.versions')); 12 | 13 | // -------------- 14 | // Postinstall. 15 | gulp.task('postinstall', done => 16 | runSequence('clean', 17 | 'npm', 18 | done)); 19 | 20 | // -------------- 21 | // Build dev. 22 | gulp.task('build.dev', done => 23 | runSequence('clean.dist', 24 | 'tslint', 25 | 'build.sass.dev', 26 | 'build.img.dev', 27 | 'build.js.dev', 28 | 'build.index', 29 | done)); 30 | 31 | // -------------- 32 | // Build prod. 33 | gulp.task('build.prod', done => 34 | runSequence('clean.dist', 35 | 'clean.tmp', 36 | 'tslint', 37 | 'build.sass.dev', 38 | 'build.img.dev', 39 | 'build.html_css.prod', 40 | 'build.deps', 41 | 'build.js.prod', 42 | 'build.bundles', 43 | 'build.index', 44 | done)); 45 | 46 | // -------------- 47 | // Watch. 48 | gulp.task('build.dev.watch', done => 49 | runSequence('build.dev', 50 | 'watch.dev', 51 | done)); 52 | 53 | gulp.task('build.test.watch', done => 54 | runSequence('build.test', 55 | 'watch.test', 56 | done)); 57 | 58 | // -------------- 59 | // Test. 60 | gulp.task('test', done => 61 | runSequence('clean.test', 62 | 'tslint', 63 | 'build.test', 64 | 'karma.start', 65 | done)); 66 | 67 | // -------------- 68 | // Serve. 69 | gulp.task('serve', done => 70 | runSequence('build.dev', 71 | 'server.start', 72 | 'watch.serve', 73 | done)); 74 | 75 | // -------------- 76 | // Docs 77 | // Disabled until https://github.com/sebastian-lenz/typedoc/issues/162 gets resolved 78 | // gulp.task('docs', done => 79 | // runSequence('build.docs', 80 | // 'serve.docs', 81 | // done)); 82 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Jul 15 2015 09:44:02 GMT+0200 (Romance Daylight Time) 3 | 'use strict'; 4 | 5 | module.exports = function(config) { 6 | config.set({ 7 | 8 | // base path that will be used to resolve all patterns (eg. files, exclude) 9 | basePath: './', 10 | 11 | 12 | // frameworks to use 13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 14 | frameworks: ['jasmine'], 15 | 16 | 17 | // list of files / patterns to load in the browser 18 | files: [ 19 | 'node_modules/zone.js/dist/zone-microtask.js', 20 | 'node_modules/zone.js/dist/long-stack-trace-zone.js', 21 | 'node_modules/zone.js/dist/jasmine-patch.js', 22 | 'node_modules/es6-module-loader/dist/es6-module-loader.js', 23 | 'node_modules/traceur/bin/traceur-runtime.js', // Required by PhantomJS2, otherwise it shouts ReferenceError: Can't find variable: require 24 | 'node_modules/traceur/bin/traceur.js', 25 | 'node_modules/systemjs/dist/system.src.js', 26 | 'node_modules/reflect-metadata/Reflect.js', 27 | 28 | { pattern: 'node_modules/angular2/**/*.js', included: false, watched: false }, 29 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false }, 30 | { pattern: 'test/**/*.js', included: false, watched: true }, 31 | { pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: false, watched: false }, // PhantomJS2 (and possibly others) might require it 32 | 33 | 'test-main.js' 34 | ], 35 | 36 | 37 | // list of files to exclude 38 | exclude: [ 39 | 'node_modules/angular2/**/*_spec.js' 40 | ], 41 | 42 | 43 | // preprocess matching files before serving them to the browser 44 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 45 | preprocessors: { 46 | }, 47 | 48 | 49 | // test results reporter to use 50 | // possible values: 'dots', 'progress' 51 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 52 | reporters: ['mocha'], 53 | 54 | 55 | // web server port 56 | port: 9876, 57 | 58 | 59 | // enable / disable colors in the output (reporters and logs) 60 | colors: true, 61 | 62 | 63 | // level of logging 64 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 65 | logLevel: config.LOG_INFO, 66 | 67 | 68 | // enable / disable watching file and executing tests whenever any file changes 69 | autoWatch: true, 70 | 71 | 72 | // start these browsers 73 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 74 | browsers: [ 75 | 'PhantomJS2', 76 | 'Chrome' 77 | ], 78 | 79 | 80 | customLaunchers: { 81 | Chrome_travis_ci: { 82 | base: 'Chrome', 83 | flags: ['--no-sandbox'] 84 | } 85 | }, 86 | 87 | 88 | // Continuous Integration mode 89 | // if true, Karma captures browsers, runs the tests and exits 90 | singleRun: false 91 | }); 92 | 93 | if (process.env.APPVEYOR) { 94 | config.browsers = ['IE']; 95 | config.singleRun = true; 96 | config.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough 97 | } 98 | 99 | if (process.env.TRAVIS || process.env.CIRCLECI) { 100 | config.browsers = ['Chrome_travis_ci']; 101 | config.singleRun = true; 102 | } 103 | }; 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-sample-app", 3 | "version": "0.0.0", 4 | "description": "Extended seed for Angular 2 apps", 5 | "repository": { 6 | "url": "https://github.com/AngularShowcase/angular2-sample-app" 7 | }, 8 | "scripts": { 9 | "build.dev": "gulp build.dev", 10 | "build.dev.watch": "gulp build.dev.watch", 11 | "build.prod": "gulp build.prod --env prod", 12 | "build.test": "gulp build.test", 13 | "build.test.watch": "gulp build.test.watch", 14 | "docs": "npm run gulp -- build.docs && npm run gulp -- serve.docs", 15 | "gulp": "gulp", 16 | "karma": "karma", 17 | "karma.start": "karma start", 18 | "lint": "gulp tslint", 19 | "postinstall": "tsd reinstall --clean && tsd link && tsd rebundle && gulp check.versions && gulp postinstall", 20 | "reinstall": "rimraf node_modules && npm cache clean && npm install", 21 | "start": "gulp serve --env dev", 22 | "serve.dev": "gulp serve --env dev", 23 | "tasks.list": "gulp --tasks-simple", 24 | "test": "gulp test", 25 | "tsd": "tsd" 26 | }, 27 | "author": "Minko Gechev ", 28 | "license": "MIT", 29 | "devDependencies": { 30 | "async": "^1.4.2", 31 | "chalk": "^1.1.1", 32 | "connect-livereload": "^0.5.3", 33 | "del": "^1.1.1", 34 | "express": "~4.13.1", 35 | "extend": "^3.0.0", 36 | "gulp": "^3.9.0", 37 | "gulp-concat": "^2.5.2", 38 | "gulp-filter": "^2.0.2", 39 | "gulp-inject": "^1.3.1", 40 | "gulp-inline-ng2-template": "^0.0.7", 41 | "gulp-load-plugins": "^0.10.0", 42 | "gulp-minify-css": "^1.1.6", 43 | "gulp-minify-html": "^1.0.3", 44 | "gulp-plumber": "~1.0.1", 45 | "gulp-sass": "^2.0.4", 46 | "gulp-shell": "~0.4.3", 47 | "gulp-sourcemaps": "~1.5.2", 48 | "gulp-template": "^3.0.0", 49 | "gulp-tslint": "^3.3.0", 50 | "gulp-tslint-stylish": "^1.0.4", 51 | "gulp-typescript": "~2.8.2", 52 | "gulp-uglify": "^1.2.0", 53 | "gulp-util": "^3.0.7", 54 | "gulp-watch": "^4.2.4", 55 | "jasmine-core": "~2.3.4", 56 | "karma": "~0.13.15", 57 | "karma-chrome-launcher": "~0.2.0", 58 | "karma-ie-launcher": "^0.2.0", 59 | "karma-jasmine": "~0.3.6", 60 | "karma-mocha-reporter": "^1.1.1", 61 | "karma-phantomjs2-launcher": "^0.3.2", 62 | "merge-stream": "^1.0.0", 63 | "open": "0.0.5", 64 | "rimraf": "^2.4.3", 65 | "run-sequence": "^1.1.0", 66 | "semver": "^5.0.3", 67 | "serve-static": "^1.9.2", 68 | "slash": "~1.0.0", 69 | "stream-series": "^0.1.1", 70 | "systemjs-builder": "^0.14.8", 71 | "tiny-lr": "^0.2.1", 72 | "traceur": "^0.0.91", 73 | "ts-node": "^0.5.4", 74 | "tsd": "^0.6.4", 75 | "typedoc": "^0.3.12", 76 | "typescript": "~1.7.3", 77 | "typescript-register": "^1.1.0", 78 | "yargs": "^3.25.0" 79 | }, 80 | "dependencies": { 81 | "angular2": "2.0.0-beta.2", 82 | "bootstrap": "^3.3.6", 83 | "es6-module-loader": "^0.17.8", 84 | "es6-shim": "^0.33.3", 85 | "reflect-metadata": "^0.1.2", 86 | "rxjs": "5.0.0-beta.0", 87 | "systemjs": "^0.19.4", 88 | "zone.js": "0.5.10" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test-main.js: -------------------------------------------------------------------------------- 1 | // Turn on full stack traces in errors to help debugging 2 | Error.stackTraceLimit=Infinity; 3 | 4 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 100; 5 | 6 | // Cancel Karma's synchronous start, 7 | // we will call `__karma__.start()` later, once all the specs are loaded. 8 | __karma__.loaded = function() {}; 9 | 10 | System.config({ 11 | baseURL: '/base/', 12 | defaultJSExtensions: true, 13 | paths: { 14 | 'angular2/*': 'node_modules/angular2/*.js', 15 | 'rxjs/*': 'node_modules/rxjs/*.js' 16 | } 17 | }); 18 | 19 | System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) { 20 | browser_adapter.BrowserDomAdapter.makeCurrent(); 21 | }).then(function() { 22 | return Promise.all( 23 | Object.keys(window.__karma__.files) // All files served by Karma. 24 | .filter(onlySpecFiles) 25 | .map(file2moduleName) 26 | .map(function(path) { 27 | return System.import(path).then(function(module) { 28 | if (module.hasOwnProperty('main')) { 29 | module.main(); 30 | } else { 31 | throw new Error('Module ' + path + ' does not implement main() method.'); 32 | } 33 | }); 34 | })); 35 | }) 36 | .then(function() { 37 | __karma__.start(); 38 | }, function(error) { 39 | console.error(error.stack || error); 40 | __karma__.start(); 41 | }); 42 | 43 | 44 | function onlySpecFiles(path) { 45 | return /[\.|_]spec\.js$/.test(path); 46 | } 47 | 48 | // Normalize paths to module names. 49 | function file2moduleName(filePath) { 50 | return filePath.replace(/\\/g, '/') 51 | .replace(/^\/base\//, '') 52 | .replace(/\.js/, ''); 53 | } 54 | -------------------------------------------------------------------------------- /tools/config.ts: -------------------------------------------------------------------------------- 1 | import {readFileSync} from 'fs'; 2 | import {argv} from 'yargs'; 3 | 4 | 5 | // -------------- 6 | // Configuration. 7 | export const ENV = argv['env'] || 'dev'; 8 | export const DEBUG = argv['debug'] || false; 9 | export const PORT = argv['port'] || 5555; 10 | export const LIVE_RELOAD_PORT = argv['reload-port'] || 4002; 11 | export const DOCS_PORT = argv['docs-port'] || 4003; 12 | export const APP_BASE = argv['base'] || '/'; 13 | 14 | export const APP_TITLE = 'My Angular2 App'; 15 | 16 | export const APP_SRC = 'app'; 17 | export const ASSETS_SRC = `${APP_SRC}/assets`; 18 | 19 | export const TOOLS_DIR = 'tools'; 20 | export const TMP_DIR = 'tmp'; 21 | export const TEST_DEST = 'test'; 22 | export const DOCS_DEST = 'docs'; 23 | export const APP_DEST = `dist/${ENV}`; 24 | export const ASSETS_DEST = `${APP_DEST}/assets`; 25 | export const BUNDLES_DEST = `${APP_DEST}/bundles`; 26 | export const CSS_DEST = `${APP_DEST}/css`; 27 | export const FONTS_DEST = `${APP_DEST}/fonts`; 28 | export const LIB_DEST = `${APP_DEST}/lib`; 29 | export const APP_ROOT = ENV === 'dev' ? `${APP_BASE}${APP_DEST}/` : `${APP_BASE}`; 30 | export const VERSION = appVersion(); 31 | 32 | export const VERSION_NPM = '2.14.7'; 33 | export const VERSION_NODE = '4.0.0'; 34 | 35 | // Declare NPM dependencies (Note that globs should not be injected). 36 | export const NPM_DEPENDENCIES = [ 37 | { src: 'systemjs/dist/system-polyfills.js', dest: LIB_DEST }, 38 | 39 | { src: 'es6-shim/es6-shim.min.js', inject: 'shims', dest: LIB_DEST }, 40 | { src: 'reflect-metadata/Reflect.js', inject: 'shims', dest: LIB_DEST }, 41 | { src: 'systemjs/dist/system.src.js', inject: 'shims', dest: LIB_DEST }, 42 | { src: 'angular2/bundles/angular2-polyfills.js', inject: 'shims', dest: LIB_DEST }, 43 | 44 | // Faster dev page load 45 | { src: 'rxjs/bundles/Rx.min.js', inject: 'libs', dest: LIB_DEST }, 46 | { src: 'angular2/bundles/angular2.min.js', inject: 'libs', dest: LIB_DEST }, 47 | { src: 'angular2/bundles/router.js', inject: 'libs', dest: LIB_DEST }, // use router.min.js with alpha47 48 | { src: 'angular2/bundles/http.min.js', inject: 'libs', dest: LIB_DEST }, 49 | 50 | { src: 'bootstrap/dist/css/bootstrap.min.css', inject: true, dest: CSS_DEST } 51 | ]; 52 | 53 | // Declare local files that needs to be injected 54 | export const APP_ASSETS = [ 55 | { src: `${ASSETS_SRC}/main.css`, inject: true, dest: CSS_DEST } 56 | ]; 57 | 58 | NPM_DEPENDENCIES 59 | .filter(d => !/\*/.test(d.src)) // Skip globs 60 | .forEach(d => d.src = require.resolve(d.src)); 61 | 62 | export const DEPENDENCIES = NPM_DEPENDENCIES.concat(APP_ASSETS); 63 | 64 | 65 | // ---------------- 66 | // SystemsJS Configuration. 67 | const SYSTEM_CONFIG_DEV = { 68 | defaultJSExtensions: true, 69 | paths: { 70 | 'bootstrap': `${APP_ROOT}bootstrap`, 71 | '*': `${APP_BASE}node_modules/*` 72 | } 73 | }; 74 | 75 | const SYSTEM_CONFIG_PROD = { 76 | defaultJSExtensions: true, 77 | bundles: { 78 | 'bundles/app': ['bootstrap'] 79 | } 80 | }; 81 | 82 | export const SYSTEM_CONFIG = ENV === 'dev' ? SYSTEM_CONFIG_DEV : SYSTEM_CONFIG_PROD; 83 | 84 | // This is important to keep clean module names as 'module name == module uri'. 85 | export const SYSTEM_CONFIG_BUILDER = { 86 | defaultJSExtensions: true, 87 | paths: { 88 | '*': `${TMP_DIR}/*`, 89 | 'angular2/*': 'node_modules/angular2/*', 90 | 'rxjs/*': 'node_modules/rxjs/*' 91 | } 92 | }; 93 | 94 | 95 | // -------------- 96 | // Private. 97 | function appVersion(): number|string { 98 | var pkg = JSON.parse(readFileSync('package.json').toString()); 99 | return pkg.version; 100 | } 101 | -------------------------------------------------------------------------------- /tools/tasks/build.bundles.ts: -------------------------------------------------------------------------------- 1 | import {parallel} from 'async'; 2 | import {join} from 'path'; 3 | import * as Builder from 'systemjs-builder'; 4 | import {BUNDLES_DEST, SYSTEM_CONFIG_BUILDER} from '../config'; 5 | 6 | const BUNDLE_OPTS = { 7 | minify: true, 8 | sourceMaps: true, 9 | format: 'cjs' 10 | }; 11 | 12 | export = function bundles(gulp, plugins) { 13 | return function (done) { 14 | let builder = new Builder(SYSTEM_CONFIG_BUILDER); 15 | 16 | parallel([ 17 | bundleApp 18 | ], () => done()); 19 | 20 | function bundleApp(done) { 21 | builder.bundle( 22 | 'bootstrap - angular2/*', 23 | join(BUNDLES_DEST, 'app.js'), BUNDLE_OPTS).then(done); 24 | } 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /tools/tasks/build.deps.ts: -------------------------------------------------------------------------------- 1 | import * as merge from 'merge-stream'; 2 | import {DEPENDENCIES} from '../config'; 3 | 4 | export = function buildDepsProd(gulp, plugins) { 5 | return function () { 6 | let stream = merge(); 7 | 8 | DEPENDENCIES.forEach(dep => { 9 | stream.add(addStream(dep)); 10 | }); 11 | 12 | return stream; 13 | 14 | function addStream(dep) { 15 | let stream = gulp.src(dep.src); 16 | stream.pipe(gulp.dest(dep.dest)); 17 | return stream; 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /tools/tasks/build.docs.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, APP_TITLE, DOCS_DEST} from '../config'; 3 | 4 | export = function buildDocs(gulp, plugins, option) { 5 | return function() { 6 | 7 | let src = [ 8 | join(APP_SRC, '**/*.ts'), 9 | '!' + join(APP_SRC, '**/*_spec.ts') 10 | ]; 11 | 12 | return gulp.src(src) 13 | .pipe(plugins.typedoc({ 14 | // TypeScript options (see typescript docs) 15 | module: 'commonjs', 16 | target: 'es5', 17 | includeDeclarations: true, 18 | // Output options (see typedoc docs) 19 | out: DOCS_DEST, 20 | json: join(DOCS_DEST , 'data/docs.json' ), 21 | name: APP_TITLE, 22 | ignoreCompilerErrors: false, 23 | experimentalDecorators: true, 24 | version: true 25 | })); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tools/tasks/build.html_css.prod.ts: -------------------------------------------------------------------------------- 1 | import * as merge from 'merge-stream'; 2 | import {join} from 'path'; 3 | import {APP_SRC, TMP_DIR} from '../config'; 4 | 5 | // const HTML_MINIFIER_OPTS = { empty: true }; 6 | 7 | export = function buildJSDev(gulp, plugins) { 8 | return function () { 9 | 10 | return merge(minifyHtml(), minifyCss()); 11 | 12 | function minifyHtml() { 13 | return gulp.src(join(APP_SRC, '**/*.html')) 14 | // .pipe(plugins.minifyHtml(HTML_MINIFIER_OPTS)) 15 | .pipe(gulp.dest(TMP_DIR)); 16 | } 17 | 18 | function minifyCss() { 19 | return gulp.src(join(APP_SRC, '**/*.css')) 20 | .pipe(plugins.minifyCss()) 21 | .pipe(gulp.dest(TMP_DIR)); 22 | } 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /tools/tasks/build.img.dev.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, APP_DEST} from '../config'; 3 | 4 | export = function buildImagesDev(gulp, plugins) { 5 | return function () { 6 | return gulp.src([ 7 | join(APP_SRC, '**/*.gif'), 8 | join(APP_SRC, '**/*.jpg'), 9 | join(APP_SRC, '**/*.png'), 10 | join(APP_SRC, '**/*.svg') 11 | ]) 12 | .pipe(gulp.dest(APP_DEST)); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /tools/tasks/build.index.ts: -------------------------------------------------------------------------------- 1 | import {join, sep} from 'path'; 2 | import {APP_SRC, APP_DEST, DEPENDENCIES, ENV} from '../config'; 3 | import {transformPath, templateLocals} from '../utils'; 4 | 5 | export = function buildIndexDev(gulp, plugins) { 6 | return function () { 7 | return gulp.src(join(APP_SRC, 'index.html')) 8 | // NOTE: There might be a way to pipe in loop. 9 | .pipe(inject('shims')) 10 | .pipe(inject('libs')) 11 | .pipe(inject()) 12 | .pipe(plugins.template(templateLocals())) 13 | .pipe(gulp.dest(APP_DEST)); 14 | }; 15 | 16 | 17 | function inject(name?: string) { 18 | return plugins.inject(gulp.src(getInjectablesDependenciesRef(name), { read: false }), { 19 | name, 20 | transform: transformPath(plugins, 'dev') 21 | }); 22 | } 23 | 24 | function getInjectablesDependenciesRef(name?: string) { 25 | return DEPENDENCIES 26 | .filter(dep => dep['inject'] && dep['inject'] === (name || true)) 27 | .map(mapPath); 28 | } 29 | 30 | function mapPath(dep) { 31 | let prodPath = join(dep.dest, dep.src.split(sep).pop()); 32 | return ('prod' === ENV ? prodPath : dep.src ); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /tools/tasks/build.js.dev.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, APP_DEST} from '../config'; 3 | import {templateLocals, tsProjectFn} from '../utils'; 4 | 5 | export = function buildJSDev(gulp, plugins) { 6 | let tsProject = tsProjectFn(plugins); 7 | return function () { 8 | let src = [ 9 | join(APP_SRC, '**/*.ts'), 10 | '!' + join(APP_SRC, '**/*_spec.ts') 11 | ]; 12 | 13 | let result = gulp.src(src) 14 | .pipe(plugins.plumber()) 15 | // Won't be required for non-production build after the change 16 | .pipe(plugins.inlineNg2Template({ base: APP_SRC })) 17 | .pipe(plugins.sourcemaps.init()) 18 | .pipe(plugins.typescript(tsProject)); 19 | 20 | return result.js 21 | .pipe(plugins.sourcemaps.write()) 22 | .pipe(plugins.template(templateLocals())) 23 | .pipe(gulp.dest(APP_DEST)); 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /tools/tasks/build.js.prod.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, TMP_DIR} from '../config'; 3 | import {templateLocals, tsProjectFn} from '../utils'; 4 | 5 | export = function buildJSDev(gulp, plugins) { 6 | return function () { 7 | let tsProject = tsProjectFn(plugins); 8 | let src = [ 9 | join(APP_SRC, '**/*.ts'), 10 | '!' + join(APP_SRC, '**/*_spec.ts') 11 | ]; 12 | 13 | let result = gulp.src(src) 14 | .pipe(plugins.plumber()) 15 | .pipe(plugins.inlineNg2Template({ base: TMP_DIR })) 16 | .pipe(plugins.typescript(tsProject)); 17 | 18 | return result.js 19 | .pipe(plugins.template(templateLocals())) 20 | .pipe(gulp.dest(TMP_DIR)); 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /tools/tasks/build.sass.dev.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC} from '../config'; 3 | 4 | export = function buildSassDev(gulp, plugins, option) { 5 | return function () { 6 | return gulp.src(join(APP_SRC, '**', '*.scss')) 7 | .pipe(plugins.sass().on('error', plugins.sass.logError)) 8 | .pipe(gulp.dest(APP_SRC)); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /tools/tasks/build.test.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, TEST_DEST} from '../config'; 3 | import {tsProjectFn} from '../utils'; 4 | 5 | export = function buildTest(gulp, plugins) { 6 | return function () { 7 | let tsProject = tsProjectFn(plugins); 8 | let src = [ 9 | join(APP_SRC, '**/*.ts'), 10 | '!' + join(APP_SRC, 'bootstrap.ts') 11 | ]; 12 | 13 | let result = gulp.src(src) 14 | .pipe(plugins.plumber()) 15 | .pipe(plugins.inlineNg2Template({ base: APP_SRC })) 16 | .pipe(plugins.typescript(tsProject)); 17 | 18 | return result.js 19 | .pipe(gulp.dest(TEST_DEST)); 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /tools/tasks/check.versions.ts: -------------------------------------------------------------------------------- 1 | import {VERSION_NPM, VERSION_NODE} from '../config'; 2 | 3 | function reportError(message: string) { 4 | console.error(require('chalk').white.bgRed.bold(message)); 5 | process.exit(1); 6 | } 7 | 8 | module.exports = function check(gulp, plugins) { 9 | return function () { 10 | let exec = require('child_process').exec; 11 | let semver = require('semver'); 12 | 13 | exec('npm --version', 14 | function (error, stdout, stderr) { 15 | if (error !== null) { 16 | reportError('npm preinstall error: ' + error + stderr); 17 | } 18 | 19 | if (!semver.gte(stdout, VERSION_NPM)) { 20 | reportError('NPM is not in required version! Required is ' + VERSION_NPM + ' and you\'re using ' + stdout); 21 | } 22 | }); 23 | 24 | exec('node --version', 25 | function (error, stdout, stderr) { 26 | if (error !== null) { 27 | reportError('npm preinstall error: ' + error + stderr); 28 | } 29 | 30 | if (!semver.gte(stdout, VERSION_NODE)) { 31 | reportError('NODE is not in required version! Required is ' + VERSION_NODE + ' and you\'re using ' + stdout); 32 | } 33 | }); 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /tools/tasks/clean.ts: -------------------------------------------------------------------------------- 1 | import * as async from 'async'; 2 | import * as del from 'del'; 3 | import {APP_DEST, TEST_DEST, TMP_DIR} from '../config'; 4 | 5 | export = function clean(gulp, plugins, option) { 6 | return function (done) { 7 | 8 | switch(option) { 9 | case 'all' : cleanAll(done); break; 10 | case 'dist' : cleanDist(done); break; 11 | case 'test' : cleanTest(done); break; 12 | case 'tmp' : cleanTmp(done); break; 13 | default: done(); 14 | } 15 | 16 | }; 17 | }; 18 | 19 | function cleanAll(done) { 20 | async.parallel([ 21 | cleanDist, 22 | cleanTest, 23 | cleanTmp 24 | ], done); 25 | } 26 | function cleanDist(done) { 27 | del(APP_DEST, done); 28 | } 29 | function cleanTest(done) { 30 | del(TEST_DEST, done); 31 | } 32 | function cleanTmp(done) { 33 | del(TMP_DIR, done); 34 | } 35 | -------------------------------------------------------------------------------- /tools/tasks/karma.start.ts: -------------------------------------------------------------------------------- 1 | import * as karma from 'karma'; 2 | import {join} from 'path'; 3 | 4 | export = function karmaStart() { 5 | return function (done) { 6 | new (karma).Server({ 7 | configFile: join(process.cwd(), 'karma.conf.js'), 8 | singleRun: true 9 | }).start(done); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /tools/tasks/npm.ts: -------------------------------------------------------------------------------- 1 | export = function npm(gulp, plugins) { 2 | return plugins.shell.task([ 3 | 'npm prune' 4 | ]); 5 | }; 6 | -------------------------------------------------------------------------------- /tools/tasks/serve.docs.ts: -------------------------------------------------------------------------------- 1 | import {serveDocs} from '../utils'; 2 | 3 | export = function serverStart(gulp, plugins) { 4 | return function () { 5 | serveDocs(); 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /tools/tasks/server.start.ts: -------------------------------------------------------------------------------- 1 | import {serveSPA} from '../utils'; 2 | 3 | export = function serverStart(gulp, plugins) { 4 | return function () { 5 | serveSPA(); 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /tools/tasks/tsd.ts: -------------------------------------------------------------------------------- 1 | export = function tsd(gulp, plugins) { 2 | return plugins.shell.task([ 3 | 'tsd reinstall --clean', 4 | 'tsd link', 5 | 'tsd rebundle' 6 | ]); 7 | }; 8 | -------------------------------------------------------------------------------- /tools/tasks/tslint.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC, TOOLS_DIR} from '../config'; 3 | 4 | export = function tslint(gulp, plugins) { 5 | return function () { 6 | let src = [ 7 | join(APP_SRC, '**/*.ts'), 8 | '!' + join(APP_SRC, '**/*.d.ts'), 9 | join(TOOLS_DIR, '**/*.ts'), 10 | '!' + join(TOOLS_DIR, '**/*.d.ts') 11 | ]; 12 | 13 | return gulp.src(src) 14 | .pipe(plugins.tslint()) 15 | .pipe(plugins.tslint.report(plugins.tslintStylish, { 16 | emitError: false, 17 | sort: true, 18 | bell: true 19 | })); 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /tools/tasks/watch.dev.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC} from '../config'; 3 | 4 | export = function watchDev(gulp, plugins) { 5 | return function () { 6 | plugins.watch(join(APP_SRC, '**/*'), () => gulp.start('build.dev')); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /tools/tasks/watch.serve.ts: -------------------------------------------------------------------------------- 1 | import * as runSequence from 'run-sequence'; 2 | import {join} from 'path'; 3 | import {APP_SRC} from '../config'; 4 | import {notifyLiveReload} from '../utils'; 5 | 6 | export = function watchServe(gulp, plugins) { 7 | return function () { 8 | plugins.watch(join(APP_SRC, '**'), e => 9 | runSequence('build.dev', () => notifyLiveReload(e)) 10 | ); 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /tools/tasks/watch.test.ts: -------------------------------------------------------------------------------- 1 | import {join} from 'path'; 2 | import {APP_SRC} from '../config'; 3 | 4 | export = function watchTest(gulp, plugins) { 5 | return function () { 6 | plugins.watch(join(APP_SRC, '**/*.ts'), () => gulp.start('build.test')); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /tools/typings/connect-livereload.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'connect-livereload' { 2 | function connectLivereload(options?: any): any; 3 | module connectLivereload {} 4 | export = connectLivereload; 5 | } 6 | -------------------------------------------------------------------------------- /tools/typings/gulp-load-plugins.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for gulp-load-plugins 2 | // Project: https://github.com/jackfranklin/gulp-load-plugins 3 | // Definitions by: Joe Skeen 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | // Does not support ES2015 import (import * as open from 'open'). 7 | 8 | /** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */ 9 | declare module 'gulp-load-plugins' { 10 | 11 | interface IOptions { 12 | /** the glob(s) to search for, default ['gulp-*', 'gulp.*'] */ 13 | pattern?: string[]; 14 | /** where to find the plugins, searched up from process.cwd(), default 'package.json' */ 15 | config?: string; 16 | /** which keys in the config to look within, default ['dependencies', 'devDependencies', 'peerDependencies'] */ 17 | scope?: string[]; 18 | /** what to remove from the name of the module when adding it to the context, default /^gulp(-|\.)/ */ 19 | replaceString?: RegExp; 20 | /** if true, transforms hyphenated plugin names to camel case, default true */ 21 | camelize?: boolean; 22 | /** whether the plugins should be lazy loaded on demand, default true */ 23 | lazy?: boolean; 24 | /** a mapping of plugins to rename, the key being the NPM name of the package, and the value being an alias you define */ 25 | rename?: IPluginNameMappings; 26 | } 27 | 28 | interface IPluginNameMappings { 29 | [npmPackageName: string]: string; 30 | } 31 | 32 | /** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */ 33 | function gulpLoadPlugins(options?: IOptions): T; 34 | module gulpLoadPlugins {} 35 | export = gulpLoadPlugins; 36 | } 37 | 38 | /** 39 | * Extend this interface to use Gulp plugins in your gulpfile.js 40 | */ 41 | interface IGulpPlugins { 42 | } 43 | -------------------------------------------------------------------------------- /tools/typings/karma.d.ts: -------------------------------------------------------------------------------- 1 | // Use this minimalistic definition file as bluebird dependency 2 | // generate a lot of errors. 3 | 4 | declare module 'karma' { 5 | var karma: IKarma; 6 | export = karma; 7 | interface IKarma { 8 | server: { 9 | start(options: any, callback: Function): void 10 | }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tools/typings/merge-stream.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'merge-stream' { 2 | function mergeStream(...streams: NodeJS.ReadWriteStream[]): MergeStream; 3 | interface MergeStream extends NodeJS.ReadWriteStream { 4 | add(stream: NodeJS.ReadWriteStream): MergeStream; 5 | } 6 | module mergeStream {} 7 | export = mergeStream; 8 | } -------------------------------------------------------------------------------- /tools/typings/open.d.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/borisyankov/DefinitelyTyped/tree/master/open 2 | // Does not support ES2015 import (import * as open from 'open'). 3 | 4 | declare module 'open' { 5 | function open(target: string, app?: string): void; 6 | module open {} 7 | export = open; 8 | } 9 | -------------------------------------------------------------------------------- /tools/typings/run-sequence.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'run-sequence' { 2 | function runSequence(...args: any[]): void; 3 | module runSequence {} 4 | export = runSequence; 5 | } 6 | -------------------------------------------------------------------------------- /tools/typings/slash.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'slash' { 2 | function slash(path: string): string; 3 | module slash {} 4 | export = slash; 5 | } 6 | -------------------------------------------------------------------------------- /tools/typings/systemjs-builder.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'systemjs-builder' { 2 | class Builder { 3 | constructor(configObject?: any, baseUrl?: string, configPath?: string); 4 | bundle(source: string, target: string, options?: any): Promise; 5 | buildStatic(source: string, target: string, options?: any): Promise; 6 | } 7 | 8 | module Builder {} 9 | export = Builder; 10 | } 11 | -------------------------------------------------------------------------------- /tools/typings/tiny-lr.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'tiny-lr' { 2 | function tinylr(): ITinylr; 3 | module tinylr {} 4 | export = tinylr; 5 | 6 | interface ITinylr { 7 | changed(options: any): void; 8 | listen(port: number): void; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/typings/yargs.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'yargs' { 2 | var yargs: IYargs; 3 | export = yargs; 4 | 5 | // Minimalistic but serves the usage in the seed. 6 | interface IYargs { 7 | argv: any; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/utils.ts: -------------------------------------------------------------------------------- 1 | export * from './utils/template-injectables'; 2 | export * from './utils/template-locals'; 3 | export * from './utils/server'; 4 | export * from './utils/tasks_tools'; 5 | 6 | 7 | export function tsProjectFn(plugins) { 8 | return plugins.typescript.createProject('tsconfig.json', { 9 | typescript: require('typescript') 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /tools/utils/server.ts: -------------------------------------------------------------------------------- 1 | import * as connectLivereload from 'connect-livereload'; 2 | import * as express from 'express'; 3 | import * as tinylrFn from 'tiny-lr'; 4 | import * as openResource from 'open'; 5 | import * as serveStatic from 'serve-static'; 6 | import {resolve} from 'path'; 7 | import {APP_BASE, APP_DEST, DOCS_DEST, LIVE_RELOAD_PORT, DOCS_PORT, PORT} from '../config'; 8 | 9 | let tinylr = tinylrFn(); 10 | 11 | 12 | export function serveSPA() { 13 | let server = express(); 14 | tinylr.listen(LIVE_RELOAD_PORT); 15 | 16 | server.use( 17 | APP_BASE, 18 | connectLivereload({ port: LIVE_RELOAD_PORT }), 19 | express.static(process.cwd()) 20 | ); 21 | 22 | server.listen(PORT, () => 23 | openResource('http://localhost:' + PORT + APP_BASE + APP_DEST) 24 | ); 25 | } 26 | 27 | export function notifyLiveReload(e) { 28 | let fileName = e.path; 29 | tinylr.changed({ 30 | body: { files: [fileName] } 31 | }); 32 | } 33 | 34 | export function serveDocs() { 35 | let server = express(); 36 | 37 | server.use( 38 | APP_BASE, 39 | serveStatic(resolve(process.cwd(), DOCS_DEST)) 40 | ); 41 | 42 | server.listen(DOCS_PORT, () => 43 | openResource('http://localhost:' + DOCS_PORT + APP_BASE) 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /tools/utils/tasks_tools.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as util from 'gulp-util'; 3 | import * as chalk from 'chalk'; 4 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 5 | import * as _runSequence from 'run-sequence'; 6 | import {readdirSync, existsSync, lstatSync} from 'fs'; 7 | import {join} from 'path'; 8 | import {TOOLS_DIR} from '../config'; 9 | 10 | const TASKS_PATH = join(TOOLS_DIR, 'tasks'); 11 | 12 | // NOTE: Remove if no issues with runSequence function below. 13 | // export function loadTasks(): void { 14 | // scanDir(TASKS_PATH, (taskname) => registerTask(taskname)); 15 | // } 16 | 17 | export function task(taskname: string, option?: string) { 18 | util.log('Loading task', chalk.yellow(taskname, option || '')); 19 | return require(join('..', 'tasks', taskname))(gulp, gulpLoadPlugins(), option); 20 | } 21 | 22 | export function runSequence(...sequence: any[]) { 23 | let tasks = []; 24 | let _sequence = sequence.slice(0); 25 | sequence.pop(); 26 | 27 | scanDir(TASKS_PATH, taskname => tasks.push(taskname)); 28 | 29 | sequence.forEach(task => { 30 | if (tasks.indexOf(task) > -1) { registerTask(task); } 31 | }); 32 | 33 | return _runSequence(..._sequence); 34 | } 35 | 36 | // ---------- 37 | // Private. 38 | 39 | function registerTask(taskname: string, filename?: string, option: string = ''): void { 40 | gulp.task(taskname, task(filename || taskname, option)); 41 | } 42 | 43 | // TODO: add recursive lookup ? or enforce pattern file + folder (ie ./tools/utils & ./tools/utils.ts ) 44 | function scanDir(root: string, cb: (taskname: string) => void) { 45 | if (!existsSync(root)) return; 46 | 47 | walk(root); 48 | 49 | function walk(path) { 50 | let files = readdirSync(path); 51 | for (let i = 0; i < files.length; i += 1) { 52 | let file = files[i]; 53 | let curPath = join(path, file); 54 | // if (lstatSync(curPath).isDirectory()) { // recurse 55 | // path = file; 56 | // walk(curPath); 57 | // } 58 | if (lstatSync(curPath).isFile() && /\.ts$/.test(file)) { 59 | let taskname = file.replace(/(\.ts)/, ''); 60 | cb(taskname); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tools/utils/template-injectables.ts: -------------------------------------------------------------------------------- 1 | import * as slash from 'slash'; 2 | import {join} from 'path'; 3 | import {APP_BASE, APP_DEST, ENV} from '../config'; 4 | 5 | let injectables: string[] = []; 6 | 7 | export function injectableAssetsRef() { 8 | return injectables; 9 | } 10 | 11 | export function registerInjectableAssetsRef(paths: string[], target: string = '') { 12 | injectables = injectables.concat( 13 | paths 14 | .filter(path => !/(\.map)$/.test(path)) 15 | .map(path => join(target, slash(path).split('/').pop())) 16 | ); 17 | } 18 | 19 | export function transformPath(plugins, env) { 20 | return function (filepath) { 21 | filepath = ENV === 'prod' ? filepath.replace(`/${APP_DEST}`, '') : filepath; 22 | arguments[0] = join(APP_BASE, filepath); 23 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments)); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /tools/utils/template-locals.ts: -------------------------------------------------------------------------------- 1 | import {APP_BASE, APP_DEST, APP_ROOT, APP_TITLE, SYSTEM_CONFIG, VERSION} from '../config'; 2 | 3 | // TODO: Add an interface to register more template locals. 4 | export function templateLocals() { 5 | return { 6 | APP_BASE, 7 | APP_DEST, 8 | APP_ROOT, 9 | APP_TITLE, 10 | SYSTEM_CONFIG, 11 | VERSION 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "noLib": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "sourceMap": true 12 | }, 13 | "exclude": [ 14 | "node_modules" 15 | ], 16 | "compileOnSave": false 17 | } 18 | -------------------------------------------------------------------------------- /tsd.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v4", 3 | "repo": "DefinitelyTyped/DefinitelyTyped", 4 | "ref": "master", 5 | "path": "tools/typings/tsd", 6 | "bundle": "tools/typings/tsd/tsd.d.ts", 7 | "installed": { 8 | "systemjs/systemjs.d.ts": { 9 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 10 | }, 11 | "gulp/gulp.d.ts": { 12 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 13 | }, 14 | "q/Q.d.ts": { 15 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 16 | }, 17 | "orchestrator/orchestrator.d.ts": { 18 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 19 | }, 20 | "gulp-shell/gulp-shell.d.ts": { 21 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 22 | }, 23 | "mime/mime.d.ts": { 24 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 25 | }, 26 | "express/express.d.ts": { 27 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 28 | }, 29 | "serve-static/serve-static.d.ts": { 30 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 31 | }, 32 | "del/del.d.ts": { 33 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 34 | }, 35 | "glob/glob.d.ts": { 36 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 37 | }, 38 | "minimatch/minimatch.d.ts": { 39 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 40 | }, 41 | "async/async.d.ts": { 42 | "commit": "5c3e47967affa3c4128a3875d1664ba206ae1b0f" 43 | }, 44 | "es6-promise/es6-promise.d.ts": { 45 | "commit": "923c5431d9447db9d5cf41adc5914e3c94c1ff10" 46 | }, 47 | "node/node.d.ts": { 48 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff" 49 | }, 50 | "gulp-util/gulp-util.d.ts": { 51 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff" 52 | }, 53 | "vinyl/vinyl.d.ts": { 54 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff" 55 | }, 56 | "through2/through2.d.ts": { 57 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff" 58 | }, 59 | "chalk/chalk.d.ts": { 60 | "commit": "5a8fc5ee71701431e4fdbb80c506e3c13f85a9ff" 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "curly": false, 5 | "eofline": true, 6 | "indent": "spaces", 7 | "max-line-length": [true, 140], 8 | "member-ordering": [true, 9 | "public-before-private", 10 | "static-before-instance", 11 | "variables-before-functions" 12 | ], 13 | "no-arg": true, 14 | "no-construct": true, 15 | "no-duplicate-key": true, 16 | "no-duplicate-variable": true, 17 | "no-empty": true, 18 | "no-eval": true, 19 | "no-trailing-comma": true, 20 | "no-trailing-whitespace": true, 21 | "no-unused-expression": true, 22 | "no-unused-variable": true, 23 | "no-unreachable": true, 24 | "no-use-before-declare": true, 25 | "one-line": [true, 26 | "check-open-brace", 27 | "check-catch", 28 | "check-else", 29 | "check-whitespace" 30 | ], 31 | "quotemark": [true, "single"], 32 | "semicolon": true, 33 | "triple-equals": true, 34 | "variable-name": false 35 | } 36 | } 37 | --------------------------------------------------------------------------------