├── src
├── app
│ ├── shared
│ │ ├── constant
│ │ │ ├── .gitignore
│ │ │ ├── main.ts
│ │ │ ├── index.ts
│ │ │ └── env.model.ts
│ │ ├── index.ts
│ │ └── navbar
│ │ │ ├── index.ts
│ │ │ ├── navbar.component.ts
│ │ │ ├── navbar.module.ts
│ │ │ └── navbar.html
│ ├── home
│ │ ├── home.css
│ │ ├── index.ts
│ │ ├── home.routes.ts
│ │ ├── home.component.ts
│ │ ├── home.module.ts
│ │ └── home.html
│ ├── app.providers.ts
│ ├── bundle.ts
│ ├── app.html
│ ├── todolist
│ │ ├── index.ts
│ │ ├── todolist.routes.ts
│ │ ├── todo.model.ts
│ │ ├── completed-filter.pipe.ts
│ │ ├── todolist.module.ts
│ │ ├── completed-filter.pipe.spec.ts
│ │ ├── todolist.component.ts
│ │ ├── todolist.html
│ │ └── todolist.component.spec.ts
│ ├── main.ts
│ ├── app.component.ts
│ ├── app.routing.ts
│ ├── app.module.ts
│ └── app.component.spec.ts
├── favicon.ico
├── assets
│ ├── styles
│ │ ├── fonts.scss
│ │ ├── overrides.scss
│ │ ├── variables.scss
│ │ ├── _bootstrap.variables.scss
│ │ ├── bootstrap.scss
│ │ ├── main.scss
│ │ ├── functions.scss
│ │ ├── module.scss
│ │ └── mixins.scss
│ ├── images
│ │ └── ng2.jpg
│ └── fonts
│ │ └── Roboto
│ │ ├── Roboto-Regular-webfont.eot
│ │ ├── Roboto-Regular-webfont.ttf
│ │ └── Roboto-Regular-webfont.woff
├── manual_typings
│ └── jasmine.d.ts
├── test
│ └── test-helpers
│ │ ├── global
│ │ ├── env.ts
│ │ └── matchers.ts
│ │ └── setup.ts
├── index.html
└── systemjs.conf.js
├── env.example.json
├── .travis.yml
├── config
├── gulp
│ ├── utils
│ │ ├── env-vars.js
│ │ ├── env.js
│ │ └── dashboard.js
│ ├── tasks
│ │ ├── sass.js
│ │ ├── clean.js
│ │ ├── serve.js
│ │ ├── component.js
│ │ ├── typescript.js
│ │ ├── build.js
│ │ └── test.js
│ └── config.js
├── env
│ └── env.ts
└── test
│ ├── protractor.conf.js
│ ├── karma-test-shim.js
│ └── karma.conf.js
├── .gitignore
├── gulpfile.js
├── tsconfig.json
├── e2e
└── home
│ └── home.spec.ts
├── .github
└── ISSUE_TEMPLATE.md
├── appveyor.yml
├── LICENSE
├── tslint.json
├── package.json
└── README.md
/src/app/shared/constant/.gitignore:
--------------------------------------------------------------------------------
1 | env.ts
--------------------------------------------------------------------------------
/env.example.json:
--------------------------------------------------------------------------------
1 | {
2 | "APP_URL": "localhost"
3 | }
--------------------------------------------------------------------------------
/src/app/home/home.css:
--------------------------------------------------------------------------------
1 | h4 {
2 | color: lightseagreen;
3 | }
--------------------------------------------------------------------------------
/src/app/app.providers.ts:
--------------------------------------------------------------------------------
1 | export const APP_PROVIDERS = [
2 | ];
3 |
--------------------------------------------------------------------------------
/src/app/bundle.ts:
--------------------------------------------------------------------------------
1 | // This file is for production only, please leave it blank
2 |
--------------------------------------------------------------------------------
/src/app/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from './constant/index';
2 | export * from './navbar/index';
3 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonybudianto/angular-starter/HEAD/src/favicon.ico
--------------------------------------------------------------------------------
/src/app/shared/navbar/index.ts:
--------------------------------------------------------------------------------
1 | export * from './navbar.component';
2 | export * from './navbar.module';
3 |
--------------------------------------------------------------------------------
/src/assets/styles/fonts.scss:
--------------------------------------------------------------------------------
1 | @include font-face(Roboto, 'Roboto/Roboto-Regular-webfont', 'eot svg ttf woff');
2 |
--------------------------------------------------------------------------------
/src/assets/styles/overrides.scss:
--------------------------------------------------------------------------------
1 | .panel-title {
2 | font-weight: bold;
3 | color: color(primary);
4 | }
5 |
--------------------------------------------------------------------------------
/src/assets/styles/variables.scss:
--------------------------------------------------------------------------------
1 | $font-stack: 'Roboto';
2 | $colors: (
3 | primary: cornflowerblue
4 | );
5 |
--------------------------------------------------------------------------------
/src/assets/images/ng2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonybudianto/angular-starter/HEAD/src/assets/images/ng2.jpg
--------------------------------------------------------------------------------
/src/app/shared/constant/main.ts:
--------------------------------------------------------------------------------
1 | export const MAIN = {
2 | APP: {
3 | BRAND: 'Angular Starter'
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/src/app/home/index.ts:
--------------------------------------------------------------------------------
1 | export * from './home.component';
2 | export * from './home.routes';
3 | export * from './home.module';
4 |
--------------------------------------------------------------------------------
/src/assets/styles/_bootstrap.variables.scss:
--------------------------------------------------------------------------------
1 | /* set variables for bootstrap
2 | eg.
3 |
4 | $font-size-base: 13px;
5 | */
6 |
7 |
--------------------------------------------------------------------------------
/src/assets/styles/bootstrap.scss:
--------------------------------------------------------------------------------
1 | @import 'bootstrap.variables';
2 | @import '../../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap';
--------------------------------------------------------------------------------
/src/manual_typings/jasmine.d.ts:
--------------------------------------------------------------------------------
1 | declare module jasmine {
2 | interface Matchers {
3 | toContainText(text: string): boolean;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7.0"
4 | - "6.9"
5 | script: npm run build
6 | after_script:
7 | - npm install -g codecov
8 | - codecov
9 |
--------------------------------------------------------------------------------
/config/gulp/utils/env-vars.js:
--------------------------------------------------------------------------------
1 | var ENV_VARS;
2 |
3 | try {
4 | ENV_VARS = require('../../../env.json');
5 | } catch(e) {}
6 |
7 | module.exports = ENV_VARS;
8 |
--------------------------------------------------------------------------------
/src/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/assets/fonts/Roboto/Roboto-Regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonybudianto/angular-starter/HEAD/src/assets/fonts/Roboto/Roboto-Regular-webfont.eot
--------------------------------------------------------------------------------
/src/assets/fonts/Roboto/Roboto-Regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonybudianto/angular-starter/HEAD/src/assets/fonts/Roboto/Roboto-Regular-webfont.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Roboto/Roboto-Regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antonybudianto/angular-starter/HEAD/src/assets/fonts/Roboto/Roboto-Regular-webfont.woff
--------------------------------------------------------------------------------
/src/app/shared/constant/index.ts:
--------------------------------------------------------------------------------
1 | import { MAIN } from './main';
2 | import { ENV } from './env';
3 |
4 | export const CONSTANTS = {
5 | MAIN,
6 | ENV
7 | };
8 |
--------------------------------------------------------------------------------
/src/test/test-helpers/global/env.ts:
--------------------------------------------------------------------------------
1 | // This lets systemjs.conf.js knows how to load the module during testing
2 | ((global) => {
3 | global.ENV = 'testing';
4 | })(this);
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | env.json
2 | .idea/
3 | .vscode
4 | /node_modules
5 | /bower_components
6 | /build
7 | /report
8 | /typings
9 | /src/tmp
10 | .DS_Store
11 | /src/assets/styles/*.css
--------------------------------------------------------------------------------
/src/assets/styles/main.scss:
--------------------------------------------------------------------------------
1 | @import 'bootstrap';
2 | @import 'variables';
3 | @import 'mixins';
4 | @import 'functions';
5 | @import 'fonts';
6 | @import 'overrides';
7 | @import 'module';
8 |
--------------------------------------------------------------------------------
/src/assets/styles/functions.scss:
--------------------------------------------------------------------------------
1 | @function color($key) {
2 | @if map-has-key($colors, $key) {
3 | @return map-get($colors, $key);
4 | }
5 |
6 | @warn "Unknown `#{$key}` in $colors.";
7 | @return null;
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/todolist/index.ts:
--------------------------------------------------------------------------------
1 | export * from './todo.model';
2 | export * from './todolist.component';
3 | export * from './todolist.routes';
4 | export * from './completed-filter.pipe';
5 | export * from './todolist.module';
6 |
--------------------------------------------------------------------------------
/src/app/home/home.routes.ts:
--------------------------------------------------------------------------------
1 | import { Routes } from '@angular/router';
2 |
3 | import { HomeComponent } from './home.component';
4 |
5 | export const HomeRoutes: Routes = [
6 | { path: '', component: HomeComponent }
7 | ];
8 |
--------------------------------------------------------------------------------
/src/app/todolist/todolist.routes.ts:
--------------------------------------------------------------------------------
1 | import { Routes } from '@angular/router';
2 |
3 | import { TodolistComponent } from './todolist.component';
4 |
5 | export const TodolistRoutes: Routes = [
6 | { path: 'todolist', component: TodolistComponent }
7 | ];
8 |
--------------------------------------------------------------------------------
/src/assets/styles/module.scss:
--------------------------------------------------------------------------------
1 | .center-fix {
2 | position: fixed;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | text-align: center;
7 | }
8 |
9 | .main-spinner {
10 | font-size: 3em;
11 | color: color(primary);
12 | }
13 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | requireDir = require('require-dir'),
3 | tasks = requireDir('./config/gulp/tasks'),
4 | dashboard = require('./config/gulp/utils/dashboard');
5 |
6 | dashboard.show();
7 |
8 | /* Default task */
9 | gulp.task('default', ['serve-dev']);
10 |
--------------------------------------------------------------------------------
/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | moduleId: module.id,
5 | selector: 'as-home',
6 | templateUrl: 'home.html',
7 | styleUrls: [
8 | 'home.css'
9 | ]
10 | })
11 | export class HomeComponent {
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { HomeComponent } from './index';
3 |
4 | @NgModule({
5 | declarations: [
6 | HomeComponent
7 | ],
8 | exports: [
9 | HomeComponent
10 | ]
11 | })
12 | export class HomeModule {
13 | }
14 |
--------------------------------------------------------------------------------
/config/gulp/utils/env.js:
--------------------------------------------------------------------------------
1 | var argv = require('yargs').argv;
2 |
3 | var ENVS = {
4 | DEV: 'development',
5 | PROD: 'production',
6 | TEST: 'testing'
7 | };
8 |
9 | var ENV = argv.env || process.env.NODE_ENV || ENVS.DEV;
10 |
11 | module.exports = {
12 | ENV: ENV,
13 | ENVS: ENVS
14 | };
15 |
--------------------------------------------------------------------------------
/src/test/test-helpers/setup.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import {
3 | BrowserDynamicTestingModule,
4 | platformBrowserDynamicTesting
5 | } from '@angular/platform-browser-dynamic/testing';
6 |
7 | TestBed.initTestEnvironment(
8 | BrowserDynamicTestingModule,
9 | platformBrowserDynamicTesting()
10 | );
11 |
--------------------------------------------------------------------------------
/src/app/home/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Home
4 |
5 |
6 |
Welcome to Angular Starter!
7 |

8 |
9 |
--------------------------------------------------------------------------------
/src/app/shared/constant/env.model.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Only valid JSON data types can be used for types
3 | *
4 | * Make sure the keys in `env.model.ts` exist in `env.json`
5 | * otherwise it'll throw message like this
6 | * Property '' is missing in type '{}'
7 | *
8 | */
9 |
10 | export interface AppEnv {
11 | APP_URL?: string;
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app.module';
5 |
6 | declare var ENV: string;
7 |
8 | if (ENV === 'production') {
9 | enableProdMode();
10 | }
11 |
12 | platformBrowserDynamic().bootstrapModule(AppModule);
13 |
--------------------------------------------------------------------------------
/src/app/shared/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
2 |
3 | @Component({
4 | moduleId: module.id,
5 | selector: 'as-navbar',
6 | templateUrl: 'navbar.html',
7 | changeDetection: ChangeDetectionStrategy.OnPush
8 | })
9 | export class NavbarComponent {
10 | @Input() brand: string;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | import { CONSTANTS } from './shared';
4 |
5 | @Component({
6 | moduleId: module.id,
7 | selector: 'as-main-app',
8 | templateUrl: 'app.html'
9 | })
10 | export class AppComponent {
11 | public appBrand: string;
12 |
13 | constructor() {
14 | this.appBrand = CONSTANTS.MAIN.APP.BRAND;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "skipLibCheck": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "removeComments": false,
11 | "noImplicitAny": false
12 | },
13 | "exclude": [
14 | "node_modules"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/e2e/home/home.spec.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | describe('Home page', () => {
4 | beforeAll(done => {
5 | browser.get('/')
6 | .then(done);
7 | });
8 |
9 | it('should have image', () => {
10 | browser.sleep(1000);
11 | let ng2Img = element(by.css('img'));
12 | expect(ng2Img.isDisplayed()).toBeTruthy();
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { Routes, RouterModule } from '@angular/router';
2 |
3 | import { HomeRoutes } from './home/index';
4 | import { TodolistRoutes } from './todolist/index';
5 |
6 | const appRoutes: Routes = [
7 | ...HomeRoutes,
8 | ...TodolistRoutes
9 | ];
10 |
11 | export const appRoutingProviders: any[] = [
12 |
13 | ];
14 |
15 | export const routing = RouterModule.forRoot(appRoutes);
16 |
--------------------------------------------------------------------------------
/src/app/shared/navbar/navbar.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule } from '@angular/router';
3 |
4 | import { NavbarComponent } from './index';
5 |
6 | @NgModule({
7 | declarations: [
8 | NavbarComponent
9 | ],
10 | imports: [
11 | RouterModule
12 | ],
13 | exports: [
14 | NavbarComponent
15 | ]
16 | })
17 | export class NavbarModule {
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/todolist/todo.model.ts:
--------------------------------------------------------------------------------
1 | export class Todo {
2 | public name: string;
3 | public done: boolean;
4 |
5 | static clone(todo: Todo): Todo {
6 | return new Todo(todo.name, todo.done);
7 | }
8 |
9 | constructor(name: string, done = false) {
10 | this.name = name;
11 | this.done = done;
12 | }
13 |
14 | clear() {
15 | this.name = '';
16 | this.done = false;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config/gulp/tasks/sass.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var sass = require('gulp-sass');
3 | var config = require('../config')();
4 |
5 | gulp.task('sass', function () {
6 | return gulp.src(config.assetsPath.styles + 'main.scss')
7 | .pipe(sass().on('error', sass.logError))
8 | .pipe(gulp.dest(config.assetsPath.styles));
9 | });
10 |
11 | gulp.task('watch-sass', function () {
12 | gulp.watch(config.assetsPath.styles + '**/*.scss', ['sass']);
13 | });
14 |
--------------------------------------------------------------------------------
/src/app/todolist/completed-filter.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { filter } from 'lodash';
3 |
4 | import { Todo } from './todo.model';
5 |
6 | @Pipe({
7 | name: 'asCompletedFilter'
8 | })
9 | export class CompletedFilterPipe implements PipeTransform {
10 | transform(todos: Todo[], done): Todo[] {
11 | if (done) {
12 | return todos;
13 | }
14 |
15 | return filter(todos, {done});
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/config/env/env.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * THIS FILE IS GENERATED by `gulp env` command from `env.json`
3 | * Generated on <%= new Date() %>
4 | *
5 | * Make sure the keys in `env.model.ts` exist in `env.json`
6 | * otherwise it'll throw message like this
7 | * Property '' is missing in type '{}'
8 | *
9 | * Feel free to modify for direct updates in development
10 | */
11 |
12 | import { AppEnv } from './env.model';
13 |
14 | export const ENV: AppEnv = {<% _.forEach(env, function(v, k) { %>
15 | <%= k %>: <%= _.isString(v) ? "\'"+v+"\'" : v %>,<% }) %>
16 | };
17 |
--------------------------------------------------------------------------------
/src/test/test-helpers/global/matchers.ts:
--------------------------------------------------------------------------------
1 | beforeEach(() => {
2 | jasmine.addMatchers({
3 | toContainText: () => {
4 | return {
5 | compare: (actual, expectedText) => {
6 | let actualText = actual.textContent;
7 | return {
8 | pass: actualText.indexOf(expectedText) > -1,
9 | get message() { return 'Expected ' + actualText + ' to contain ' + expectedText; }
10 | };
11 | }
12 | };
13 | }
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/src/app/todolist/todolist.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { FormsModule } from '@angular/forms';
4 | import { CompletedFilterPipe, TodolistComponent } from './index';
5 |
6 | @NgModule({
7 | declarations: [
8 | CompletedFilterPipe,
9 | TodolistComponent
10 | ],
11 | imports: [
12 | FormsModule,
13 | BrowserModule
14 | ],
15 | exports: [
16 | CompletedFilterPipe,
17 | TodolistComponent
18 | ]
19 | })
20 | export class TodolistModule {
21 | }
22 |
--------------------------------------------------------------------------------
/config/test/protractor.conf.js:
--------------------------------------------------------------------------------
1 | require('ts-node/register');
2 |
3 | var glob = require('glob');
4 | var seleniumPath = '../node_modules/gulp-protractor/node_modules/protractor/selenium/';
5 | var seleniumJarPath = '';
6 |
7 | glob(seleniumPath + '*.jar',
8 | function(err, files) {
9 | seleniumJarPath = files[0];
10 | });
11 |
12 | exports.config = {
13 | seleniumServerJar: seleniumJarPath,
14 | capabilities: {
15 | 'browserName': 'chrome'
16 | },
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 60000
20 | },
21 | allScriptsTimeout: 30000,
22 | useAllAngular2AppRoots: true
23 | };
24 |
--------------------------------------------------------------------------------
/src/assets/styles/mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin font-face($name, $path, $exts: eot woff2 woff ttf svg) {
2 | $src: null;
3 | $path: '../fonts/' + $path;
4 |
5 | $extmods: (
6 | eot: "?",
7 | svg: "#"
8 | );
9 |
10 | $formats: (
11 | otf: "opentype",
12 | ttf: "truetype"
13 | );
14 |
15 | @each $ext in $exts {
16 | $extmod: if(map-has-key($extmods, $ext), $ext + map-get($extmods, $ext), $ext);
17 | $format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext);
18 | $src: append($src, url(quote($path + "." + $extmod)) format(quote($format)), comma);
19 | }
20 |
21 | @font-face {
22 | font-family: quote($name);
23 | src: $src;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 |
4 | import { APP_PROVIDERS } from './app.providers';
5 | import { AppComponent } from './app.component';
6 | import { appRoutingProviders, routing } from './app.routing';
7 | import { NavbarModule } from './shared';
8 | import { HomeModule } from './home/home.module';
9 | import { TodolistModule } from './todolist/todolist.module';
10 |
11 | @NgModule({
12 | declarations: [
13 | AppComponent
14 | ],
15 | imports: [
16 | BrowserModule,
17 | NavbarModule,
18 | HomeModule,
19 | TodolistModule,
20 | routing
21 | ],
22 | providers: [ APP_PROVIDERS, appRoutingProviders ],
23 | bootstrap: [ AppComponent ]
24 | })
25 | export class AppModule {
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/todolist/completed-filter.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { CompletedFilterPipe } from './completed-filter.pipe';
2 | import { Todo } from './todo.model';
3 |
4 | describe('CompletedFilterPipe', () => {
5 | let pipe: CompletedFilterPipe;
6 | let todos: Todo[] = [
7 | new Todo('test1', true),
8 | new Todo('test2', false)
9 | ];
10 |
11 | beforeEach(() => {
12 | pipe = new CompletedFilterPipe();
13 | });
14 |
15 | it('should return original todos when pass true', () => {
16 | let result = pipe.transform(todos, true);
17 | expect(result).toEqual(todos);
18 | });
19 |
20 | it('should return not-completed todos when pass false', () => {
21 | let result = pipe.transform(todos, false);
22 | result.forEach(todo => expect(todo.done).toBeFalsy());
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/app/shared/navbar/navbar.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ## Issue Overview
6 |
7 |
8 | ## Issue Description
9 |
10 |
11 | ## Reproducables
12 |
13 |
14 | ## Information
15 | | | |
16 | |--------------------- |--------------------------------- |
17 | | **Operating System** | Windows/OSX/Ubuntu/orYourOSHere |
18 | | **Node version** | 4.x/5.x/orYourNodeVersionHere |
19 | | **NPM Version** | 2.x/3.x/orYourNPMVersionHere |
20 | | **Environment** | Browser/Mobile/WebWorker |
21 |
--------------------------------------------------------------------------------
/src/app/todolist/todolist.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | import { Todo } from './todo.model';
4 |
5 | @Component({
6 | moduleId: module.id,
7 | selector: 'as-todolist',
8 | templateUrl: 'todolist.html'
9 | })
10 | export class TodolistComponent {
11 | public todo: Todo;
12 | private list: Todo[];
13 | private showCompleted: Boolean;
14 |
15 | constructor() {
16 | this.showCompleted = true;
17 | this.todo = new Todo('Add me to list!', false);
18 | this.list = [
19 | new Todo('Its cool'),
20 | new Todo('Hello', true)
21 | ];
22 | }
23 |
24 | addTodo() {
25 | this.list = this.list.concat(Todo.clone(this.todo));
26 | this.todo.clear();
27 | }
28 |
29 | delTodo(todoIndex: number) {
30 | this.list = this.list.filter(
31 | (todo, index) => index !== todoIndex);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/config/gulp/tasks/clean.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var config = require('../config')();
3 | var del = require('del');
4 |
5 | /* Run all clean tasks */
6 | gulp.task('clean', ['clean-build', 'clean-report', 'clean-ts', 'clean-sass']);
7 |
8 | /* Clean build folder */
9 | gulp.task('clean-build', function () {
10 | return del([config.build.path]);
11 | });
12 |
13 | /* Clean report folder */
14 | gulp.task('clean-report', function () {
15 | return del([config.report.path]);
16 | });
17 |
18 | /* Clean sass compile */
19 | gulp.task('clean-sass', function () {
20 | return del([config.assetsPath.styles + '**/*.css']);
21 | });
22 |
23 | /* Clean js and map */
24 | gulp.task('clean-ts', function () {
25 | return del([config.tmp]);
26 | });
27 |
28 | gulp.task('clean-ts-app', function () {
29 | return del([config.tmpApp]);
30 | });
31 |
32 | gulp.task('clean-ts-test', function () {
33 | return del([config.tmpTest]);
34 | });
--------------------------------------------------------------------------------
/config/gulp/tasks/serve.js:
--------------------------------------------------------------------------------
1 | var runSequence = require('run-sequence');
2 |
3 | var envConfig = require('../utils/env');
4 |
5 | if (envConfig.ENV === envConfig.ENVS.DEV)
6 | {
7 | var gulp = require('gulp');
8 | var config = require('../config')();
9 | var bs = require("browser-sync");
10 |
11 | function startBrowsersync (config)
12 | {
13 | bsIns = bs.create();
14 | bsIns.init(config);
15 | bsIns.reload();
16 | }
17 |
18 | /* Start live server dev mode */
19 | gulp.task('serve-dev', function ()
20 | {
21 | runSequence(
22 | ['sass', 'tsc-app'],
23 | ['html', 'css'],
24 | ['watch-sass', 'watch-ts', 'watch-html', 'watch-css'], function() {
25 | startBrowsersync(config.browserSync.dev);
26 | });
27 | });
28 |
29 | /* Start live server production mode */
30 | gulp.task('serve-build', ['build'], function ()
31 | {
32 | startBrowsersync(config.browserSync.prod);
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/config/gulp/tasks/component.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var path = require('path');
3 |
4 | var config = require('../config')();
5 |
6 | gulp.task('html', function () {
7 | return gulp.src(config.app + '**/*.html')
8 | .pipe(gulp.dest(config.tmpApp));
9 | });
10 |
11 | gulp.task('watch-html', function () {
12 | gulp.watch(config.app + '**/*.html', function(file) {
13 | var des = convertToTmpPath(file);
14 |
15 | return gulp.src(file.path)
16 | .pipe(gulp.dest(path.dirname(des)));
17 | });
18 | });
19 |
20 | gulp.task('css', function () {
21 | return gulp.src(config.app + '**/*.css')
22 | .pipe(gulp.dest(config.tmpApp));
23 | });
24 |
25 | gulp.task('watch-css', function () {
26 | gulp.watch(config.app + '**/*.css', function(file) {
27 | var des = convertToTmpPath(file);
28 |
29 | return gulp.src(file.path)
30 | .pipe(gulp.dest(path.dirname(des)));
31 | });
32 | });
33 |
34 | function convertToTmpPath(file) {
35 | var re = new RegExp('src\\' + path.sep + 'app\\' + path.sep,"g");
36 | return file.path.replace(re, config.tmpApp);
37 | }
--------------------------------------------------------------------------------
/config/gulp/utils/dashboard.js:
--------------------------------------------------------------------------------
1 | var envVars = require('../utils/env-vars'),
2 | envConfig = require('../utils/env'),
3 | util = require('gulp-util'),
4 | _ = require('lodash'),
5 | envStatusMessage;
6 |
7 | var color;
8 | var colorMap = {
9 | 'development': 'bgGreen',
10 | 'production': 'bgCyan'
11 | };
12 | color = colorMap[envConfig.ENV] || 'bgMagenta';
13 |
14 | var StarterDashboard = {
15 | show: function() {
16 | if (envVars) {
17 | envStatusMessage = '- env.json is detected. ' + _.toArray(envVars).length +
18 | ' values loaded.';
19 | } else {
20 | envStatusMessage = '- env.json is not detected. You can create one on project root';
21 | }
22 |
23 | console.log('============ Angular 2 Starter ============');
24 | console.log('Current environment: ' + util.colors[color](envConfig.ENV));
25 | console.log('- Change environment via --env or NODE_ENV');
26 | console.log(envStatusMessage);
27 | console.log('===========================================');
28 | }
29 | };
30 |
31 | module.exports = StarterDashboard;
32 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # AppVeyor file
2 | # http://www.appveyor.com/docs/appveyor-yml
3 | # This file: cloned from https://github.com/gruntjs/grunt/blob/master/appveyor.yml
4 |
5 | # Build version format
6 | version: "{build}"
7 |
8 | # Test against this version of Node.js
9 | environment:
10 | nodejs_version: "5.5.0"
11 |
12 | build: off
13 |
14 | clone_depth: 10
15 |
16 | # Fix line endings on Windows
17 | init:
18 | - git config --global core.autocrlf true
19 |
20 | install:
21 | - ps: Install-Product node $env:nodejs_version
22 | - npm install -g npm
23 | - ps: $env:path = $env:appdata + "\npm;" + $env:path
24 | - npm install
25 |
26 | test_script:
27 | # Output useful info for debugging.
28 | - node --version && npm --version
29 | - node -e 'console.log(process.env);'
30 | # We test multiple Windows shells because of prior stdout buffering issues
31 | # filed against Grunt. https://github.com/joyent/node/issues/3584
32 | - ps: "npm test # PowerShell" # Pass comment to PS for easier debugging
33 | - cmd: npm test
34 |
35 | cache:
36 | - node_modules -> package.json # local npm modules
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Antony Budianto
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 |
--------------------------------------------------------------------------------
/config/test/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | // Turn on full stack traces in errors to help debugging
2 | Error.stackTraceLimit=Infinity;
3 |
4 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
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.import('test/test-helpers/setup')
11 | .then(function() {
12 | return Promise.all(
13 | Object.keys(window.__karma__.files)
14 | .filter(onlySpecFiles)
15 | .map(file2moduleName)
16 | .map(importModules)
17 | );
18 | })
19 | .then(function() {
20 | __karma__.start();
21 | }, function(error) {
22 | __karma__.error(error.name + ": " + error.message);
23 | });
24 |
25 | // Filter spec files
26 | function onlySpecFiles(path) {
27 | return /\.spec\.js$/.test(path);
28 | }
29 |
30 | // Normalize paths to module names.
31 | function file2moduleName(filePath) {
32 | return filePath.replace(/\\/g, '/')
33 | .replace(/^\/base\//, '')
34 | .replace(/\.js/, '');
35 | }
36 |
37 | // Import module path
38 | function importModules(path) {
39 | return System.import(path);
40 | }
41 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Angular Starter
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RouterTestingModule
3 | } from '@angular/router/testing';
4 | import {
5 | async,
6 | TestBed,
7 | ComponentFixture
8 | } from '@angular/core/testing';
9 | import { provideRoutes, Routes, RouterModule } from '@angular/router';
10 | import { Component } from '@angular/core';
11 |
12 | import { AppComponent } from './app.component';
13 | import { NavbarComponent } from './shared/navbar/navbar.component';
14 |
15 | @Component({
16 | selector: 'as-test-cmp',
17 | template: 'Hello test
'
18 | })
19 | class TestRouterComponent {
20 | }
21 |
22 | let config: Routes = [
23 | {
24 | path: '', component: TestRouterComponent
25 | }
26 | ];
27 |
28 | describe('AppComponent', () => {
29 | beforeEach(() => {
30 | TestBed.configureTestingModule({
31 | declarations: [
32 | TestRouterComponent,
33 | AppComponent,
34 | NavbarComponent
35 | ],
36 | imports: [ RouterTestingModule, RouterModule ],
37 | providers: [ provideRoutes(config) ]
38 | });
39 | });
40 |
41 | it('should have title Hello world', async(() => {
42 | TestBed.compileComponents().then(() => {
43 | let fixture: ComponentFixture;
44 | fixture = TestBed.createComponent(AppComponent);
45 | fixture.detectChanges();
46 |
47 | let compiled = fixture.debugElement.nativeElement;
48 | expect(compiled).toBeDefined();
49 | // TODO: find a way to compile the routed component
50 | // expect(compiled.querySelector('div.title')).toMatch('Hello world');
51 | });
52 | }));
53 | });
54 |
--------------------------------------------------------------------------------
/src/app/todolist/todolist.html:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
To Do List {{list.length}}
23 |
24 |
51 |
52 |
--------------------------------------------------------------------------------
/src/systemjs.conf.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This config is only used during development and build phase only
3 | * It will not be available on production
4 | *
5 | */
6 |
7 | (function(global) {
8 | // ENV
9 | global.ENV = global.ENV || 'development';
10 |
11 | // map tells the System loader where to look for things
12 | var map = {
13 | 'app': 'src/tmp/app',
14 | 'test': 'src/tmp/test'
15 | };
16 |
17 | // packages tells the System loader how to load when no filename and/or no extension
18 | var packages = {
19 | 'app': {
20 | defaultExtension: 'js'
21 | },
22 | 'test': {
23 | defaultExtension: 'js'
24 | },
25 | 'rxjs': {
26 | defaultExtension: 'js'
27 | }
28 | };
29 |
30 | // List npm packages here
31 | var npmPackages = [
32 | '@angular',
33 | 'rxjs',
34 | 'lodash'
35 | ];
36 |
37 | // Add package entries for packages that expose barrels using index.js
38 | var packageNames = [
39 | // App barrels
40 | 'app/shared',
41 |
42 | // 3rd party barrels
43 | 'lodash'
44 | ];
45 |
46 | // Add package entries for angular packages
47 | var ngPackageNames = [
48 | 'common',
49 | 'compiler',
50 | 'core',
51 | 'forms',
52 | 'http',
53 | 'platform-browser',
54 | 'platform-browser-dynamic',
55 | 'router'
56 | ];
57 |
58 | npmPackages.forEach(function (pkgName) {
59 | map[pkgName] = 'node_modules/' + pkgName;
60 | });
61 |
62 | packageNames.forEach(function(pkgName) {
63 | packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
64 | });
65 |
66 | ngPackageNames.forEach(function(pkgName) {
67 | map['@angular/' + pkgName] = 'node_modules/@angular/' + pkgName +
68 | '/bundles/' + pkgName + '.umd.js';
69 | map['@angular/' + pkgName+'/testing'] = 'node_modules/@angular/' + pkgName +
70 | '/bundles/' + pkgName + '-testing.umd.js';
71 | });
72 |
73 | var config = {
74 | map: map,
75 | packages: packages
76 | };
77 |
78 | // filterSystemConfig - index.html's chance to modify config before we register it.
79 | if (global.filterSystemConfig) { global.filterSystemConfig(config); }
80 |
81 | System.config(config);
82 |
83 | })(this);
84 |
--------------------------------------------------------------------------------
/config/gulp/tasks/typescript.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var util = require('gulp-util');
3 | var config = require('../config')();
4 | var ts = require('gulp-typescript');
5 | var tslint = require('gulp-tslint');
6 | var sourcemaps = require('gulp-sourcemaps');
7 | var argv = require('yargs').argv;
8 |
9 | /* Initialize TS Project */
10 | var typingFiles = [
11 | config.src + 'manual_typings/**/*.d.ts'
12 | ];
13 | var tsUnitFiles = [].concat(config.tsTestFiles.unit, config.tsTestFiles.helper);
14 | var tsFiles = [].concat(config.tsFiles, tsUnitFiles);
15 |
16 | /* Watch changed typescripts file and compile it */
17 | gulp.task('watch-ts', function () {
18 | return gulp.watch(tsFiles, function (file) {
19 | util.log('Compiling ' + file.path + '...');
20 | return compileTs(file.path, true);
21 | });
22 | });
23 |
24 | /* Compile typescripts */
25 | gulp.task('tsc', ['clean-ts', 'env'], function () {
26 | return compileTs(tsFiles);
27 | });
28 |
29 | gulp.task('tsc-app', ['env'], function () {
30 | return compileTs(config.tsFiles);
31 | });
32 |
33 | gulp.task('tsc-unit', ['clean-ts-test'], function () {
34 | return compileTs(tsUnitFiles);
35 | });
36 |
37 | /* Lint typescripts */
38 | gulp.task('tslint', function () {
39 | return lintTs(tsFiles);
40 | });
41 |
42 | gulp.task('tslint-app', function () {
43 | return lintTs(config.tsFiles);
44 | });
45 |
46 | gulp.task('tslint-unit', function () {
47 | return lintTs(tsUnitFiles);
48 | });
49 |
50 | function lintTs(files) {
51 | return gulp.src(files)
52 | .pipe(tslint({
53 | formatter: 'verbose'
54 | }))
55 | .pipe(tslint.report());
56 | }
57 |
58 | function compileTs(files, watchMode) {
59 | watchMode = watchMode || false;
60 |
61 | var tsProject = ts.createProject('tsconfig.json');
62 | var allFiles = [].concat(files, typingFiles);
63 | var res = gulp.src(allFiles, {
64 | base: config.src,
65 | outDir: config.tmp
66 | })
67 | .pipe(tslint({
68 | formatter: 'verbose'
69 | }))
70 | .pipe(tslint.report())
71 | .pipe(sourcemaps.init())
72 | .pipe(tsProject())
73 | .on('error', function () {
74 | if (watchMode) {
75 | return;
76 | }
77 | process.exit(1);
78 | });
79 | return res.js
80 | .pipe(sourcemaps.write())
81 | .pipe(gulp.dest(config.tmp));
82 | }
--------------------------------------------------------------------------------
/config/gulp/tasks/build.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var util = require('gulp-util');
3 | var runSequence = require('run-sequence');
4 | var config = require('../config')();
5 | var useref = require('gulp-useref');
6 | var gulpif = require('gulp-if');
7 | var rev = require('gulp-rev');
8 | var revReplace = require('gulp-rev-replace');
9 | var uglify = require('gulp-uglify');
10 | var cssnano = require('gulp-cssnano');
11 | var gulpTemplate = require('gulp-template');
12 | var flatten = require('gulp-flatten');
13 |
14 | var envVars = require('../utils/env-vars');
15 |
16 | require('@ngstarter/systemjs-extension')(config);
17 |
18 | gulp.task('build', function (done) {
19 | runSequence('test', 'build-systemjs', 'build-assets', done);
20 | });
21 |
22 | /* Concat and minify/uglify all css, js, and copy fonts */
23 | gulp.task('build-assets', function (done) {
24 | runSequence('clean-build', ['sass', 'fonts'], function () {
25 | gulp.src(config.app + '**/*.html')
26 | .pipe(flatten())
27 | .pipe(gulp.dest(config.build.path));
28 |
29 | gulp.src(config.app + '**/*.css')
30 | .pipe(cssnano({zindex: false}))
31 | .pipe(flatten())
32 | .pipe(gulp.dest(config.build.path));
33 |
34 | gulp.src(config.src + 'favicon.ico')
35 | .pipe(gulp.dest(config.build.path));
36 |
37 | gulp.src(config.assetsPath.images + '**/*.*', {
38 | base: config.assetsPath.images
39 | })
40 | .pipe(gulp.dest(config.build.assetPath + 'images'));
41 |
42 | gulp.src(config.index)
43 | .pipe(useref())
44 | .pipe(gulpif('assets/lib.js', uglify()))
45 | .pipe(gulpif('*.css', cssnano()))
46 | .pipe(gulpif('!*.html', rev()))
47 | .pipe(revReplace())
48 | .pipe(gulp.dest(config.build.path))
49 | .on('finish', done);
50 | });
51 | });
52 |
53 | /* Copy fonts in packages */
54 | gulp.task('fonts', function () {
55 | gulp.src(config.assetsPath.fonts + '**/*.*', {
56 | base: config.assetsPath.fonts
57 | })
58 | .pipe(gulp.dest(config.build.fonts));
59 |
60 | gulp.src([
61 | 'node_modules/font-awesome/fonts/*.*'
62 | ])
63 | .pipe(gulp.dest(config.build.fonts));
64 | });
65 |
66 | gulp.task('env', function () {
67 | return gulp.src(config.config + 'env/env.ts')
68 | .pipe(gulpTemplate({
69 | env: envVars || {}
70 | }))
71 | .pipe(gulp.dest(config.app + 'shared/constant'))
72 | .on('finish', function () {
73 | util.log(config.app + 'shared/constant/env.ts is generated successfully');
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/src/app/todolist/todolist.component.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | async,
3 | TestBed
4 | } from '@angular/core/testing';
5 | import { Component } from '@angular/core';
6 |
7 | import { Todo, TodolistComponent, TodolistModule } from './index';
8 |
9 | @Component({
10 | selector: 'as-test',
11 | template: ''
12 | })
13 | class TestComponent {
14 | }
15 |
16 | let todoCompiled;
17 | let todolistCmp: TodolistComponent;
18 |
19 | describe('TodolistComponent', () => {
20 | beforeEach(() => {
21 | TestBed.configureTestingModule({
22 | declarations: [ TestComponent ],
23 | imports: [ TodolistModule ]
24 | });
25 | });
26 |
27 | it('should have been created successfully', async(() => {
28 | TestBed.compileComponents().then(() => {
29 | let fixture = TestBed.createComponent(TestComponent);
30 | fixture.detectChanges();
31 |
32 | todoCompiled = fixture.nativeElement;
33 | todolistCmp = fixture.debugElement
34 | .children[0].componentInstance;
35 | expect(todoCompiled).toBeDefined();
36 | });
37 | }));
38 |
39 | it('should add todo successfully', async(() => {
40 | TestBed.compileComponents().then(() => {
41 | let fixture = TestBed.createComponent(TestComponent);
42 | fixture.detectChanges();
43 | todoCompiled = fixture.nativeElement;
44 | todolistCmp = fixture.debugElement
45 | .children[0].componentInstance;
46 | todolistCmp.todo = new Todo('test', true);
47 | todolistCmp.addTodo();
48 | fixture.detectChanges();
49 |
50 | let items = todoCompiled.querySelectorAll('.list-group-item');
51 | expect(items.length).toEqual(3);
52 |
53 | let item = items[items.length - 1];
54 | expect(item.querySelector('label').textContent).toEqual(' test');
55 | expect(item.querySelector('input[type="checkbox"]').value).toBeTruthy();
56 | });
57 | }));
58 |
59 | it('should delete todo successfully', async(() => {
60 | TestBed.compileComponents().then(() => {
61 | let fixture = TestBed.createComponent(TestComponent);
62 | fixture.detectChanges();
63 |
64 | todoCompiled = fixture.nativeElement;
65 | todolistCmp = fixture.debugElement
66 | .children[0].componentInstance;
67 |
68 | todolistCmp.delTodo(0);
69 | fixture.detectChanges();
70 | expect(todoCompiled.querySelectorAll('.list-group-item').length)
71 | .toEqual(1);
72 | });
73 | }));
74 | });
75 |
--------------------------------------------------------------------------------
/config/gulp/tasks/test.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var util = require('gulp-util');
3 | var config = require('../config')();
4 | var Server = require('karma').Server;
5 | var gulpProtractor = require('gulp-protractor');
6 | var remapIstanbul = require('remap-istanbul/lib/gulpRemapIstanbul');
7 | var runSequence = require('run-sequence');
8 | var argv = require('yargs')
9 | .alias('w', 'watch')
10 | .argv;
11 |
12 | gulp.task('test', ['clean-report', 'unit-test']);
13 |
14 | gulp.task('unit-test', ['tsc'], function (done) {
15 | var watch = argv.watch || false;
16 |
17 | runSequence(['html', 'css'], copyComponentFilesDone);
18 |
19 | if (watch) {
20 | runSequence(['watch-ts', 'watch-html', 'watch-css']);
21 | console.log('=== Unit Test Watch Mode ===');
22 | console.log('- It will autowatch the changed files and re-run the test');
23 | console.log('- Press Cmd/Ctrl + C to exit and get the coverage result');
24 | console.log('- Press Cmd/Ctrl + C again to close the TSC watch.');
25 | }
26 |
27 | function copyComponentFilesDone() {
28 | new Server({
29 | configFile: __dirname + '/../../test/karma.conf.js',
30 | singleRun: !watch
31 | }, karmaDone).start();
32 | }
33 |
34 | function karmaDone (exitCode) {
35 | remapCoverage(done, exitCode);
36 | }
37 | });
38 |
39 | gulp.task('e2e', ['e2e-test']);
40 | gulp.task('driver-update', gulpProtractor['webdriver_update']);
41 | gulp.task('e2e-test', ['driver-update'], function () {
42 | gulp.src(config.e2e + '**/*.spec.ts')
43 | .pipe(gulpProtractor.protractor({
44 | configFile: 'config/test/protractor.conf.js',
45 | args: ['--baseUrl', config.e2eConfig.seleniumTarget]
46 | }))
47 | .on('error', function(e) {
48 | util.log('Error running E2E testing');
49 | process.exit(1);
50 | });
51 | });
52 |
53 | function remapCoverage (done, exitCode) {
54 | util.log('Remapping coverage to TypeScript format...');
55 | gulp.src(config.report.path + 'report-json/coverage-final.json')
56 | .pipe(remapIstanbul({
57 | reports: {
58 | 'lcovonly': config.report.path + 'remap/lcov.info',
59 | 'json': config.report.path + 'remap/coverage.json',
60 | 'html': config.report.path + 'remap/html-report',
61 | 'text-summary': config.report.path + 'remap/text-summary.txt'
62 | }
63 | }))
64 | .on('finish', function () {
65 | util.log('Test Done with exit code: ' + exitCode);
66 | done(exitCode);
67 | util.log('Remapping done! View the result in report/remap/html-report');
68 | });
69 | }
70 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "class-name": true,
7 | "comment-format": [true, "check-space"],
8 | "curly": true,
9 | "eofline": true,
10 | "forin": true,
11 | "indent": [true, "spaces"],
12 | "label-position": true,
13 | "max-line-length": [true, 140],
14 | "member-access": false,
15 | "member-ordering": [true,
16 | "public-before-private",
17 | "static-before-instance",
18 | "variables-before-functions"
19 | ],
20 | "no-arg": true,
21 | "no-bitwise": true,
22 | "no-console": [true,
23 | "debug",
24 | "info",
25 | "time",
26 | "timeEnd",
27 | "trace"
28 | ],
29 | "no-construct": true,
30 | "no-debugger": true,
31 | "no-duplicate-variable": true,
32 | "no-empty": true,
33 | "no-eval": true,
34 | "no-inferrable-types": true,
35 | "no-shadowed-variable": true,
36 | "no-string-literal": true,
37 | "no-switch-case-fall-through": true,
38 | "trailing-comma": true,
39 | "no-trailing-whitespace": true,
40 | "no-unused-expression": true,
41 | "no-use-before-declare": true,
42 | "no-var-keyword": true,
43 | "object-literal-sort-keys": false,
44 | "one-line": [true,
45 | "check-open-brace",
46 | "check-catch",
47 | "check-else",
48 | "check-whitespace"
49 | ],
50 | "quotemark": [true, "single"],
51 | "radix": true,
52 | "semicolon": [true, "always"],
53 | "triple-equals": [true, "allow-null-check"],
54 | "typedef-whitespace": [true, {
55 | "call-signature": "nospace",
56 | "index-signature": "nospace",
57 | "parameter": "nospace",
58 | "property-declaration": "nospace",
59 | "variable-declaration": "nospace"
60 | }],
61 | "variable-name": false,
62 | "whitespace": [true,
63 | "check-branch",
64 | "check-decl",
65 | "check-operator",
66 | "check-separator",
67 | "check-type"
68 | ],
69 |
70 | "directive-selector": [true, "attribute", ["as"], "camelCase"],
71 | "component-selector": [true, "element", ["as"], "kebab-case"],
72 | "use-input-property-decorator": true,
73 | "use-output-property-decorator": true,
74 | "use-host-property-decorator": true,
75 | "no-attribute-parameter-decorator": true,
76 | "no-input-rename": true,
77 | "no-output-rename": true,
78 | "no-forward-ref": true,
79 | "use-life-cycle-interface": true,
80 | "use-pipe-transform-interface": true,
81 | "component-class-suffix": [true, "Component"],
82 | "directive-class-suffix": [true, "Directive"],
83 | "import-destructuring-spacing": true,
84 | "templates-use-public": false,
85 | "no-access-missing-member": true,
86 | "invoke-injectable": true
87 | }
88 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-starter",
3 | "version": "1.1.1",
4 | "author": "Antony Budianto",
5 | "description": "Angular Starter with extensible features",
6 | "main": "src/tmp/app/main.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/antonybudianto/angular-starter.git"
10 | },
11 | "engines": {
12 | "node": ">=6.9",
13 | "npm": "~3.0.0"
14 | },
15 | "scripts": {
16 | "start": "gulp serve-dev",
17 | "lint": "gulp tslint",
18 | "test": "gulp test",
19 | "e2e": "gulp e2e",
20 | "env": "gulp env",
21 | "build": "gulp build",
22 | "serve-build": "gulp serve-build",
23 | "clean": "gulp clean",
24 | "coverage": "coveralls < ./report/remap/lcov.info"
25 | },
26 | "keywords": [
27 | "angular",
28 | "starter",
29 | "seed",
30 | "gulp",
31 | "webpack",
32 | "extensible",
33 | "systemjs",
34 | "systemjs builder",
35 | "travis",
36 | "karma",
37 | "jasmine",
38 | "istanbul"
39 | ],
40 | "license": "MIT",
41 | "bugs": {
42 | "url": "https://github.com/antonybudianto/angular-starter/issues"
43 | },
44 | "dependencies": {
45 | "@angular/common": "~4.4.3",
46 | "@angular/compiler": "~4.4.3",
47 | "@angular/core": "~4.4.3",
48 | "@angular/forms": "~4.4.3",
49 | "@angular/http": "~4.4.3",
50 | "@angular/platform-browser": "~4.4.3",
51 | "@angular/platform-browser-dynamic": "~4.4.3",
52 | "@angular/router": "~4.4.3",
53 | "@ngstarter/systemjs-extension": "2.0.1",
54 | "@types/core-js": "0.9.43",
55 | "@types/jasmine": "2.6.0",
56 | "@types/lodash": "4.14.74",
57 | "@types/selenium-webdriver": "^3.0.7",
58 | "bootstrap-sass": "^3.3.7",
59 | "codelyzer": "3.2.0",
60 | "core-js": "^2.5.1",
61 | "del": "~3.0.0",
62 | "font-awesome": "^4.7.0",
63 | "glob": "^7.1.2",
64 | "gulp": "^3.9.1",
65 | "gulp-cssnano": "^2.1.2",
66 | "gulp-flatten": "^0.3.1",
67 | "gulp-if": "~2.0.2",
68 | "gulp-protractor": "^4.1.0",
69 | "gulp-rev": "^8.0.0",
70 | "gulp-rev-replace": "^0.4.3",
71 | "gulp-sass": "^3.1.0",
72 | "gulp-sourcemaps": "^2.6.1",
73 | "gulp-template": "^4.0.0",
74 | "gulp-tslint": "8.1.2",
75 | "gulp-typescript": "~3.2.2",
76 | "gulp-uglify": "~3.0.0",
77 | "gulp-useref": "~3.1.2",
78 | "jasmine-core": "~2.8.0",
79 | "jquery": "^3.2.1",
80 | "karma": "~1.7.1",
81 | "karma-coverage": "~1.1.1",
82 | "karma-ie-launcher": "^1.0.0",
83 | "karma-jasmine": "~1.1.0",
84 | "karma-phantomjs-launcher": "~1.0.4",
85 | "karma-sourcemap-loader": "^0.3.7",
86 | "lodash": "^4.17.4",
87 | "phantomjs-prebuilt": "^2.1.15",
88 | "remap-istanbul": "0.9.5",
89 | "require-dir": "~0.3.2",
90 | "run-sequence": "~2.2.0",
91 | "rxjs": "5.4.3",
92 | "systemjs": "^0.20.19",
93 | "tslint": "~5.7.0",
94 | "typescript": "~2.5.2",
95 | "yargs": "^9.0.1",
96 | "zone.js": "^0.8.17"
97 | },
98 | "devDependencies": {
99 | "browser-sync": "^2.18.13",
100 | "connect-history-api-fallback": "^1.3.0",
101 | "ts-node": "^3.3.0"
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/config/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | var gulpConfig = require('../gulp/config')();
3 |
4 | /**
5 | * List of npm packages that imported via `import` syntax
6 | */
7 | var dependencies = [
8 | '@angular',
9 | 'lodash',
10 | 'rxjs'
11 | ];
12 |
13 | var configuration = {
14 | basePath: '../../',
15 |
16 | frameworks: ['jasmine'],
17 | browsers: ['PhantomJS'],
18 | reporters: ['progress', 'coverage'],
19 |
20 | preprocessors: {},
21 |
22 | // Generate json used for remap-istanbul
23 | coverageReporter: {
24 | dir: 'report/',
25 | reporters: [
26 | { type: 'json', subdir: 'report-json' }
27 | ]
28 | },
29 |
30 | files: [
31 | 'node_modules/core-js/client/shim.min.js',
32 | 'node_modules/zone.js/dist/zone.js',
33 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
34 | 'node_modules/zone.js/dist/proxy.js',
35 | 'node_modules/zone.js/dist/sync-test.js',
36 | 'node_modules/zone.js/dist/jasmine-patch.js',
37 | 'node_modules/zone.js/dist/async-test.js',
38 | 'node_modules/zone.js/dist/fake-async-test.js',
39 | 'node_modules/systemjs/dist/system.src.js'
40 | ],
41 |
42 | // proxied base paths
43 | proxies: {
44 | // required for component assests fetched by Angular's compiler
45 | "/src/": "/base/src/",
46 | "/app/": "/base/src/app/",
47 | "/tmp/": "/base/src/tmp/",
48 | "/node_modules/": "/base/node_modules/"
49 | },
50 |
51 | port: 9876,
52 | colors: true,
53 | logLevel: config.LOG_INFO,
54 | autoWatch: true
55 | };
56 |
57 | configuration.preprocessors[gulpConfig.tmpApp + '**/!(*.spec)+(.js)'] = ['coverage'];
58 | configuration.preprocessors[gulpConfig.tmpApp + '**/*.js'] = ['sourcemap'];
59 | configuration.preprocessors[gulpConfig.tmpTest + '**/*.js'] = ['sourcemap'];
60 |
61 | var files = [
62 | gulpConfig.tmpTest + 'test-helpers/global/**/*.js',
63 | gulpConfig.src + 'systemjs.conf.js',
64 | 'config/test/karma-test-shim.js',
65 | createFilePattern(gulpConfig.tmpApp + '**/*.js', { included: false }),
66 | createFilePattern(gulpConfig.tmpTest + 'test-helpers/*.js', { included: false }),
67 | createFilePattern(gulpConfig.app + '**/*.html', { included: false }),
68 | createFilePattern(gulpConfig.tmpApp + '**/*.html', { included: false }),
69 | createFilePattern(gulpConfig.app + '**/*.css', { included: false }),
70 | createFilePattern(gulpConfig.app + '**/*.ts', { included: false, watched: false }),
71 | createFilePattern(gulpConfig.tmpApp + '**/*.js.map', { included: false, watched: false })
72 | ];
73 |
74 | configuration.files = configuration.files.concat(files);
75 |
76 | dependencies.forEach(function(key) {
77 | configuration.files.push({
78 | pattern: 'node_modules/' + key + '/**/!(*.spec)+(.js)',
79 | included: false,
80 | watched: false
81 | });
82 | });
83 |
84 | if (process.env.APPVEYOR) {
85 | configuration.browsers = ['IE'];
86 | configuration.singleRun = true;
87 | configuration.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough
88 | }
89 |
90 | config.set(configuration);
91 |
92 | // Helpers
93 | function createFilePattern(path, config) {
94 | config.pattern = path;
95 | return config;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/config/gulp/config.js:
--------------------------------------------------------------------------------
1 | var envConfig = require('./utils/env');
2 |
3 | module.exports = function () {
4 | var root = '',
5 | src = root + 'src/',
6 | config = root + 'config/',
7 | app = src + 'app/',
8 | test = src + 'test/',
9 | tmp = src + 'tmp/',
10 | tmpApp = tmp + 'app/',
11 | tmpTest = tmp + 'test/',
12 | testHelper = test + 'test-helpers/',
13 | e2e = root + 'e2e/',
14 | assets = src + 'assets/',
15 | assetsPath = {
16 | styles: assets + 'styles/',
17 | images: assets + 'images/',
18 | fonts: assets + 'fonts/'
19 | },
20 | index = src + 'index.html',
21 | tsFiles = [
22 | app + '**/!(*.spec)+(.ts)'
23 | ],
24 | tsTestFiles = {
25 | unit: [app + '**/*.spec.ts'],
26 | e2e: [e2e + '**/*.ts'],
27 | helper: [testHelper + '**/*.ts']
28 | },
29 | build = {
30 | path: 'build/',
31 | app: 'build/app/',
32 | fonts: 'build/fonts',
33 | assetPath: 'build/assets/',
34 | assets: {
35 | lib: {
36 | js: 'lib.js',
37 | css: 'lib.css'
38 | }
39 | }
40 | },
41 | report = {
42 | path: 'report/'
43 | };
44 |
45 | var e2eConfig = {
46 | seleniumTarget: 'http://127.0.0.1:3000'
47 | };
48 |
49 | var systemJs = {
50 | builder: {
51 | normalize: true,
52 | minify: true,
53 | mangle: true,
54 | runtime: false,
55 | globalDefs: {
56 | DEBUG: false,
57 | ENV: 'production'
58 | }
59 | }
60 | };
61 |
62 | var gulpConfig = {
63 | root: root,
64 | config: config,
65 | src: src,
66 | app: app,
67 | test: test,
68 | tmp: tmp,
69 | tmpApp: tmpApp,
70 | tmpTest: tmpTest,
71 | testHelper: testHelper,
72 | e2e: e2e,
73 | e2eConfig: e2eConfig,
74 | assets: assets,
75 | index: index,
76 | build: build,
77 | report: report,
78 | assetsPath: assetsPath,
79 | tsFiles: tsFiles,
80 | tsTestFiles: tsTestFiles,
81 | systemJs: systemJs
82 | };
83 |
84 | if (envConfig.ENV === envConfig.ENVS.DEV)
85 | {
86 | var historyApiFallback = require('connect-history-api-fallback');
87 | var browserSync = {
88 | dev: {
89 | port: 3000,
90 | injectChanges: false,
91 | server: {
92 | baseDir: './src/',
93 | middleware: [historyApiFallback()],
94 | routes: {
95 | "/node_modules": "node_modules",
96 | "/src": "src"
97 | }
98 | },
99 | files: [
100 | src + "index.html",
101 | src + "systemjs.conf.js",
102 | assetsPath.styles + "main.css",
103 | tmpApp + "**/*.js",
104 | app + "**/*.css",
105 | app + "**/*.html"
106 | ]
107 | },
108 | prod: {
109 | port: 3001,
110 | server: {
111 | baseDir: './' + build.path,
112 | middleware: [historyApiFallback()]
113 | }
114 | }
115 | };
116 |
117 | gulpConfig.browserSync = browserSync;
118 | }
119 |
120 | return gulpConfig;
121 | };
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Starter
2 |
3 | [](https://travis-ci.org/antonybudianto/angular-starter)
4 | [](https://codecov.io/gh/antonybudianto/angular-starter)
5 | [](https://david-dm.org/antonybudianto/angular-starter)
6 | [](https://david-dm.org/antonybudianto/angular-starter#info=devDependencies)
7 |
8 | > Live Production Build [Demo](https://antonybudianto.github.io/angular-starter/)
9 |
10 | > [Angular Webpack Starter](https://github.com/antonybudianto/angular-webpack-starter) is out! Featuring [AoT compilation](https://angular.io/docs/ts/latest/cookbook/aot-compiler.html), [Lazy loaded module](https://angular.io/docs/ts/latest/api/router/index/Routes-type-alias.html#!#sts=Lazy%20Loading), [Tree-shaking](https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80#.103r6vl29) with [Webpack 2](https://webpack.github.io/docs/roadmap.html#2)
11 |
12 | ## Introduction
13 | Welcome to Angular Starter!
14 | This starter contains almost everything you need to start developing [Angular 2](https://angular.io/).
15 |
16 | ### Why choose this starter?
17 | - Extensible via [ngstarter extensions](https://github.com/ngstarter)
18 | - Complete workflow from serve, lint, unit test, e2e test, to bundling
19 | - Support file-based and strong-typed [Environment Variables](https://github.com/antonybudianto/angular-starter/wiki/Environment-Variables)
20 | - 100% code coverage
21 | - 100% [CI/CD](https://github.com/antonybudianto/angular-starter/wiki/Continuous-Integration) pipeline ready
22 | - No global package installation
23 | - No module bundler coupling
24 |
25 | ### What's included?
26 | * [npm](https://www.npmjs.com/) for package manager
27 | * [TypeScript](http://www.typescriptlang.org/) for the base language
28 | * with [Typings](https://github.com/typings/typings) for TypeScript definition manager
29 | * [Gulp](http://gulpjs.com/) for workflow (from *serve*, *watch*, *compile*, *test* to *build*)
30 | * [Browsersync](https://www.browsersync.io/) for development server & reload capability
31 | * [SystemJS](https://github.com/systemjs/systemjs) for module loader
32 | * [Codelyzer](https://github.com/mgechev/codelyzer) for static code analyzer
33 | * [Karma](http://karma-runner.github.io/) for test-runner
34 | * [Jasmine](http://jasmine.github.io/) for test framework
35 | * [Istanbul](https://github.com/gotwarlost/istanbul) for test coverage
36 | * with [Remap Istanbul](https://github.com/SitePen/remap-istanbul) for remapping Javascript to TypeScript coverage
37 | * [SystemJS Builder](https://github.com/systemjs/builder) or [Webpack](https://webpack.github.io/) for module bundling in production
38 |
39 | Please visit the [wiki](https://github.com/antonybudianto/angular2-starter/wiki) for more details.
40 |
41 | ## Prerequisites
42 | You need to have [Node.js and npm](https://nodejs.org/en/)
43 | - Support Node v6.9 - latest
44 | - Support npm v3 - latest
45 |
46 | [Global Gulp CLI](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md) is not required, since you can map them to npm scripts, but a nice to have for development purpose.
47 |
48 | ## Installation
49 | Download the starter from [releases page](https://github.com/antonybudianto/angular-starter/releases)
50 |
51 | Go to the starter directory and install the packages:
52 | ```bash
53 | npm install
54 | ```
55 |
56 | ## Start
57 | Let's start up the server, run:
58 | ```bash
59 | npm start
60 | ```
61 |
62 | and done! The browser will popup and you can start trying Angular!
63 | Every changes to the file will refresh the browser automatically
64 | and it'll also compile your changed TypeScripts files to Javascript files.
65 |
66 | ## Testing
67 | This starter comes with testing gulp workflow
68 |
69 | ### Unit testing
70 | Just run
71 | ```bash
72 | npm test
73 | ```
74 | and it'll compile all TypeScript files, start Karma, then remap Istanbul coverage so that it shows TypeScript coverage, not the transpiled JavaScript coverage.
75 |
76 | 
77 |
78 | ### E2E testing
79 | Firstly start the server:
80 | ```bash
81 | npm start
82 | ```
83 | To begin testing, run:
84 | ```bash
85 | npm run e2e
86 | ```
87 | and it'll compile all E2E spec files in `/src/test/e2e/*.spec.ts`, boot up Selenium server then launches Chrome browser.
88 |
89 | ## Production
90 | > All build tasks will run the `gulp test`, the bundle will only be created if the test passed.
91 |
92 | > For more details, visit [Continuous Integration wiki](https://github.com/antonybudianto/angular-starter/wiki/Continuous-Integration)
93 |
94 | You can create production build by running:
95 | ```bash
96 | npm run build
97 | ```
98 | or you can create production build and then serve it using Browsersync by running:
99 | ```bash
100 | npm run serve-build
101 | ```
102 | The starter defaults to bundle using [SystemJS Builder extension](https://github.com/ngstarter/systemjs-extension).
103 | There is [Webpack extension](https://github.com/ngstarter/webpack-extension) available too, feel free to swap it as you like.
104 |
105 | ## Extension
106 | You can extend this starter with many extensions built by the community. Browse the extensions [here](https://github.com/ngstarter)
107 |
108 | ## Contributing
109 | Feel free to submit a PR if there are any issues or new features, please read [this](https://github.com/antonybudianto/angular-starter/wiki/Contributing) before
110 |
111 | ## Special thanks
112 | * For all contributors who have helped this starter improvement
113 | * John Papa for his awesome [angular-styleguide](https://github.com/johnpapa/angular-styleguide) and [Tour of Heroes](https://github.com/johnpapa/angular2-tour-of-heroes)
114 | * Julie Ralph for her [ng2-test-seed](https://github.com/juliemr/ng2-test-seed) which helped me a lot to get started with testing feature
115 | * Minko Gechev for his [angular2-seed](https://github.com/mgechev/angular2-seed) and [angular2-ngc-rollup-build](https://github.com/mgechev/angular2-ngc-rollup-build) which helped a lot
116 |
117 | ## License
118 | MIT
119 |
--------------------------------------------------------------------------------