diff options
| author | Alex Tatiyants <atatiyan@gmail.com> | 2016-01-03 17:17:48 -0800 | 
|---|---|---|
| committer | Alex Tatiyants <atatiyan@gmail.com> | 2016-01-03 17:17:48 -0800 | 
| commit | 5310ac7d8eb1838a6297117bc7f9fca70291f46a (patch) | |
| tree | 28f54b184cb85f04e6d6720dd03258f3728fedde /tools | |
initial commit
Diffstat (limited to 'tools')
38 files changed, 778 insertions, 0 deletions
| diff --git a/tools/config.ts b/tools/config.ts new file mode 100644 index 0000000..9c5559a --- /dev/null +++ b/tools/config.ts @@ -0,0 +1,101 @@ +import {readFileSync} from 'fs'; +import {argv} from 'yargs'; + + +// -------------- +// Configuration. +export const ENV                  = argv['env']         || 'dev'; +export const DEBUG                = argv['debug']       || false; +export const PORT                 = argv['port']        || 5555; +export const LIVE_RELOAD_PORT     = argv['reload-port'] || 4002; +export const DOCS_PORT            = argv['docs-port']   || 4003; +export const APP_BASE             = argv['base']        || '/'; + +export const APP_TITLE            = 'My Angular2 App'; + +export const APP_SRC              = 'app'; +export const ASSETS_SRC           = `${APP_SRC}/assets`; + +export const TOOLS_DIR            = 'tools'; +export const TMP_DIR              = 'tmp'; +export const TEST_DEST            = 'test'; +export const DOCS_DEST            = 'docs'; +export const APP_DEST             = `dist/${ENV}`; +export const ASSETS_DEST          = `${APP_DEST}/assets`; +export const BUNDLES_DEST         = `${APP_DEST}/bundles`; +export const CSS_DEST             = `${APP_DEST}/css`; +export const FONTS_DEST           = `${APP_DEST}/fonts`; +export const LIB_DEST             = `${APP_DEST}/lib`; +export const APP_ROOT             = ENV === 'dev' ? `${APP_BASE}${APP_DEST}/` : `${APP_BASE}`; +export const VERSION              = appVersion(); + +export const VERSION_NPM          = '2.14.7'; +export const VERSION_NODE         = '4.0.0'; + +// Declare NPM dependencies (Note that globs should not be injected). +export const NPM_DEPENDENCIES = [ +  { src: 'systemjs/dist/system-polyfills.js', dest: LIB_DEST }, + +  { src: 'es6-shim/es6-shim.min.js', inject: 'shims', dest: LIB_DEST }, +  { src: 'reflect-metadata/Reflect.js', inject: 'shims', dest: LIB_DEST }, +  { src: 'systemjs/dist/system.src.js', inject: 'shims', dest: LIB_DEST }, +  { src: 'angular2/bundles/angular2-polyfills.js', inject: 'shims', dest: LIB_DEST }, + +  // Faster dev page load +  { src: 'rxjs/bundles/Rx.min.js', inject: 'libs', dest: LIB_DEST }, +  { src: 'angular2/bundles/angular2.min.js', inject: 'libs', dest: LIB_DEST }, +  { src: 'angular2/bundles/router.js', inject: 'libs', dest: LIB_DEST }, // use router.min.js with alpha47 +  { src: 'angular2/bundles/http.min.js', inject: 'libs', dest: LIB_DEST }, + +  { src: 'lodash/index.js', inject: 'libs', dest: LIB_DEST }, +  { src: 'moment/moment.js', inject: 'libs', dest: LIB_DEST } +]; + +// Declare local files that needs to be injected +export const APP_ASSETS = [ +  { src: `${ASSETS_SRC}/css/styles.css`, inject: true, dest: CSS_DEST} +]; + +NPM_DEPENDENCIES +  .filter(d => !/\*/.test(d.src)) // Skip globs +  .forEach(d => d.src = require.resolve(d.src)); + +export const DEPENDENCIES = NPM_DEPENDENCIES.concat(APP_ASSETS); + + +// ---------------- +// SystemsJS Configuration. +const SYSTEM_CONFIG_DEV = { +  defaultJSExtensions: true, +  paths: { +    'bootstrap': `${APP_ROOT}bootstrap`, +    '*': `${APP_BASE}node_modules/*` +  } +}; + +const SYSTEM_CONFIG_PROD = { +  defaultJSExtensions: true, +  bundles: { +    'bundles/app': ['bootstrap'] +  } +}; + +export const SYSTEM_CONFIG = ENV === 'dev' ? SYSTEM_CONFIG_DEV : SYSTEM_CONFIG_PROD; + +// This is important to keep clean module names as 'module name == module uri'. +export const SYSTEM_CONFIG_BUILDER = { +  defaultJSExtensions: true, +  paths: { +    '*': `${TMP_DIR}/*`, +    'angular2/*': 'node_modules/angular2/*', +    'rxjs/*': 'node_modules/rxjs/*' +  } +}; + + +// -------------- +// Private. +function appVersion(): number|string { +  var pkg = JSON.parse(readFileSync('package.json').toString()); +  return pkg.version; +} diff --git a/tools/tasks/build.bundles.ts b/tools/tasks/build.bundles.ts new file mode 100644 index 0000000..52eb381 --- /dev/null +++ b/tools/tasks/build.bundles.ts @@ -0,0 +1,26 @@ +import {parallel} from 'async'; +import {join} from 'path'; +import * as Builder from 'systemjs-builder'; +import {BUNDLES_DEST, SYSTEM_CONFIG_BUILDER} from '../config'; + +const BUNDLE_OPTS = { +  minify: true, +  sourceMaps: true, +  format: 'cjs' +}; + +export = function bundles(gulp, plugins) { +  return function (done) { +    let builder = new Builder(SYSTEM_CONFIG_BUILDER); + +    parallel([ +      bundleApp +    ], () => done()); + +    function bundleApp(done) { +      builder.bundle( +        'bootstrap - angular2/*', +        join(BUNDLES_DEST, 'app.js'), BUNDLE_OPTS).then(done); +    } +  }; +}; diff --git a/tools/tasks/build.deps.ts b/tools/tasks/build.deps.ts new file mode 100644 index 0000000..071f4cd --- /dev/null +++ b/tools/tasks/build.deps.ts @@ -0,0 +1,20 @@ +import * as merge from 'merge-stream'; +import {DEPENDENCIES} from '../config'; + +export = function buildDepsProd(gulp, plugins) { +  return function () { +    let stream = merge(); + +    DEPENDENCIES.forEach(dep => { +      stream.add(addStream(dep)); +    }); + +    return stream; + +    function addStream(dep) { +      let stream = gulp.src(dep.src); +      stream.pipe(gulp.dest(dep.dest)); +      return stream; +    } +  }; +}; diff --git a/tools/tasks/build.docs.ts b/tools/tasks/build.docs.ts new file mode 100644 index 0000000..a464c67 --- /dev/null +++ b/tools/tasks/build.docs.ts @@ -0,0 +1,27 @@ +import {join} from 'path'; +import {APP_SRC, APP_TITLE, DOCS_DEST} from '../config'; + +export = function buildDocs(gulp, plugins, option) { +  return function() { + +    let src = [ +                join(APP_SRC, '**/*.ts'), +                '!' + join(APP_SRC, '**/*_spec.ts') +              ]; + +    return gulp.src(src) +      .pipe(plugins.typedoc({ +        // TypeScript options (see typescript docs) +        module: 'commonjs', +        target: 'es5', +        includeDeclarations: true, +        // Output options (see typedoc docs) +        out: DOCS_DEST, +        json: join(DOCS_DEST , 'data/docs.json' ), +        name: APP_TITLE, +        ignoreCompilerErrors: false, +        experimentalDecorators: true, +        version: true +      })); +    }; +} diff --git a/tools/tasks/build.fonts.dev.ts b/tools/tasks/build.fonts.dev.ts new file mode 100644 index 0000000..6aa0b92 --- /dev/null +++ b/tools/tasks/build.fonts.dev.ts @@ -0,0 +1,15 @@ +import {join} from 'path'; +import {APP_SRC, APP_DEST} from '../config'; + +export = function buildFontsDev(gulp, plugins) { +  return function () { +    return gulp.src([ +        join(APP_SRC, '**/*.eot'), +        join(APP_SRC, '**/*.ttf'), +        join(APP_SRC, '**/*.woff'), +        join(APP_SRC, '**/*.woff2'), +        join(APP_SRC, '**/*.otf') +      ]) +      .pipe(gulp.dest(APP_DEST)); +  }; +} diff --git a/tools/tasks/build.html_css.prod.ts b/tools/tasks/build.html_css.prod.ts new file mode 100644 index 0000000..93d0aa9 --- /dev/null +++ b/tools/tasks/build.html_css.prod.ts @@ -0,0 +1,24 @@ +import * as merge from 'merge-stream'; +import {join} from 'path'; +import {APP_SRC, TMP_DIR} from '../config'; + +// const HTML_MINIFIER_OPTS = { empty: true }; + +export = function buildJSDev(gulp, plugins) { +  return function () { + +    return merge(minifyHtml(), minifyCss()); + +    function minifyHtml() { +      return gulp.src(join(APP_SRC, '**/*.html')) +        // .pipe(plugins.minifyHtml(HTML_MINIFIER_OPTS)) +        .pipe(gulp.dest(TMP_DIR)); +    } + +    function minifyCss() { +      return gulp.src(join(APP_SRC, '**/*.css')) +        .pipe(plugins.minifyCss()) +        .pipe(gulp.dest(TMP_DIR)); +    } +  }; +}; diff --git a/tools/tasks/build.img.dev.ts b/tools/tasks/build.img.dev.ts new file mode 100644 index 0000000..28a7897 --- /dev/null +++ b/tools/tasks/build.img.dev.ts @@ -0,0 +1,14 @@ +import {join} from 'path'; +import {APP_SRC, APP_DEST} from '../config'; + +export = function buildImagesDev(gulp, plugins) { +  return function () { +    return gulp.src([ +        join(APP_SRC, '**/*.gif'), +        join(APP_SRC, '**/*.jpg'), +        join(APP_SRC, '**/*.png'), +        join(APP_SRC, '**/*.svg') +      ]) +      .pipe(gulp.dest(APP_DEST)); +  }; +} diff --git a/tools/tasks/build.index.ts b/tools/tasks/build.index.ts new file mode 100644 index 0000000..bbf98ee --- /dev/null +++ b/tools/tasks/build.index.ts @@ -0,0 +1,34 @@ +import {join, sep} from 'path'; +import {APP_SRC, APP_DEST, DEPENDENCIES, ENV} from '../config'; +import {transformPath, templateLocals} from '../utils'; + +export = function buildIndexDev(gulp, plugins) { +  return function () { +    return gulp.src(join(APP_SRC, 'index.html')) +      // NOTE: There might be a way to pipe in loop. +      .pipe(inject('shims')) +      .pipe(inject('libs')) +      .pipe(inject()) +      .pipe(plugins.template(templateLocals())) +      .pipe(gulp.dest(APP_DEST)); +  }; + + +  function inject(name?: string) { +    return plugins.inject(gulp.src(getInjectablesDependenciesRef(name), { read: false }), { +      name, +      transform: transformPath(plugins, 'dev') +    }); +  } + +  function getInjectablesDependenciesRef(name?: string) { +    return DEPENDENCIES +      .filter(dep => dep['inject'] && dep['inject'] === (name || true)) +      .map(mapPath); +  } + +  function mapPath(dep) { +    let prodPath = join(dep.dest, dep.src.split(sep).pop()); +    return ('prod' === ENV ? prodPath : dep.src ); +  } +}; diff --git a/tools/tasks/build.js.dev.ts b/tools/tasks/build.js.dev.ts new file mode 100644 index 0000000..dfe9539 --- /dev/null +++ b/tools/tasks/build.js.dev.ts @@ -0,0 +1,25 @@ +import {join} from 'path'; +import {APP_SRC, APP_DEST} from '../config'; +import {templateLocals, tsProjectFn} from '../utils'; + +export = function buildJSDev(gulp, plugins) { +  let tsProject = tsProjectFn(plugins); +  return function () { +    let src = [ +                join(APP_SRC, '**/*.ts'), +                '!' + join(APP_SRC, '**/*_spec.ts') +              ]; + +    let result = gulp.src(src) +      .pipe(plugins.plumber()) +      // Won't be required for non-production build after the change +      .pipe(plugins.inlineNg2Template({ base: APP_SRC })) +      .pipe(plugins.sourcemaps.init()) +      .pipe(plugins.typescript(tsProject)); + +    return result.js +      .pipe(plugins.sourcemaps.write()) +      .pipe(plugins.template(templateLocals())) +      .pipe(gulp.dest(APP_DEST)); +  }; +}; diff --git a/tools/tasks/build.js.prod.ts b/tools/tasks/build.js.prod.ts new file mode 100644 index 0000000..54ed21a --- /dev/null +++ b/tools/tasks/build.js.prod.ts @@ -0,0 +1,22 @@ +import {join} from 'path'; +import {APP_SRC, TMP_DIR} from '../config'; +import {templateLocals, tsProjectFn} from '../utils'; + +export = function buildJSDev(gulp, plugins) { +  return function () { +    let tsProject = tsProjectFn(plugins); +    let src = [ +                join(APP_SRC, '**/*.ts'), +                '!' + join(APP_SRC, '**/*_spec.ts') +              ]; + +    let result = gulp.src(src) +      .pipe(plugins.plumber()) +      .pipe(plugins.inlineNg2Template({ base: TMP_DIR })) +      .pipe(plugins.typescript(tsProject)); + +    return result.js +      .pipe(plugins.template(templateLocals())) +      .pipe(gulp.dest(TMP_DIR)); +  }; +}; diff --git a/tools/tasks/build.sass.dev.ts b/tools/tasks/build.sass.dev.ts new file mode 100644 index 0000000..a2127be --- /dev/null +++ b/tools/tasks/build.sass.dev.ts @@ -0,0 +1,22 @@ +import {join} from 'path'; +import {APP_SRC} from '../config'; + +export = function buildSassDev(gulp, plugins, option) { +    return function() { +        return gulp.src(join(APP_SRC, '**', '*.scss')) +            .pipe(plugins.plumber({ +                // this allows gulp not to crash on sass compilation errors +                errorHandler: function(error) { +                    console.log(error.message); +                    this.emit('end'); +                } +            })) +            .pipe(plugins.compass({ +                // config_file: './config.rb', +                style: 'compressed', +                css: 'app/assets/css', +                sass: join(APP_SRC, 'assets/sass'), +            })) +            .pipe(gulp.dest(join(APP_SRC, 'assets'))); +    }; +} diff --git a/tools/tasks/build.test.ts b/tools/tasks/build.test.ts new file mode 100644 index 0000000..3e089cd --- /dev/null +++ b/tools/tasks/build.test.ts @@ -0,0 +1,21 @@ +import {join} from 'path'; +import {APP_SRC, TEST_DEST} from '../config'; +import {tsProjectFn} from '../utils'; + +export = function buildTest(gulp, plugins) { +  return function () { +    let tsProject = tsProjectFn(plugins); +    let src = [ +                join(APP_SRC, '**/*.ts'), +                '!' + join(APP_SRC, 'bootstrap.ts') +              ]; + +    let result = gulp.src(src) +      .pipe(plugins.plumber()) +      .pipe(plugins.inlineNg2Template({ base: APP_SRC })) +      .pipe(plugins.typescript(tsProject)); + +    return result.js +      .pipe(gulp.dest(TEST_DEST)); +  }; +}; diff --git a/tools/tasks/check.versions.ts b/tools/tasks/check.versions.ts new file mode 100644 index 0000000..211d5ed --- /dev/null +++ b/tools/tasks/check.versions.ts @@ -0,0 +1,35 @@ +import {VERSION_NPM, VERSION_NODE} from '../config'; + +function reportError(message: string) { +  console.error(require('chalk').white.bgRed.bold(message)); +  process.exit(1); +} + +module.exports = function check(gulp, plugins) { +  return function () { +    let exec = require('child_process').exec; +    let semver = require('semver'); + +    exec('npm --version', +      function (error, stdout, stderr) { +        if (error !== null) { +          reportError('npm preinstall error: ' + error + stderr); +        } + +        if (!semver.gte(stdout, VERSION_NPM)) { +          reportError('NPM is not in required version! Required is ' + VERSION_NPM + ' and you\'re using ' + stdout); +        } +      }); + +    exec('node --version', +      function (error, stdout, stderr) { +        if (error !== null) { +          reportError('npm preinstall error: ' + error + stderr); +        } + +        if (!semver.gte(stdout, VERSION_NODE)) { +          reportError('NODE is not in required version! Required is ' + VERSION_NODE + ' and you\'re using ' + stdout); +        } +      }); +  }; +}; diff --git a/tools/tasks/clean.ts b/tools/tasks/clean.ts new file mode 100644 index 0000000..9f0ebf2 --- /dev/null +++ b/tools/tasks/clean.ts @@ -0,0 +1,34 @@ +import * as async from 'async'; +import * as del from 'del'; +import {APP_DEST, TEST_DEST, TMP_DIR} from '../config'; + +export = function clean(gulp, plugins, option) { +  return function (done) { + +    switch(option) { +      case 'all'    : cleanAll(done);     break; +      case 'dist'   : cleanDist(done);    break; +      case 'test'   : cleanTest(done);    break; +      case 'tmp'    : cleanTmp(done);     break; +      default: done(); +    } + +  }; +}; + +function cleanAll(done) { +  async.parallel([ +    cleanDist, +    cleanTest, +    cleanTmp +  ], done); +} +function cleanDist(done) { +  del(APP_DEST, done); +} +function cleanTest(done) { +  del(TEST_DEST, done); +} +function cleanTmp(done) { +  del(TMP_DIR, done); +} diff --git a/tools/tasks/karma.start.ts b/tools/tasks/karma.start.ts new file mode 100644 index 0000000..313aacd --- /dev/null +++ b/tools/tasks/karma.start.ts @@ -0,0 +1,11 @@ +import * as karma from 'karma'; +import {join} from 'path'; + +export = function karmaStart() { +  return function (done) { +    new (<any>karma).Server({ +      configFile: join(process.cwd(), 'karma.conf.js'), +      singleRun: true +    }).start(done); +  }; +}; diff --git a/tools/tasks/npm.ts b/tools/tasks/npm.ts new file mode 100644 index 0000000..2ab5e76 --- /dev/null +++ b/tools/tasks/npm.ts @@ -0,0 +1,5 @@ +export = function npm(gulp, plugins) { +  return plugins.shell.task([ +    'npm prune' +  ]); +}; diff --git a/tools/tasks/serve.docs.ts b/tools/tasks/serve.docs.ts new file mode 100644 index 0000000..2aa5f05 --- /dev/null +++ b/tools/tasks/serve.docs.ts @@ -0,0 +1,7 @@ +import {serveDocs} from '../utils'; + +export = function serverStart(gulp, plugins) { +  return function () { +    serveDocs(); +  }; +}; diff --git a/tools/tasks/server.start.ts b/tools/tasks/server.start.ts new file mode 100644 index 0000000..e733e92 --- /dev/null +++ b/tools/tasks/server.start.ts @@ -0,0 +1,7 @@ +import {serveSPA} from '../utils'; + +export = function serverStart(gulp, plugins) { +  return function () { +    serveSPA(); +  }; +}; diff --git a/tools/tasks/tsd.ts b/tools/tasks/tsd.ts new file mode 100644 index 0000000..bf38ad0 --- /dev/null +++ b/tools/tasks/tsd.ts @@ -0,0 +1,7 @@ +export = function tsd(gulp, plugins) { +  return plugins.shell.task([ +    'tsd reinstall --clean', +    'tsd link', +    'tsd rebundle' +  ]); +}; diff --git a/tools/tasks/tslint.ts b/tools/tasks/tslint.ts new file mode 100644 index 0000000..ccea264 --- /dev/null +++ b/tools/tasks/tslint.ts @@ -0,0 +1,21 @@ +import {join} from 'path'; +import {APP_SRC, TOOLS_DIR} from '../config'; + +export = function tslint(gulp, plugins) { +  return function () { +    let src = [ +                join(APP_SRC, '**/*.ts'), +                '!' + join(APP_SRC, '**/*.d.ts'), +                join(TOOLS_DIR, '**/*.ts'), +                '!' + join(TOOLS_DIR, '**/*.d.ts') +              ]; + +    return gulp.src(src) +      .pipe(plugins.tslint()) +      .pipe(plugins.tslint.report(plugins.tslintStylish, { +        emitError: false, +        sort: true, +        bell: true +      })); +  }; +}; diff --git a/tools/tasks/watch.dev.ts b/tools/tasks/watch.dev.ts new file mode 100644 index 0000000..bfa37a3 --- /dev/null +++ b/tools/tasks/watch.dev.ts @@ -0,0 +1,8 @@ +import {join} from 'path'; +import {APP_SRC} from '../config'; + +export = function watchDev(gulp, plugins) { +  return function () { +    plugins.watch(join(APP_SRC, '**/*'), () => gulp.start('build.dev')); +  }; +}; diff --git a/tools/tasks/watch.serve.ts b/tools/tasks/watch.serve.ts new file mode 100644 index 0000000..2bb18f1 --- /dev/null +++ b/tools/tasks/watch.serve.ts @@ -0,0 +1,12 @@ +import * as runSequence from 'run-sequence'; +import {join} from 'path'; +import {APP_SRC} from '../config'; +import {notifyLiveReload} from '../utils'; + +export = function watchServe(gulp, plugins) { +  return function () { +    plugins.watch(join(APP_SRC, '**'), e => +      runSequence('build.dev', () => notifyLiveReload(e)) +    ); +  }; +}; diff --git a/tools/tasks/watch.test.ts b/tools/tasks/watch.test.ts new file mode 100644 index 0000000..2a8b55b --- /dev/null +++ b/tools/tasks/watch.test.ts @@ -0,0 +1,8 @@ +import {join} from 'path'; +import {APP_SRC} from '../config'; + +export = function watchTest(gulp, plugins) { +  return function () { +    plugins.watch(join(APP_SRC, '**/*.ts'), () => gulp.start('build.test')); +  }; +}; diff --git a/tools/typings/connect-livereload.d.ts b/tools/typings/connect-livereload.d.ts new file mode 100644 index 0000000..1b1ef21 --- /dev/null +++ b/tools/typings/connect-livereload.d.ts @@ -0,0 +1,5 @@ +declare module 'connect-livereload' { +  function connectLivereload(options?: any): any; +  module connectLivereload {} +  export = connectLivereload; +} diff --git a/tools/typings/gulp-load-plugins.d.ts b/tools/typings/gulp-load-plugins.d.ts new file mode 100644 index 0000000..809c305 --- /dev/null +++ b/tools/typings/gulp-load-plugins.d.ts @@ -0,0 +1,42 @@ +// Type definitions for gulp-load-plugins +// Project: https://github.com/jackfranklin/gulp-load-plugins +// Definitions by: Joe Skeen <http://github.com/joeskeen> +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +// Does not support ES2015 import (import * as open from 'open'). + +/** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */ +declare module 'gulp-load-plugins' { + +	interface IOptions { +		/** the glob(s) to search for, default ['gulp-*', 'gulp.*'] */ +		pattern?: string[]; +		/** where to find the plugins, searched up from process.cwd(), default 'package.json' */ +		config?: string; +		/** which keys in the config to look within, default ['dependencies', 'devDependencies', 'peerDependencies'] */ +		scope?: string[]; +		/** what to remove from the name of the module when adding it to the context, default /^gulp(-|\.)/ */ +		replaceString?: RegExp; +		/** if true, transforms hyphenated plugin names to camel case, default true */ +		camelize?: boolean; +		/** whether the plugins should be lazy loaded on demand, default true */ +		lazy?: boolean; +		/** a mapping of plugins to rename, the key being the NPM name of the package, and the value being an alias you define */ +		rename?: IPluginNameMappings; +	} + +	interface IPluginNameMappings { +		[npmPackageName: string]: string; +	} + +	/** Loads in any gulp plugins and attaches them to an object, freeing you up from having to manually require each gulp plugin. */ +	function gulpLoadPlugins<T extends IGulpPlugins>(options?: IOptions): T; +	module gulpLoadPlugins {} +	export = gulpLoadPlugins; +} + +/** + * Extend this interface to use Gulp plugins in your gulpfile.js + */ +interface IGulpPlugins { +} diff --git a/tools/typings/karma.d.ts b/tools/typings/karma.d.ts new file mode 100644 index 0000000..5d2cd42 --- /dev/null +++ b/tools/typings/karma.d.ts @@ -0,0 +1,12 @@ +// Use this minimalistic definition file as bluebird dependency +// generate a lot of errors. + +declare module 'karma' { +  var karma: IKarma; +  export = karma; +  interface IKarma { +    server: { +      start(options: any, callback: Function): void +    }; +  } +} diff --git a/tools/typings/merge-stream.d.ts b/tools/typings/merge-stream.d.ts new file mode 100644 index 0000000..7425d35 --- /dev/null +++ b/tools/typings/merge-stream.d.ts @@ -0,0 +1,8 @@ +declare module 'merge-stream' { +  function mergeStream(...streams: NodeJS.ReadWriteStream[]): MergeStream; +  interface MergeStream extends NodeJS.ReadWriteStream { +    add(stream: NodeJS.ReadWriteStream): MergeStream; +  } +  module mergeStream {} +  export = mergeStream; +}
\ No newline at end of file diff --git a/tools/typings/open.d.ts b/tools/typings/open.d.ts new file mode 100644 index 0000000..89d4b76 --- /dev/null +++ b/tools/typings/open.d.ts @@ -0,0 +1,8 @@ +// https://github.com/borisyankov/DefinitelyTyped/tree/master/open +// Does not support ES2015 import (import * as open from 'open'). + +declare module 'open' { +	function open(target: string, app?: string): void; +  module open {} +	export = open; +} diff --git a/tools/typings/run-sequence.d.ts b/tools/typings/run-sequence.d.ts new file mode 100644 index 0000000..c4fada3 --- /dev/null +++ b/tools/typings/run-sequence.d.ts @@ -0,0 +1,5 @@ +declare module 'run-sequence' { +  function runSequence(...args: any[]): void; +  module runSequence {} +  export = runSequence; +} diff --git a/tools/typings/slash.d.ts b/tools/typings/slash.d.ts new file mode 100644 index 0000000..10ec0b5 --- /dev/null +++ b/tools/typings/slash.d.ts @@ -0,0 +1,5 @@ +declare module 'slash' { +  function slash(path: string): string; +  module slash {} +  export = slash; +} diff --git a/tools/typings/systemjs-builder.d.ts b/tools/typings/systemjs-builder.d.ts new file mode 100644 index 0000000..4644816 --- /dev/null +++ b/tools/typings/systemjs-builder.d.ts @@ -0,0 +1,10 @@ +declare module 'systemjs-builder' { +  class Builder { +    constructor(configObject?: any, baseUrl?: string, configPath?: string); +    bundle(source: string, target: string, options?: any): Promise<any>; +    buildStatic(source: string, target: string, options?: any): Promise<any>; +  } + +  module Builder {} +  export = Builder; +} diff --git a/tools/typings/tiny-lr.d.ts b/tools/typings/tiny-lr.d.ts new file mode 100644 index 0000000..8a492d5 --- /dev/null +++ b/tools/typings/tiny-lr.d.ts @@ -0,0 +1,10 @@ +declare module 'tiny-lr' { +  function tinylr(): ITinylr; +  module tinylr {} +  export = tinylr; + +  interface ITinylr { +    changed(options: any): void; +    listen(port: number): void; +  } +} diff --git a/tools/typings/yargs.d.ts b/tools/typings/yargs.d.ts new file mode 100644 index 0000000..8351942 --- /dev/null +++ b/tools/typings/yargs.d.ts @@ -0,0 +1,9 @@ +declare module 'yargs' { +  var yargs: IYargs; +  export = yargs; + +  // Minimalistic but serves the usage in the seed. +  interface IYargs { +    argv: any; +  } +} diff --git a/tools/utils.ts b/tools/utils.ts new file mode 100644 index 0000000..81e3bb2 --- /dev/null +++ b/tools/utils.ts @@ -0,0 +1,11 @@ +export * from './utils/template-injectables'; +export * from './utils/template-locals'; +export * from './utils/server'; +export * from './utils/tasks_tools'; + + +export function tsProjectFn(plugins) { +  return plugins.typescript.createProject('tsconfig.json', { +    typescript: require('typescript') +  }); +} diff --git a/tools/utils/server.ts b/tools/utils/server.ts new file mode 100644 index 0000000..9e185d3 --- /dev/null +++ b/tools/utils/server.ts @@ -0,0 +1,45 @@ +import * as connectLivereload from 'connect-livereload'; +import * as express from 'express'; +import * as tinylrFn from 'tiny-lr'; +import * as openResource from 'open'; +import * as serveStatic from 'serve-static'; +import {resolve} from 'path'; +import {APP_BASE, APP_DEST, DOCS_DEST, LIVE_RELOAD_PORT, DOCS_PORT, PORT} from '../config'; + +let tinylr = tinylrFn(); + + +export function serveSPA() { +  let server = express(); +  tinylr.listen(LIVE_RELOAD_PORT); + +  server.use( +    APP_BASE, +    connectLivereload({ port: LIVE_RELOAD_PORT }), +    express.static(process.cwd()) +  ); + +  server.listen(PORT, () => +    openResource('http://localhost:' + PORT + APP_BASE + APP_DEST) +  ); +} + +export function notifyLiveReload(e) { +  let fileName = e.path; +  tinylr.changed({ +    body: { files: [fileName] } +  }); +} + +export function serveDocs() { +  let server = express(); + +   server.use( +    APP_BASE, +    serveStatic(resolve(process.cwd(), DOCS_DEST)) +  ); + +   server.listen(DOCS_PORT, () => +    openResource('http://localhost:' + DOCS_PORT + APP_BASE) +  ); +} diff --git a/tools/utils/tasks_tools.ts b/tools/utils/tasks_tools.ts new file mode 100644 index 0000000..af1a069 --- /dev/null +++ b/tools/utils/tasks_tools.ts @@ -0,0 +1,64 @@ +import * as gulp from 'gulp'; +import * as util from 'gulp-util'; +import * as chalk from 'chalk'; +import * as gulpLoadPlugins from 'gulp-load-plugins'; +import * as _runSequence from 'run-sequence'; +import {readdirSync, existsSync, lstatSync} from 'fs'; +import {join} from 'path'; +import {TOOLS_DIR} from '../config'; + +const TASKS_PATH = join(TOOLS_DIR, 'tasks'); + +// NOTE: Remove if no issues with runSequence function below. +// export function loadTasks(): void { +//   scanDir(TASKS_PATH, (taskname) => registerTask(taskname)); +// } + +export function task(taskname: string, option?: string) { +  util.log('Loading task', chalk.yellow(taskname, option || '')); +  return require(join('..', 'tasks', taskname))(gulp, gulpLoadPlugins(), option); +} + +export function runSequence(...sequence: any[]) { +  let tasks = []; +  let _sequence = sequence.slice(0); +  sequence.pop(); + +  scanDir(TASKS_PATH, taskname => tasks.push(taskname)); + +  sequence.forEach(task => { +    if (tasks.indexOf(task) > -1) { registerTask(task); } +  }); + +  return _runSequence(..._sequence); +} + +// ---------- +// Private. + +function registerTask(taskname: string, filename?: string, option: string = ''): void { +  gulp.task(taskname, task(filename || taskname, option)); +} + +// TODO: add recursive lookup ? or enforce pattern file + folder (ie ./tools/utils & ./tools/utils.ts ) +function scanDir(root: string, cb: (taskname: string) => void) { +  if (!existsSync(root)) return; + +  walk(root); + +  function walk(path) { +    let files = readdirSync(path); +    for (let i = 0; i < files.length; i += 1) { +      let file = files[i]; +      let curPath = join(path, file); +      // if (lstatSync(curPath).isDirectory()) { // recurse +      //   path = file; +      //   walk(curPath); +      // } +      if (lstatSync(curPath).isFile() && /\.ts$/.test(file)) { +        let taskname = file.replace(/(\.ts)/, ''); +        cb(taskname); +      } +    } +  } +} diff --git a/tools/utils/template-injectables.ts b/tools/utils/template-injectables.ts new file mode 100644 index 0000000..83ac315 --- /dev/null +++ b/tools/utils/template-injectables.ts @@ -0,0 +1,25 @@ +import * as slash from 'slash'; +import {join} from 'path'; +import {APP_BASE, APP_DEST, ENV} from '../config'; + +let injectables: string[] = []; + +export function injectableAssetsRef() { +  return injectables; +} + +export function registerInjectableAssetsRef(paths: string[], target: string = '') { +  injectables = injectables.concat( +    paths +      .filter(path => !/(\.map)$/.test(path)) +      .map(path => join(target, slash(path).split('/').pop())) +  ); +} + +export function transformPath(plugins, env) { +  return function (filepath) { +    filepath = ENV === 'prod' ? filepath.replace(`/${APP_DEST}`, '') : filepath; +    arguments[0] = join(APP_BASE, filepath); +    return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments)); +  }; +} diff --git a/tools/utils/template-locals.ts b/tools/utils/template-locals.ts new file mode 100644 index 0000000..be6b669 --- /dev/null +++ b/tools/utils/template-locals.ts @@ -0,0 +1,13 @@ +import {APP_BASE, APP_DEST, APP_ROOT, APP_TITLE, SYSTEM_CONFIG, VERSION} from '../config'; + +// TODO: Add an interface to register more template locals. +export function templateLocals() { +  return { +    APP_BASE, +    APP_DEST, +    APP_ROOT, +    APP_TITLE, +    SYSTEM_CONFIG, +    VERSION +  }; +} | 
