diff --git a/DEVELOPER.md b/DEVELOPER.md index f13c0efda386..aa162be51335 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -249,12 +249,7 @@ Your life will be easier if you include the formatter in your standard workflow. likely forget to check the formatting, and waste time waiting for a build on Travis that fails due to some whitespace difference. -* Install clang-format with `npm install -g clang-format`. -* Use `clang-format -i [file name]` to format a file (or multiple). - Note that `clang-format` tries to load a `clang-format` node module close to the sources being - formatted, or from the `$CWD`, and only then uses the globally installed one - so the version used - should automatically match the one required by the project. - Use `clang-format -version` in case you get confused. +* Use `$(npm bin)/clang-format -i [file name]` to format a file (or multiple). * Use `gulp enforce-format` to check if your code is `clang-format` clean. This also gives you a command line to format your code. * `clang-format` also includes a git hook, run `git clang-format` to format all files you @@ -276,7 +271,7 @@ to some whitespace difference. - Synchronize files after execution: checked - Open console: not checked - Show in: Editor menu - - Program: [path to clang-format, try `$ echo $(npm config get prefix)/bin/clang-format`] + - Program: `$ProjectFileDir$/node_modules/.bin/clang-format` - Parameters: `-i -style=file $FilePath$` - Working directory: `$ProjectFileDir$` * `clang-format` integrations are also available for many popular editors (`vim`, `emacs`, diff --git a/gulpfile.js b/gulpfile.js index 07b72c8b4ca5..d1fafbbd4272 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -46,10 +46,36 @@ var dartSdk = require('./tools/build/dart'); var browserProvidersConf = require('./browser-providers.conf.js'); var os = require('os'); -require('./tools/check-environment')({ - requiredNpmVersion: '>=2.14.7', - requiredNodeVersion: '>=4.2.1' -}); +require('./tools/check-environment')( + {requiredNpmVersion: '>=2.14.7', requiredNodeVersion: '>=4.2.1'}); + +var cliArgs = minimist(process.argv.slice(2)); + +if (cliArgs.projects) { + // normalize for analytics + cliArgs.projects.split(',').sort().join(','); +} + +// --projects=angular2,angular2_material => {angular2: true, angular2_material: true} +var allProjects = + 'angular1_router,angular2,angular2_material,benchmarks,benchmarks_external,benchpress,playground'; +var cliArgsProjects = (cliArgs.projects || allProjects) + .split(',') + .reduce((map, projectName) => { + map[projectName] = true; + return map; + }, {}); + +function printModulesWarning() { + if (!cliArgs.projects && !process.env.CI) { + // if users didn't specify projects to build, tell them why and how they should + console.warn( + "Pro Tip: Did you know that you can speed up your build by specifying project name(s)?"); + console.warn(" It's like pressing the turbo button in the old days, but better!"); + console.warn(" Examples: --project=angular2 or --project=angular2,angular2_material"); + } +} + // Make it easy to quiet down portions of the build. // --logs=all -> log everything (This is the default) @@ -59,9 +85,7 @@ require('./tools/check-environment')({ // Not all commands support optional logging, feel free // to add support by adding a new key to this list, // and toggling output from the command based on it. -var logs = { - dartfmt: shouldLog('dartfmt') -}; +var logs = {dartfmt: shouldLog('dartfmt')}; // dynamic require in build.tools so we can bootstrap TypeScript compilation function throwToolsBuildMissingError() { @@ -78,7 +102,7 @@ var angularBuilder = { function sequenceComplete(done) { - return function (err) { + return function(err) { if (err) { var error = new Error('build sequence failed'); error.showStack = false; @@ -118,14 +142,8 @@ var CONFIG = { dest: { js: { all: 'dist/js', - dev: { - es6: 'dist/js/dev/es6', - es5: 'dist/js/dev/es5' - }, - prod: { - es6: 'dist/js/prod/es6', - es5: 'dist/js/prod/es5' - }, + dev: {es6: 'dist/js/dev/es6', es5: 'dist/js/dev/es5'}, + prod: {es6: 'dist/js/prod/es6', es5: 'dist/js/prod/es5'}, cjs: 'dist/js/cjs', dart2js: 'dist/js/dart2js' }, @@ -139,81 +157,59 @@ var CONFIG = { var BENCHPRESS_BUNDLE_CONFIG = { entries: ['./dist/js/cjs/benchpress/index.js'], packageJson: './dist/js/cjs/benchpress/package.json', - includes: [ - 'angular2' - ], - excludes: [ - 'reflect-metadata', - 'selenium-webdriver', - 'zone.js' - ], - ignore: [ - '@reactivex/rxjs' - ], + includes: ['angular2'], + excludes: ['reflect-metadata', 'selenium-webdriver', 'zone.js'], + ignore: ['@reactivex/rxjs'], dest: CONFIG.dest.benchpress_bundle }; // ------------ // clean -gulp.task('build/clean.tools', function() { - del(path.join('dist', 'tools')); -}); +gulp.task('build/clean.tools', function() { del(path.join('dist', 'tools')); }); -gulp.task('build/clean.js', function(done) { - del(CONFIG.dest.js.all, done); -}); +gulp.task('build/clean.js', function(done) { del(CONFIG.dest.js.all, done); }); -gulp.task('build/clean.dart', function(done) { - del(CONFIG.dest.dart, done); -}); +gulp.task('build/clean.dart', function(done) { del(CONFIG.dest.dart, done); }); -gulp.task('build/clean.docs', function(done) { - del(CONFIG.dest.docs, done); -}); +gulp.task('build/clean.docs', function(done) { del(CONFIG.dest.docs, done); }); -gulp.task('build/clean.docs_angular_io', function(done) { - del(CONFIG.dest.docs_angular_io, done); -}); +gulp.task('build/clean.docs_angular_io', + function(done) { del(CONFIG.dest.docs_angular_io, done); }); -gulp.task('build/clean.benchpress.bundle', function(done) { - del(CONFIG.dest.benchpress_bundle, done); -}); +gulp.task('build/clean.benchpress.bundle', + function(done) { del(CONFIG.dest.benchpress_bundle, done); }); // ------------ // transpile -gulp.task('build/tree.dart', ['build/clean.dart', 'build.tools'], function(done) { - runSequence('!build/tree.dart', sequenceComplete(done)); -}); +gulp.task('build/tree.dart', ['build/clean.dart', 'build.tools'], + function(done) { runSequence('!build/tree.dart', sequenceComplete(done)); }); -gulp.task('!build/tree.dart', function() { - return angularBuilder.rebuildDartTree(); -}); +gulp.task('!build/tree.dart', + function() { return angularBuilder.rebuildDartTree(cliArgsProjects); }); // ------------ // pubspec // Run a top-level `pub get` for this project. -gulp.task('pubget.dart', pubget.dir(gulp, gulpPlugins, { dir: '.', command: DART_SDK.PUB })); +gulp.task('pubget.dart', pubget.dir(gulp, gulpPlugins, {dir: '.', command: DART_SDK.PUB})); // Run `pub get` only on the angular2 dir of CONFIG.dest.dart -gulp.task('!build/pubget.angular2.dart', pubget.dir(gulp, gulpPlugins, { - dir: path.join(CONFIG.dest.dart, 'angular2'), - command: DART_SDK.PUB -})); +gulp.task('!build/pubget.angular2.dart', + pubget.dir(gulp, gulpPlugins, + {dir: path.join(CONFIG.dest.dart, 'angular2'), command: DART_SDK.PUB})); // Run `pub get` over CONFIG.dest.dart -gulp.task('build/pubspec.dart', pubget.subDir(gulp, gulpPlugins, { - dir: CONFIG.dest.dart, - command: DART_SDK.PUB -})); +gulp.task('build/pubspec.dart', + pubget.subDir(gulp, gulpPlugins, {dir: CONFIG.dest.dart, command: DART_SDK.PUB})); // This is a hacky way to work around dart's pub that creates `packages` symlink in every directory -// that contains a dart file with the main method. For our tests this means that every test subfolder +// that contains a dart file with the main method. For our tests this means that every test +// subfolder // has a link to the root `packages` directory which causes Karma to sift through 80k files during // each `karma run` invocation. // @@ -227,50 +223,43 @@ gulp.task('!build/remove-pub-symlinks', function(done) { return; } - exec('find dist/dart/angular2/test/ -name packages | xargs rm -r', function (error, stdout, stderr) { - if (error) { - done(stderr); - return; - } - done(); - }); + exec('find dist/dart/angular2/test/ -name packages | xargs rm -r', + function(error, stdout, stderr) { + if (error) { + done(stderr); + return; + } + done(); + }); }); // ------------ // dartanalyzer -gulp.task('build/analyze.dart', dartanalyzer(gulp, gulpPlugins, { - dest: CONFIG.dest.dart, - command: DART_SDK.ANALYZER -})); +gulp.task('build/analyze.dart', + dartanalyzer(gulp, gulpPlugins, {dest: CONFIG.dest.dart, command: DART_SDK.ANALYZER})); -gulp.task('build/analyze.ddc.dart', dartanalyzer(gulp, gulpPlugins, { - dest: CONFIG.dest.dart, - command: DART_SDK.ANALYZER, - use_ddc: true -})); +gulp.task('build/analyze.ddc.dart', + dartanalyzer(gulp, gulpPlugins, + {dest: CONFIG.dest.dart, command: DART_SDK.ANALYZER, use_ddc: true})); -gulp.task('build/check.apidocs.dart', dartapidocs(gulp, gulpPlugins, { - dest: CONFIG.dest.dart, - output: os.tmpdir(), - command: DART_SDK.DARTDOCGEN -})); +gulp.task('build/check.apidocs.dart', + dartapidocs(gulp, gulpPlugins, + {dest: CONFIG.dest.dart, output: os.tmpdir(), command: DART_SDK.DARTDOCGEN})); // ------------ // pubbuild // WARNING: this task is very slow (~15m as of July 2015) -gulp.task('build/pubbuild.dart', pubbuild(gulp, gulpPlugins, { - src: CONFIG.dest.dart, - dest: CONFIG.dest.js.dart2js, - command: DART_SDK.PUB -})); +gulp.task('build/pubbuild.dart', + pubbuild(gulp, gulpPlugins, + {src: CONFIG.dest.dart, dest: CONFIG.dest.js.dart2js, command: DART_SDK.PUB})); // ------------ // formatting function doCheckFormat() { - return gulp.src(['modules/**/*.ts', 'tools/**/*.ts', '!**/typings/**/*.d.ts']) + return gulp.src(['modules/**/*.ts', 'tools/**/*.ts', '!**/typings/**/*.d.ts', 'gulpfile.js']) .pipe(gulpFormat.checkFormat('file', clangFormat)); } @@ -312,14 +301,12 @@ gulp.task('lint', ['build.tools'], function() { // ------------ // check circular dependencies in Node.js context -gulp.task('build/checkCircularDependencies', function (done) { +gulp.task('build/checkCircularDependencies', function(done) { var dependencyObject = madge(CONFIG.dest.js.dev.es6, { format: 'es6', paths: [CONFIG.dest.js.dev.es6], extensions: ['.js'], - onParseFile: function(data) { - data.src = data.src.replace(/import \* as/g, "//import * as"); - } + onParseFile: function(data) { data.src = data.src.replace(/import \* as/g, "//import * as"); } }); var circularDependencies = dependencyObject.circular().getArray(); if (circularDependencies.length > 0) { @@ -330,24 +317,15 @@ gulp.task('build/checkCircularDependencies', function (done) { }); function jsServeDev() { - return jsserve(gulp, gulpPlugins, { - path: CONFIG.dest.js.dev.es5, - port: 8000 - })(); + return jsserve(gulp, gulpPlugins, {path: CONFIG.dest.js.dev.es5, port: 8000})(); } function jsServeProd() { - return jsserve(gulp, gulpPlugins, { - path: CONFIG.dest.js.prod.es5, - port: 8001 - })(); + return jsserve(gulp, gulpPlugins, {path: CONFIG.dest.js.prod.es5, port: 8001})(); } function jsServeDartJs() { - return jsserve(gulp, gulpPlugins, { - path: CONFIG.dest.js.dart2js, - port: 8002 - })(); + return jsserve(gulp, gulpPlugins, {path: CONFIG.dest.js.dart2js, port: 8002})(); } function proxyServeDart() { @@ -364,56 +342,55 @@ function proxyServeDart() { // ------------------ // web servers gulp.task('serve.js.dev', ['build.js'], function(neverDone) { - watch('modules/**', { ignoreInitial: true }, '!broccoli.js.dev'); + watch('modules/**', {ignoreInitial: true}, '!broccoli.js.dev'); jsServeDev(); }); gulp.task('serve.js.prod', jsServeProd); -gulp.task('serve.e2e.dev', ['build.js.dev', 'build.js.cjs', 'build.css.material'], function(neverDone) { - watch('modules/**', { ignoreInitial: true }, ['!broccoli.js.dev', '!build.js.cjs']); - jsServeDev(); -}); +gulp.task('serve.e2e.dev', ['build.js.dev', 'build.js.cjs', 'build.css.material'], + function(neverDone) { + watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.dev', '!build.js.cjs']); + jsServeDev(); + }); -gulp.task('serve.e2e.prod', ['build.js.prod', 'build.js.cjs', 'build.css.material'], function(neverDone) { - watch('modules/**', { ignoreInitial: true }, ['!broccoli.js.prod', '!build.js.cjs']); - jsServeProd(); -}); +gulp.task('serve.e2e.prod', ['build.js.prod', 'build.js.cjs', 'build.css.material'], + function(neverDone) { + watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.prod', '!build.js.cjs']); + jsServeProd(); + }); gulp.task('serve.js.dart2js', jsServeDartJs); gulp.task('!proxyServeDart', proxyServeDart); gulp.task('serve.dart', function(done) { - runSequence([ - '!proxyServeDart', - 'serve/playground.dart', - 'serve/benchmarks.dart', - 'serve/benchmarks_external.dart' - ], done); -}); - -gulp.task('serve/playground.dart', pubserve(gulp, gulpPlugins, { - command: DART_SDK.PUB, - path: CONFIG.dest.dart + '/playground', - port: 8004 -})); - -gulp.task('serve/benchmarks.dart', pubserve(gulp, gulpPlugins, { - command: DART_SDK.PUB, - path: CONFIG.dest.dart + '/benchmarks', - port: 8006 -})); - -gulp.task('serve/benchmarks_external.dart', pubserve(gulp, gulpPlugins, { - command: DART_SDK.PUB, - path: CONFIG.dest.dart + '/benchmarks_external', - port: 8008 -})); + runSequence( + [ + '!proxyServeDart', + 'serve/playground.dart', + 'serve/benchmarks.dart', + 'serve/benchmarks_external.dart' + ], + done); +}); + +gulp.task('serve/playground.dart', + pubserve(gulp, gulpPlugins, + {command: DART_SDK.PUB, path: CONFIG.dest.dart + '/playground', port: 8004})); + +gulp.task('serve/benchmarks.dart', + pubserve(gulp, gulpPlugins, + {command: DART_SDK.PUB, path: CONFIG.dest.dart + '/benchmarks', port: 8006})); + +gulp.task( + 'serve/benchmarks_external.dart', + pubserve(gulp, gulpPlugins, + {command: DART_SDK.PUB, path: CONFIG.dest.dart + '/benchmarks_external', port: 8008})); gulp.task('serve.e2e.dart', ['build.js.cjs'], function(neverDone) { // Note: we are not using build.dart as the dart analyzer takes too long... - watch('modules/**', { ignoreInitial: true }, ['!build/tree.dart', '!build.js.cjs']); + watch('modules/**', {ignoreInitial: true}, ['!build/tree.dart', '!build.js.cjs']); runSequence('build/packages.dart', 'build/pubspec.dart', 'build.dart.material.css', 'serve.dart'); }); @@ -442,9 +419,7 @@ gulp.task('test.dart', function(done) { sequenceComplete(done)); }); -gulp.task('versions.dart', function() { - dartSdk.logVersion(DART_SDK); -}); +gulp.task('versions.dart', function() { dartSdk.logVersion(DART_SDK); }); // Reuse the Travis scripts // TODO: rename test_*.sh to test_all_*.sh @@ -456,26 +431,31 @@ gulp.task('test.all.dart', shell.task(['./scripts/ci/test_dart.sh'])); // HTML DOM APIs. function getBrowsersFromCLI(provider) { var isProvider = false; - var args = minimist(process.argv.slice(2)); - var rawInput = args.browsers ? args.browsers : 'DartiumWithWebPlatform'; + var rawInput = cliArgs.browsers ? cliArgs.browsers : 'DartiumWithWebPlatform'; var inputList = rawInput.replace(' ', '').split(','); var outputList = []; for (var i = 0; i < inputList.length; i++) { var input = inputList[i]; var karmaChromeLauncher = require('karma-chrome-launcher'); - if (browserProvidersConf.customLaunchers.hasOwnProperty(input) || karmaChromeLauncher.hasOwnProperty("launcher:" + input)) { - // In case of non-sauce browsers, or browsers defined in karma-chrome-launcher (Chrome, ChromeCanary and Dartium): + if (browserProvidersConf.customLaunchers.hasOwnProperty(input) || + karmaChromeLauncher.hasOwnProperty("launcher:" + input)) { + // In case of non-sauce browsers, or browsers defined in karma-chrome-launcher (Chrome, + // ChromeCanary and Dartium): // overrides everything, ignoring other options outputList = [input]; isProvider = false; break; - } else if (provider && browserProvidersConf.customLaunchers.hasOwnProperty(provider + "_" + input.toUpperCase())) { + } else if (provider && + browserProvidersConf.customLaunchers.hasOwnProperty(provider + "_" + + input.toUpperCase())) { isProvider = true; outputList.push(provider + "_" + input.toUpperCase()); - } else if (provider && provider == 'SL' && browserProvidersConf.sauceAliases.hasOwnProperty(input.toUpperCase())) { + } else if (provider && provider == 'SL' && + browserProvidersConf.sauceAliases.hasOwnProperty(input.toUpperCase())) { outputList = outputList.concat(browserProvidersConf.sauceAliases[input.toUpperCase()]); isProvider = true; - } else if (provider && provider == 'BS' && browserProvidersConf.browserstackAliases.hasOwnProperty(input.toUpperCase())) { + } else if (provider && provider == 'BS' && + browserProvidersConf.browserstackAliases.hasOwnProperty(input.toUpperCase())) { outputList = outputList.concat(browserProvidersConf.browserstackAliases[input.toUpperCase()]); isProvider = true; } else { @@ -483,28 +463,26 @@ function getBrowsersFromCLI(provider) { } } return { - browsersToRun: outputList.filter(function(item, pos, self) {return self.indexOf(item) == pos;}), + browsersToRun: + outputList.filter(function(item, pos, self) { return self.indexOf(item) == pos; }), isProvider: isProvider }; } -gulp.task('test.unit.js', ['build.js.dev'], function (done) { - runSequence( - '!test.unit.js/karma-server', - function() { - watch('modules/**', { ignoreInitial: true }, [ - '!broccoli.js.dev', - '!test.unit.js/karma-run' - ]); - } - ); +gulp.task('test.unit.js', ['build.js.dev'], function(done) { + printModulesWarning(); + runSequence('!test.unit.js/karma-server', function() { + watch('modules/**', {ignoreInitial: true}, ['!broccoli.js.dev', '!test.unit.js/karma-run']); + }); }); -gulp.task('watch.js.dev', ['build.js.dev'], function (done) { +gulp.task('watch.js.dev', ['build.js.dev'], function(done) { + printModulesWarning(); watch('modules/**', ['!broccoli.js.dev']); }); -gulp.task('test.unit.js.sauce', ['build.js.dev'], function (done) { +gulp.task('test.unit.js.sauce', ['build.js.dev'], function(done) { + printModulesWarning(); var browserConf = getBrowsersFromCLI('SL'); if (browserConf.isProvider) { launchKarmaWithExternalBrowsers(['dots'], browserConf.browsersToRun, done); @@ -513,30 +491,38 @@ gulp.task('test.unit.js.sauce', ['build.js.dev'], function (done) { } }); -gulp.task('test.unit.js.browserstack', ['build.js.dev'], function (done) { +gulp.task('test.unit.js.browserstack', ['build.js.dev'], function(done) { + printModulesWarning(); var browserConf = getBrowsersFromCLI('BS'); if (browserConf.isProvider) { launchKarmaWithExternalBrowsers(['dots'], browserConf.browsersToRun, done); } else { - throw new Error('ERROR: no Browserstack browsers provided, add them with the --browsers option'); + throw new Error( + 'ERROR: no Browserstack browsers provided, add them with the --browsers option'); } }); function launchKarmaWithExternalBrowsers(reporters, browsers, done) { - new karma.Server({ - configFile: __dirname + '/karma-js.conf.js', - singleRun: true, - browserNoActivityTimeout: 240000, - captureTimeout: 120000, - reporters: reporters, - browsers: browsers}, - function(err) {done(); process.exit(err ? 1 : 0);}).start(); + new karma.Server( + { + configFile: __dirname + '/karma-js.conf.js', + singleRun: true, + browserNoActivityTimeout: 240000, + captureTimeout: 120000, + reporters: reporters, + browsers: browsers + }, + function(err) { + done(); + process.exit(err ? 1 : 0); + }) + .start(); } gulp.task('!test.unit.js/karma-server', function(done) { var watchStarted = false; var server = new karma.Server({configFile: __dirname + '/karma-js.conf.js', reporters: 'dots'}); - server.on('run_complete', function () { + server.on('run_complete', function() { if (!watchStarted) { watchStarted = true; done(); @@ -552,89 +538,66 @@ gulp.task('!test.unit.js/karma-run', function(done) { runKarma('karma-js.conf.js', done); }); -gulp.task('test.unit.router', function (done) { - runSequence( - '!test.unit.router/karma-server', - function() { - watch('modules/**', [ - 'buildRouter.dev', - '!test.unit.router/karma-run' - ]); - } - ); +gulp.task('test.unit.router', function(done) { + runSequence('!test.unit.router/karma-server', function() { + watch('modules/**', ['buildRouter.dev', '!test.unit.router/karma-run']); + }); }); gulp.task('!test.unit.router/karma-server', function() { new karma.Server({ - configFile: __dirname + '/modules/angular1_router/karma-router.conf.js', - reporters: 'dots' - } - ).start(); + configFile: __dirname + '/modules/angular1_router/karma-router.conf.js', + reporters: 'dots' + }) + .start(); }); gulp.task('!test.unit.router/karma-run', function(done) { - karma.runner.run({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js'}, function(exitCode) { - // ignore exitCode, we don't want to fail the build in the interactive (non-ci) mode - // karma will print all test failures - done(); - }); -}); - -gulp.task('buildRouter.dev', function () { - buildRouter(); -}); - -gulp.task('test.unit.dart', function (done) { - runSequence( - 'build/tree.dart', - 'build/pure-packages.dart', - '!build/pubget.angular2.dart', - '!build/change_detect.dart', - '!build/remove-pub-symlinks', - 'build.dart.material.css', - '!test.unit.dart/karma-server', - '!test.unit.dart/karma-run', - function(error) { - // if initial build failed (likely due to build or formatting step) then exit - // otherwise karma server doesn't start and we can't continue running properly - if (error) { - done(error); - return; - } - - watch(['modules/angular2/**'], { ignoreInitial: true }, [ - '!build/tree.dart', - '!test.unit.dart/karma-run' - ]); - } - ); -}); - -gulp.task('watch.dart.dev', function (done) { - runSequence( - 'build/tree.dart', - 'build/pure-packages.dart', - '!build/pubget.angular2.dart', - '!build/change_detect.dart', - '!build/remove-pub-symlinks', - 'build.dart.material.css', - function(error) { - // if initial build failed (likely due to build or formatting step) then exit - // otherwise karma server doesn't start and we can't continue running properly - if (error) { - done(error); - return; - } - - watch(['modules/angular2/**'], { ignoreInitial: true }, [ - '!build/tree.dart' - ]); - } - ); -}); - -gulp.task('!test.unit.dart/karma-run', function (done) { + karma.runner.run({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js'}, + function(exitCode) { + // ignore exitCode, we don't want to fail the build in the interactive (non-ci) + // mode + // karma will print all test failures + done(); + }); +}); + +gulp.task('buildRouter.dev', function() { buildRouter(); }); + +gulp.task('test.unit.dart', function(done) { + printModulesWarning(); + runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart', + '!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css', + '!test.unit.dart/karma-server', '!test.unit.dart/karma-run', function(error) { + // if initial build failed (likely due to build or formatting step) then exit + // otherwise karma server doesn't start and we can't continue running properly + if (error) { + done(error); + return; + } + + watch(['modules/angular2/**'], {ignoreInitial: true}, + ['!build/tree.dart', '!test.unit.dart/karma-run']); + }); +}); + +gulp.task('watch.dart.dev', function(done) { + runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart', + '!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css', + function(error) { + // if initial build failed (likely due to build or formatting step) then exit + // otherwise karma server doesn't start and we can't continue running properly + if (error) { + done(error); + return; + } + + watch(['modules/angular2/**'], {ignoreInitial: true}, ['!build/tree.dart']); + }); +}); + +gulp.task('!test.unit.dart/karma-run', function(done) { // run the run command in a new process to avoid duplicate logging by both server and runner from // a single process runKarma('karma-dart.conf.js', done); @@ -646,48 +609,52 @@ gulp.task('!test.unit.dart/karma-server', function() { }); -gulp.task('test.unit.router/ci', function (done) { +gulp.task('test.unit.router/ci', function(done) { var browserConf = getBrowsersFromCLI(); - new karma.Server({ - configFile: __dirname + '/modules/angular1_router/karma-router.conf.js', - singleRun: true, - reporters: ['dots'], - browsers: browserConf.browsersToRun - }, - done - ).start(); -}); - -gulp.task('test.unit.js/ci', function (done) { + new karma.Server( + { + configFile: __dirname + '/modules/angular1_router/karma-router.conf.js', + singleRun: true, + reporters: ['dots'], + browsers: browserConf.browsersToRun + }, + done) + .start(); +}); + +gulp.task('test.unit.js/ci', function(done) { var browserConf = getBrowsersFromCLI(); - new karma.Server({ - configFile: __dirname + '/karma-js.conf.js', - singleRun: true, - reporters: ['dots'], - browsers: browserConf.browsersToRun - }, - done - ).start(); + new karma.Server( + { + configFile: __dirname + '/karma-js.conf.js', + singleRun: true, + reporters: ['dots'], + browsers: browserConf.browsersToRun + }, + done) + .start(); }); -gulp.task('test.unit.js.sauce/ci', function (done) { - launchKarmaWithExternalBrowsers(['dots', 'saucelabs'], browserProvidersConf.sauceAliases.CI, done); +gulp.task('test.unit.js.sauce/ci', function(done) { + launchKarmaWithExternalBrowsers(['dots', 'saucelabs'], browserProvidersConf.sauceAliases.CI, + done); }); -gulp.task('test.unit.js.browserstack/ci', function (done) { +gulp.task('test.unit.js.browserstack/ci', function(done) { launchKarmaWithExternalBrowsers(['dots'], browserProvidersConf.browserstackAliases.CI, done); }); -gulp.task('test.unit.dart/ci', function (done) { +gulp.task('test.unit.dart/ci', function(done) { var browserConf = getBrowsersFromCLI(); - new karma.Server({ - configFile: __dirname + '/karma-dart.conf.js', - singleRun: true, - reporters: ['dots'], - browsers: browserConf.browsersToRun - }, - done - ).start(); + new karma.Server( + { + configFile: __dirname + '/karma-dart.conf.js', + singleRun: true, + reporters: ['dots'], + browsers: browserConf.browsersToRun + }, + done) + .start(); }); @@ -696,52 +663,34 @@ gulp.task('test.unit.cjs/ci', function(done) { }); -gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function (neverDone) { - +gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function(neverDone) { + printModulesWarning(); treatTestErrorsAsFatal = false; - - var buildAndTest = [ - '!build.js.cjs', - 'test.unit.cjs/ci' - ]; - - watch('modules/**', buildAndTest); + watch('modules/**', ['!build.js.cjs', 'test.unit.cjs/ci']); }); // Use this target to continuously run dartvm unit-tests (such as transformer // tests) while coding. Note: these tests do not use Karma. -gulp.task('test.unit.dartvm', function (done) { +gulp.task('test.unit.dartvm', function(done) { runSequence( - 'build/tree.dart', - 'build/pure-packages.dart', - '!build/pubget.angular2.dart', - '!build/change_detect.dart', - '!test.unit.dartvm/run', - function(error) { - // Watch for changes made in the TS and Dart code under "modules" and - // run ts2dart and test change detector generator prior to rerunning the - // tests. - watch('modules/angular2/**', { ignoreInitial: true }, [ - '!build/tree.dart', - '!build/change_detect.dart', - '!test.unit.dartvm/run' - ]); - - // Watch for changes made in Dart code under "modules_dart", then copy it - // to dist and run test change detector generator prior to retunning the - // tests. - watch('modules_dart/**', { ignoreInitial: true }, [ - 'build/pure-packages.dart', - '!build/change_detect.dart', - '!test.unit.dartvm/run' - ]); - } - ); + 'build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart', + '!build/change_detect.dart', '!test.unit.dartvm/run', function(error) { + // Watch for changes made in the TS and Dart code under "modules" and + // run ts2dart and test change detector generator prior to rerunning the + // tests. + watch('modules/angular2/**', {ignoreInitial: true}, + ['!build/tree.dart', '!build/change_detect.dart', '!test.unit.dartvm/run']); + + // Watch for changes made in Dart code under "modules_dart", then copy it + // to dist and run test change detector generator prior to retunning the + // tests. + watch('modules_dart/**', {ignoreInitial: true}, + ['build/pure-packages.dart', '!build/change_detect.dart', '!test.unit.dartvm/run']); + }); }); -gulp.task('!test.unit.dartvm/run', runServerDartTests(gulp, gulpPlugins, { - dir: 'dist/dart/angular2' -})); +gulp.task('!test.unit.dartvm/run', + runServerDartTests(gulp, gulpPlugins, {dir: 'dist/dart/angular2'})); gulp.task('test.unit.tools/ci', function(done) { @@ -749,14 +698,11 @@ gulp.task('test.unit.tools/ci', function(done) { }); -gulp.task('test.unit.tools', ['build/clean.tools'], function(done) { +gulp.task('test.unit.tools', ['build/clean.tools'], function(done) { treatTestErrorsAsFatal = false; - var buildAndTest = [ - '!build.tools', - 'test.unit.tools/ci' - ]; + var buildAndTest = ['!build.tools', 'test.unit.tools/ci']; watch(['tools/**', '!tools/**/test-fixtures/**'], buildAndTest); }); @@ -766,15 +712,12 @@ gulp.task('test.unit.tools', ['build/clean.tools'], function(done) { // server tests // These tests run on the VM on the command-line and are // allowed to access the file system and network. -gulp.task('test.server.dart', runServerDartTests(gulp, gulpPlugins, { - dest: 'dist/dart' -})); +gulp.task('test.server.dart', runServerDartTests(gulp, gulpPlugins, {dest: 'dist/dart'})); // ----------------- // test builders -gulp.task('test.transpiler.unittest', function(done) { - runJasmineTests(['tools/transpiler/unittest/**/*.js'], done); -}); +gulp.task('test.transpiler.unittest', + function(done) { runJasmineTests(['tools/transpiler/unittest/**/*.js'], done); }); // ----------------- // Pre-test checks @@ -789,9 +732,8 @@ gulp.task('pre-test-checks', function(done) { // feedback while allowing tests to execute. gulp.task('static-checks', ['!build.tools'], function(done) { runSequence( - // We do not run test.typings here because it requires building, which is too slow. - ['enforce-format', 'lint'], - sequenceComplete(done)); + // We do not run test.typings here because it requires building, which is too slow. + ['enforce-format', 'lint'], sequenceComplete(done)); }); @@ -803,28 +745,27 @@ gulp.task('static-checks', ['!build.tools'], function(done) { // the typescript compiler. // Make sure the two typings tests are isolated, by running this one in a tempdir -var tmpdir = path.join(os.tmpdir(), 'test.typings', new Date().getTime().toString()); +var tmpdir = path.join(os.tmpdir(), 'test.typings', new Date().getTime().toString()); gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() { - return gulp - .src(['dist/js/cjs/angular2/**/*', 'node_modules/@reactivex/rxjs/dist/cjs/**'], {base: 'dist/js/cjs'}) - .pipe(gulp.dest(path.join(tmpdir, 'node_modules'))); + return gulp.src(['dist/js/cjs/angular2/**/*', 'node_modules/@reactivex/rxjs/dist/cjs/**'], + {base: 'dist/js/cjs'}) + .pipe(gulp.dest(path.join(tmpdir, 'node_modules'))); }); gulp.task('!pre.test.typings.copyTypingsSpec', function() { - return gulp - .src(['typing_spec/*.ts'], {base: 'typing_spec'}) - .pipe(gulp.dest(path.join(tmpdir))); -}); -gulp.task('test.typings', [ - '!pre.test.typings.layoutNodeModule', - '!pre.test.typings.copyTypingsSpec' -], function() { - return gulp.src([tmpdir + '/**']) - .pipe(tsc({target: 'ES5', module: 'commonjs', - experimentalDecorators: true, - noImplicitAny: true, - moduleResolution: 'node', - typescript: require('typescript')})); -}); + return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir))); +}); +gulp.task('test.typings', + ['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() { + return gulp.src([tmpdir + '/**']) + .pipe(tsc({ + target: 'ES5', + module: 'commonjs', + experimentalDecorators: true, + noImplicitAny: true, + moduleResolution: 'node', + typescript: require('typescript') + })); + }); // ----------------- // orchestrated targets @@ -839,105 +780,86 @@ gulp.task('build/pure-packages.dart', function() { var yaml = require('js-yaml'); var originalPrefix = '../../dist/dart/'; - return gulp - .src([ - 'modules_dart/transform/**/*', - '!modules_dart/transform/**/*.proto', - '!modules_dart/transform/pubspec.yaml', - '!modules_dart/transform/**/packages{,/**}', - ]) - .pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2'))); + return gulp.src([ + 'modules_dart/transform/**/*', + '!modules_dart/transform/**/*.proto', + '!modules_dart/transform/pubspec.yaml', + '!modules_dart/transform/**/packages{,/**}', + ]) + .pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2'))); }); // Builds all Dart packages, but does not compile them gulp.task('build/packages.dart', function(done) { - runSequence( - 'lint_protos.dart', - 'build/tree.dart', - 'build/pure-packages.dart', - // Run after 'build/tree.dart' because broccoli clears the dist/dart folder - '!build/pubget.angular2.dart', - '!build/change_detect.dart', - sequenceComplete(done)); + runSequence('lint_protos.dart', 'build/tree.dart', 'build/pure-packages.dart', + // Run after 'build/tree.dart' because broccoli clears the dist/dart folder + '!build/pubget.angular2.dart', '!build/change_detect.dart', sequenceComplete(done)); }); // Builds and compiles all Dart packages gulp.task('build.dart', function(done) { - runSequence( - 'build/packages.dart', - 'build/pubspec.dart', - 'build/analyze.dart', - 'build/check.apidocs.dart', - 'build.dart.material.css', - sequenceComplete(done) - ); + runSequence('build/packages.dart', 'build/pubspec.dart', 'build/analyze.dart', + 'build/check.apidocs.dart', 'build.dart.material.css', sequenceComplete(done)); }); // public task to build tools -gulp.task('build.tools', ['build/clean.tools'], function(done) { - runSequence('!build.tools', sequenceComplete(done)); -}); +gulp.task('build.tools', ['build/clean.tools'], + function(done) { runSequence('!build.tools', sequenceComplete(done)); }); // private task to build tools gulp.task('!build.tools', function() { var stream = gulp.src(['tools/**/*.ts']) - .pipe(sourcemaps.init()) - .pipe(tsc({target: 'ES5', module: 'commonjs', - // Don't use the version of typescript that gulp-typescript depends on - // see https://github.com/ivogabe/gulp-typescript#typescript-version - typescript: require('typescript')})) - .on('error', function(error) { - // nodejs doesn't propagate errors from the src stream into the final stream so we are - // forwarding the error into the final stream - stream.emit('error', error); - }) - .pipe(sourcemaps.write('.')) - .pipe(gulp.dest('dist/tools')) - .on('end', function() { - var AngularBuilder = require('./dist/tools/broccoli/angular_builder').AngularBuilder; - angularBuilder = new AngularBuilder({ - outputPath: 'dist', - dartSDK: DART_SDK, - logs: logs - }); - }); + .pipe(sourcemaps.init()) + .pipe(tsc({ + target: 'ES5', + module: 'commonjs', + // Don't use the version of typescript that gulp-typescript depends on + // see https://github.com/ivogabe/gulp-typescript#typescript-version + typescript: require('typescript') + })) + .on('error', + function(error) { + // nodejs doesn't propagate errors from the src stream into the final + // stream so we are + // forwarding the error into the final stream + stream.emit('error', error); + }) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('dist/tools')) + .on('end', function() { + var AngularBuilder = + require('./dist/tools/broccoli/angular_builder').AngularBuilder; + angularBuilder = + new AngularBuilder({outputPath: 'dist', dartSDK: DART_SDK, logs: logs}); + }); return stream; }); -gulp.task('broccoli.js.dev', ['build.tools'], function(done) { - runSequence('!broccoli.js.dev', sequenceComplete(done)); -}); +gulp.task('broccoli.js.dev', ['build.tools'], + function(done) { runSequence('!broccoli.js.dev', sequenceComplete(done)); }); -gulp.task('!broccoli.js.dev', function() { - return angularBuilder.rebuildBrowserDevTree(); -}); +gulp.task('!broccoli.js.dev', + () => { return angularBuilder.rebuildBrowserDevTree(cliArgsProjects); }); -gulp.task('!broccoli.js.prod', function() { - return angularBuilder.rebuildBrowserProdTree(); -}); +gulp.task('!broccoli.js.prod', + function() { return angularBuilder.rebuildBrowserProdTree(cliArgsProjects); }); gulp.task('build.js.dev', ['build/clean.js'], function(done) { - runSequence( - 'broccoli.js.dev', - 'build.css.material', - sequenceComplete(done) - ); + runSequence('broccoli.js.dev', 'build.css.material', sequenceComplete(done)); }); -gulp.task('build.js.prod', ['build.tools'], function(done) { - runSequence('!broccoli.js.prod', sequenceComplete(done)); -}); +gulp.task('build.js.prod', ['build.tools'], + function(done) { runSequence('!broccoli.js.prod', sequenceComplete(done)); }); /** * public task */ -gulp.task('build.js.cjs', ['build.tools'], function(done) { - runSequence('!build.js.cjs', sequenceComplete(done)); -}); +gulp.task('build.js.cjs', ['build.tools'], + function(done) { runSequence('!build.js.cjs', sequenceComplete(done)); }); var firstBuildJsCjs = true; @@ -946,16 +868,15 @@ var firstBuildJsCjs = true; * private task */ gulp.task('!build.js.cjs', function() { - return angularBuilder.rebuildNodeTree().then(function() { - if (firstBuildJsCjs) { - firstBuildJsCjs = false; - console.log('creating node_modules symlink hack'); - // linknodemodules is all sync - linknodemodules(gulp, gulpPlugins, { - dir: CONFIG.dest.js.cjs - })(); - } - }); + return angularBuilder.rebuildNodeTree(cliArgsProjects) + .then(function() { + if (firstBuildJsCjs) { + firstBuildJsCjs = false; + console.log('creating node_modules symlink hack'); + // linknodemodules is all sync + linknodemodules(gulp, gulpPlugins, {dir: CONFIG.dest.js.cjs})(); + } + }); }); @@ -973,81 +894,72 @@ var bundleConfig = { // production build gulp.task('!bundle.js.prod', ['build.js.prod'], function() { - var bundlerConfig = { - sourceMaps: true - }; - - return bundler.bundle(bundleConfig, 'angular2/angular2', './dist/build/angular2.js', bundlerConfig) - .then(function(){ - return q.all([ - bundler.bundle(bundleConfig, 'angular2/http - angular2/angular2', './dist/build/http.js', bundlerConfig), - bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', './dist/build/router.js', bundlerConfig) - ]); - }); + var bundlerConfig = {sourceMaps: true}; + + return bundler.bundle(bundleConfig, 'angular2/angular2', './dist/build/angular2.js', + bundlerConfig) + .then(function() { + return q.all([ + bundler.bundle(bundleConfig, 'angular2/http - angular2/angular2', './dist/build/http.js', + bundlerConfig), + bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', + './dist/build/router.js', bundlerConfig) + ]); + }); }); // minified production build gulp.task('!bundle.js.min', ['build.js.prod'], function() { - var bundlerConfig = { - sourceMaps: true, - minify: true - }; - - return bundler.bundle(bundleConfig, 'angular2/angular2', './dist/build/angular2.min.js', bundlerConfig) - .then(function(){ - return q.all([ - bundler.bundle(bundleConfig, 'angular2/http - angular2/angular2', './dist/build/http.min.js', bundlerConfig), - bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', './dist/js/build/router.min.js', bundlerConfig) - ]); - }); + var bundlerConfig = {sourceMaps: true, minify: true}; + + return bundler.bundle(bundleConfig, 'angular2/angular2', './dist/build/angular2.min.js', + bundlerConfig) + .then(function() { + return q.all([ + bundler.bundle(bundleConfig, 'angular2/http - angular2/angular2', + './dist/build/http.min.js', bundlerConfig), + bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', + './dist/js/build/router.min.js', bundlerConfig) + ]); + }); }); // development build gulp.task('!bundle.js.dev', ['build.js.dev'], function() { - var bundlerConfig = { - sourceMaps: true - }; + var bundlerConfig = {sourceMaps: true}; var devBundleConfig = merge(true, bundleConfig); - devBundleConfig.paths = merge(true, devBundleConfig.paths, { - "*": "dist/js/dev/es5/*.js" - }); + devBundleConfig.paths = merge(true, devBundleConfig.paths, {"*": "dist/js/dev/es5/*.js"}); - return bundler.bundle(devBundleConfig, 'angular2/angular2', './dist/build/angular2.dev.js', bundlerConfig) - .then(function(){ - return q.all([ - bundler.bundle(devBundleConfig, 'angular2/http - angular2/angular2', './dist/build/http.dev.js', bundlerConfig), - bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', './dist/build/router.dev.js', bundlerConfig) - ]); - }); + return bundler.bundle(devBundleConfig, 'angular2/angular2', './dist/build/angular2.dev.js', + bundlerConfig) + .then(function() { + return q.all([ + bundler.bundle(devBundleConfig, 'angular2/http - angular2/angular2', + './dist/build/http.dev.js', bundlerConfig), + bundler.bundle(bundleConfig, 'angular2/router - angular2/angular2', + './dist/build/router.dev.js', bundlerConfig) + ]); + }); }); // WebWorker build gulp.task("!bundle.web_worker.js.dev", ["build.js.dev"], function() { var devBundleConfig = merge(true, bundleConfig); devBundleConfig.paths = merge(true, devBundleConfig.paths, {"*": "dist/js/dev/es5/*.js"}); - return bundler.bundle( - devBundleConfig, - 'angular2/web_worker/ui', - './dist/build/web_worker/ui.dev.js', - { sourceMaps: true }). - then(function() { - return bundler.bundle( - devBundleConfig, - 'angular2/web_worker/worker', - './dist/build/web_worker/worker.dev.js', - { sourceMaps: true}); + return bundler.bundle(devBundleConfig, 'angular2/web_worker/ui', + './dist/build/web_worker/ui.dev.js', {sourceMaps: true}) + .then(function() { + return bundler.bundle(devBundleConfig, 'angular2/web_worker/worker', + './dist/build/web_worker/worker.dev.js', {sourceMaps: true}); }); }); gulp.task('!bundle.testing', ['build.js.dev'], function() { var devBundleConfig = merge(true, bundleConfig); devBundleConfig.paths = merge(true, devBundleConfig.paths, {"*": "dist/js/dev/es5/*.js"}); - return bundler.bundle( - devBundleConfig, - 'angular2/testing + angular2/mock - angular2/angular2', - './dist/js/bundle/testing.js', - { sourceMaps: true }); + return bundler.bundle(devBundleConfig, 'angular2/testing + angular2/mock - angular2/angular2', + './dist/js/bundle/testing.js', {sourceMaps: true}); }); // self-executing development build @@ -1069,22 +981,18 @@ gulp.task('!bundle.js.sfx.dev', ['build.js.dev'], function() { }); gulp.task('!bundle.js.prod.deps', ['!bundle.js.prod'], function() { - return merge2( - addDevDependencies('angular2.js'), - bundler.modify(['dist/build/http.js'], 'http.js'), - bundler.modify(['dist/build/router.js'], 'router.js') - ) - .pipe(gulp.dest('dist/js/bundle')); + return merge2(addDevDependencies('angular2.js'), + bundler.modify(['dist/build/http.js'], 'http.js'), + bundler.modify(['dist/build/router.js'], 'router.js')) + .pipe(gulp.dest('dist/js/bundle')); }); gulp.task('!bundle.js.min.deps', ['!bundle.js.min'], function() { - return merge2( - addDevDependencies('angular2.min.js'), - bundler.modify(['dist/build/http.min.js'], 'http.min.js'), - bundler.modify(['dist/build/router.min.js'], 'router.min.js') - ) - .pipe(uglify()) - .pipe(gulp.dest('dist/js/bundle')); + return merge2(addDevDependencies('angular2.min.js'), + bundler.modify(['dist/build/http.min.js'], 'http.min.js'), + bundler.modify(['dist/build/router.min.js'], 'router.min.js')) + .pipe(uglify()) + .pipe(gulp.dest('dist/js/bundle')); }); var JS_DEV_DEPS = [ @@ -1107,46 +1015,41 @@ function insertRXLicense(source) { } function addDevDependencies(outputFile) { - return bundler.modify( - JS_DEV_DEPS.concat(['dist/build/' + outputFile]), - outputFile) + return bundler.modify(JS_DEV_DEPS.concat(['dist/build/' + outputFile]), outputFile) .pipe(insert.transform(insertRXLicense)) .pipe(gulp.dest('dist/js/bundle')); } gulp.task('!bundle.js.dev.deps', ['!bundle.js.dev'], function() { - return merge2( - addDevDependencies('angular2.dev.js'), - bundler.modify(['dist/build/http.dev.js'], 'http.dev.js'), - bundler.modify(['dist/build/router.dev.js'], 'router.dev.js') - ) - .pipe(gulp.dest('dist/js/bundle')); + return merge2(addDevDependencies('angular2.dev.js'), + bundler.modify(['dist/build/http.dev.js'], 'http.dev.js'), + bundler.modify(['dist/build/router.dev.js'], 'router.dev.js')) + .pipe(gulp.dest('dist/js/bundle')); }); gulp.task('!bundle.js.sfx.dev.deps', ['!bundle.js.sfx.dev'], function() { return merge2( - bundler.modify(JS_DEV_DEPS.concat(['dist/build/angular2.sfx.dev.js']), - 'angular2.sfx.dev.js') - .pipe(gulp.dest('dist/js/bundle')), - bundler.modify(['dist/build/http.sfx.dev.js'], - 'http.sfx.dev.js') - .pipe(gulp.dest('dist/js/bundle'))); + bundler.modify(JS_DEV_DEPS.concat(['dist/build/angular2.sfx.dev.js']), 'angular2.sfx.dev.js') + .pipe(gulp.dest('dist/js/bundle')), + bundler.modify(['dist/build/http.sfx.dev.js'], 'http.sfx.dev.js') + .pipe(gulp.dest('dist/js/bundle'))); }); gulp.task('!bundle.web_worker.js.dev.deps', ['!bundle.web_worker.js.dev'], function() { - return merge2(addDevDependencies("web_worker/ui.dev.js", - addDevDependencies("web_worker/worker.dev.js"))); + return merge2( + addDevDependencies("web_worker/ui.dev.js", addDevDependencies("web_worker/worker.dev.js"))); }); // We need to duplicate the deps of bundles.js so that this task runs after // all the bundle files are created. -gulp.task('!bundle.copy', [ - '!bundle.js.prod.deps', - '!bundle.js.dev.deps', - '!bundle.js.min.deps', - '!bundle.web_worker.js.dev.deps', - '!bundle.js.sfx.dev.deps' -], +gulp.task('!bundle.copy', + [ + '!bundle.js.prod.deps', + '!bundle.js.dev.deps', + '!bundle.js.min.deps', + '!bundle.web_worker.js.dev.deps', + '!bundle.js.sfx.dev.deps' + ], function() { return merge2(gulp.src('dist/js/bundle/**').pipe(gulp.dest('dist/js/prod/es5/bundle')), gulp.src('dist/js/bundle/**').pipe(gulp.dest('dist/js/dev/es5/bundle'))); @@ -1159,27 +1062,35 @@ gulp.task('bundles.js', [ '!bundle.web_worker.js.dev.deps', '!bundle.js.sfx.dev.deps', '!bundle.testing', - '!bundle.copy']); + '!bundle.copy' +]); -gulp.task('build.js', ['build.js.dev', 'build.js.prod', 'build.js.cjs', 'bundles.js', 'benchpress.bundle']); +gulp.task('build.js', + ['build.js.dev', 'build.js.prod', 'build.js.cjs', 'bundles.js', 'benchpress.bundle']); -gulp.task('clean', ['build/clean.tools', 'build/clean.js', 'build/clean.dart', 'build/clean.docs', 'build/clean.benchpress.bundle']); +gulp.task('clean', [ + 'build/clean.tools', + 'build/clean.js', + 'build/clean.dart', + 'build/clean.docs', + 'build/clean.benchpress.bundle' +]); gulp.task('build', ['build.js', 'build.dart']); // ------------ // transform codegen gulp.task('lint_protos.dart', function(done) { - return proto.lint({ - dir: 'modules_dart/transform/lib/src/transform/common/model/' - }, done); + return proto.lint({dir: 'modules_dart/transform/lib/src/transform/common/model/'}, done); }); gulp.task('gen_protos.dart', function(done) { - return proto.generate({ - dir: 'modules_dart/transform/lib/src/transform/common/model/', - plugin: 'tools/build/protoc-gen-dart' - }, done); + return proto.generate( + { + dir: 'modules_dart/transform/lib/src/transform/common/model/', + plugin: 'tools/build/protoc-gen-dart' + }, + done); }); // change detection codegen @@ -1196,7 +1107,7 @@ gulp.task('!build/change_detect.dart', function(done) { var dartStream = fs.createWriteStream(path.join(destDir, 'change_detector_classes.dart')); var genMain = path.join(srcDir, 'gen_change_detectors.dart'); - var proc = spawn(DART_SDK.VM, [genMain], { stdio:['ignore', 'pipe', 'inherit'] }); + var proc = spawn(DART_SDK.VM, [genMain], {stdio: ['ignore', 'pipe', 'inherit']}); proc.on('error', function(code) { done(new Error('Failed while generating change detector classes. Please run manually: ' + DART_SDK.VM + ' ' + dartArgs.join(' '))); @@ -1239,29 +1150,20 @@ gulp.task('build.dart.material', ['build/packages.dart'], function(done) { runSequence('build/packages.dart', 'build.dart.material.css', sequenceComplete(done)); }); -gulp.task('cleanup.builder', function() { - return angularBuilder.cleanup(); -}); +gulp.task('cleanup.builder', function() { return angularBuilder.cleanup(); }); gulp.task('benchpress.bundle', ['build/clean.benchpress.bundle', 'build.js.cjs'], function(cb) { - bundler.benchpressBundle( - BENCHPRESS_BUNDLE_CONFIG.entries, - BENCHPRESS_BUNDLE_CONFIG.packageJson, - BENCHPRESS_BUNDLE_CONFIG.includes, - BENCHPRESS_BUNDLE_CONFIG.excludes, - BENCHPRESS_BUNDLE_CONFIG.ignore, - BENCHPRESS_BUNDLE_CONFIG.dest, - cb - ); + bundler.benchpressBundle(BENCHPRESS_BUNDLE_CONFIG.entries, BENCHPRESS_BUNDLE_CONFIG.packageJson, + BENCHPRESS_BUNDLE_CONFIG.includes, BENCHPRESS_BUNDLE_CONFIG.excludes, + BENCHPRESS_BUNDLE_CONFIG.ignore, BENCHPRESS_BUNDLE_CONFIG.dest, cb); }); -// register cleanup listener for ctrl+c/kill used to quit any persistent task (autotest or serve tasks) +// register cleanup listener for ctrl+c/kill used to quit any persistent task (autotest or serve +// tasks) process.on('SIGINT', function() { if (!angularBuilder.uninitialized) { - runSequence('cleanup.builder', function () { - process.exit(); - }); + runSequence('cleanup.builder', function() { process.exit(); }); } else { process.exit(); } @@ -1282,6 +1184,14 @@ process.on('beforeExit', function() { }); -gulp.on('task_start', (e) => { analytics.buildStart('gulp ' + e.task)}); -gulp.on('task_stop', (e) => { analytics.buildSuccess('gulp ' + e.task, e.duration*1000)}); -gulp.on('task_err', (e) => { analytics.buildError('gulp ' + e.task, e.duration*1000)}); +var firstTask = true; +gulp.on('task_start', (e) => { + if (firstTask) { + firstTask = false; + analytics.buildSuccess('gulp ', process.uptime() * 1000); + } + + analytics.buildStart('gulp ' + e.task) +}); +gulp.on('task_stop', (e) => {analytics.buildSuccess('gulp ' + e.task, e.duration * 1000)}); +gulp.on('task_err', (e) => {analytics.buildError('gulp ' + e.task, e.duration * 1000)}); diff --git a/modules/angular2/manual_typings/globals-es6.d.ts b/modules/angular2/manual_typings/globals-es6.d.ts index 02540be14c96..43d437ad648a 100644 --- a/modules/angular2/manual_typings/globals-es6.d.ts +++ b/modules/angular2/manual_typings/globals-es6.d.ts @@ -8,8 +8,14 @@ /// /// /// + +// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all +// the code including client code +/// + declare var assert: any; + interface BrowserNodeGlobal { Object: typeof Object; Array: typeof Array; diff --git a/tools/analytics/analytics.js b/tools/analytics/analytics.js index 3a5378c337e2..7d4ee2df2cf8 100644 --- a/tools/analytics/analytics.js +++ b/tools/analytics/analytics.js @@ -2,6 +2,7 @@ let execSync = require('child_process').execSync; let fs = require('fs'); +let minimist = require('minimist'); let path = require('path'); let os = require('os'); let ua; @@ -35,7 +36,7 @@ if (ua) { // https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters let customParams = { // OS Platform (darwin, win32, linux) - cd1: os.platform, + cd1: os.platform(), // Node.js Version (v4.1.2) cd2: process.version, // npm Version (2.14.7) @@ -58,6 +59,8 @@ let customParams = { cd8: `${os.cpus().length} x ${os.cpus()[0].model}`, // HW - Memory Info cd9: `${Math.round(os.totalmem()/1024/1024/1024)}GB`, + // gulp --projects (angular2,angular2_material) + cd13: minimist(process.argv.slice(2)).projects }; diff --git a/tools/broccoli/angular_builder.ts b/tools/broccoli/angular_builder.ts index ae45e1ef579a..699c3d6a0271 100644 --- a/tools/broccoli/angular_builder.ts +++ b/tools/broccoli/angular_builder.ts @@ -7,6 +7,10 @@ var path = require('path'); var printSlowTrees = require('broccoli-slow-trees'); var Q = require('q'); +type ProjectMap = { + [key: string]: boolean +}; + /** * BroccoliBuilder facade for all of our build pipelines. */ @@ -21,26 +25,26 @@ export class AngularBuilder { constructor(public options: AngularBuilderOptions) { this.outputPath = options.outputPath; } - public rebuildBrowserDevTree(): Promise { - this.browserDevBuilder = this.browserDevBuilder || this.makeBrowserDevBuilder(); + public rebuildBrowserDevTree(projects: ProjectMap): Promise { + this.browserDevBuilder = this.browserDevBuilder || this.makeBrowserDevBuilder(projects); return this.rebuild(this.browserDevBuilder, 'js.dev'); } - public rebuildBrowserProdTree(): Promise { - this.browserProdBuilder = this.browserProdBuilder || this.makeBrowserProdBuilder(); + public rebuildBrowserProdTree(projects: ProjectMap): Promise { + this.browserProdBuilder = this.browserProdBuilder || this.makeBrowserProdBuilder(projects); return this.rebuild(this.browserProdBuilder, 'js.prod'); } - public rebuildNodeTree(): Promise { - this.nodeBuilder = this.nodeBuilder || this.makeNodeBuilder(); + public rebuildNodeTree(projects: ProjectMap): Promise { + this.nodeBuilder = this.nodeBuilder || this.makeNodeBuilder(projects); return this.rebuild(this.nodeBuilder, 'js.cjs'); } - public rebuildDartTree(): Promise { - this.dartBuilder = this.dartBuilder || this.makeDartBuilder(); + public rebuildDartTree(projects: ProjectMap): Promise { + this.dartBuilder = this.dartBuilder || this.makeDartBuilder(projects); return this.rebuild(this.dartBuilder, 'dart'); } @@ -54,31 +58,32 @@ export class AngularBuilder { } - private makeBrowserDevBuilder(): BroccoliBuilder { - let tree = makeBrowserTree({name: 'dev', typeAssertions: true}, + private makeBrowserDevBuilder(projects: ProjectMap): BroccoliBuilder { + let tree = makeBrowserTree({name: 'dev', typeAssertions: true, projects: projects}, path.join(this.outputPath, 'js', 'dev')); return new broccoli.Builder(tree); } - private makeBrowserProdBuilder(): BroccoliBuilder { - let tree = makeBrowserTree({name: 'prod', typeAssertions: false}, + private makeBrowserProdBuilder(projects: ProjectMap): BroccoliBuilder { + let tree = makeBrowserTree({name: 'prod', typeAssertions: false, projects: projects}, path.join(this.outputPath, 'js', 'prod')); return new broccoli.Builder(tree); } - private makeNodeBuilder(): BroccoliBuilder { - let tree = makeNodeTree(path.join(this.outputPath, 'js', 'cjs')); + private makeNodeBuilder(projects: ProjectMap): BroccoliBuilder { + let tree = makeNodeTree(projects, path.join(this.outputPath, 'js', 'cjs')); return new broccoli.Builder(tree); } - private makeDartBuilder(): BroccoliBuilder { + private makeDartBuilder(projects: ProjectMap): BroccoliBuilder { let options = { outputPath: path.join(this.outputPath, 'dart'), dartSDK: this.options.dartSDK, - logs: this.options.logs + logs: this.options.logs, + projects: projects }; let tree = makeDartTree(options); return new broccoli.Builder(tree); diff --git a/tools/broccoli/broccoli-typescript.ts b/tools/broccoli/broccoli-typescript.ts index 5156422e8ff6..c90db682a810 100644 --- a/tools/broccoli/broccoli-typescript.ts +++ b/tools/broccoli/broccoli-typescript.ts @@ -47,6 +47,12 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin { // in tsc 1.7.x this api was renamed to parseJsonConfigFileContent // the conversion is a bit awkward, see https://github.com/Microsoft/TypeScript/issues/5276 this.tsOpts = ts.parseConfigFile({compilerOptions: options, files: []}, null, null).options; + + // TODO: the above turns rootDir set to './' into an empty string - looks like a tsc bug + // check back when we upgrade to 1.7.x + if (this.tsOpts.rootDir === '') { + this.tsOpts.rootDir = './'; + } this.tsOpts.outDir = this.cachePath; this.tsServiceHost = new CustomLanguageServiceHost(this.tsOpts, this.rootFilePaths, diff --git a/tools/broccoli/diffing-broccoli-plugin.ts b/tools/broccoli/diffing-broccoli-plugin.ts index 4ab3d3610984..d61db4364f2f 100644 --- a/tools/broccoli/diffing-broccoli-plugin.ts +++ b/tools/broccoli/diffing-broccoli-plugin.ts @@ -20,7 +20,7 @@ export {DiffResult} from './tree-differ'; * an instance of BroccoliTree. * * @param pluginClass - * @returns {DiffingPlugin} + * @returns {DiffingBroccoliPlugin} */ export function wrapDiffingPlugin(pluginClass): DiffingPluginWrapperFactory { return function() { return new DiffingPluginWrapper(pluginClass, arguments); }; @@ -160,10 +160,19 @@ class DiffingPluginWrapper implements BroccoliTree { private stabilizeTrees(trees: BroccoliTree[]) { // Prevent extensions to prevent array from being mutated from the outside. // For-loop used to avoid re-allocating a new array. + var stableTrees = []; for (let i = 0; i < trees.length; ++i) { - trees[i] = this.stabilizeTree(trees[i]); + // ignore null/undefined input tries in order to support conditional build pipelines + if (trees[i]) { + stableTrees.push(this.stabilizeTree(trees[i])); + } + } + + if (stableTrees.length === 0) { + throw new Error('No input trees provided!'); } - return Object.freeze(trees); + + return Object.freeze(stableTrees); } @@ -172,7 +181,7 @@ class DiffingPluginWrapper implements BroccoliTree { // so we need to stabilize them. // Since it's not safe to use instanceof operator in node, we are checking the constructor.name. // - // New-styler/rebuild trees should always be stable. + // New-style/rebuild trees should always be stable. let isNewStyleTree = !!(tree['newStyleTree'] || typeof tree.rebuild === 'function' || tree['isReadAPICompatTree'] || tree.constructor['name'] === 'Funnel'); diff --git a/tools/broccoli/trees/browser_tree.ts b/tools/broccoli/trees/browser_tree.ts index ad02214e9127..b736c25b6396 100644 --- a/tools/broccoli/trees/browser_tree.ts +++ b/tools/broccoli/trees/browser_tree.ts @@ -70,26 +70,55 @@ const kServedPaths = [ module.exports = function makeBrowserTree(options, destinationPath) { - var modulesTree = new Funnel('modules', { - include: ['**/**'], - exclude: [ - '**/*.cjs', - 'benchmarks/e2e_test/**', - 'angular1_router/**', - // Exclude ES6 polyfill typings when tsc target=ES6 - 'angular2/typings/es6-*/**', - ], - destDir: '/' - }); + var modules = options.projects; + + if (modules.angular2) { + var angular2Tree = new Funnel('modules/angular2', { + include: ['**/**'], + exclude: [ + // Exclude ES6 polyfill typings when tsc target=ES6 + 'typings/es6-*/**', + ], + destDir: '/angular2/' + }); + } + + if (modules.angular2_material) { + var angular2MaterialTree = + new Funnel('modules/angular2_material', + {include: ['**/**'], exclude: ['e2e_test/**'], destDir: '/angular2_material/'}); + } + + if (modules.benchmarks) { + var benchmarksTree = + new Funnel('modules/benchmarks', + {include: ['**/**'], exclude: ['e2e_test/**'], destDir: '/benchmarks/'}); + } + + if (modules.benchmarks_external) { + var benchmarksExternalTree = new Funnel( + 'modules/benchmarks_external', + {include: ['**/**'], exclude: ['e2e_test/**'], destDir: '/benchmarks_external/'}); + } + + if (modules.playground) { + var playgroundTree = + new Funnel('modules/playground', + {include: ['**/**'], exclude: ['e2e_test/**'], destDir: '/playground/'}); + } + + var modulesTree = mergeTrees( + [angular2Tree, angular2MaterialTree, benchmarksTree, benchmarksExternalTree, playgroundTree]); var clientModules = new Funnel( 'node_modules', {include: ['@reactivex/**/**', 'parse5/**/**', 'css/**/**'], destDir: '/'}); - var es5ModulesTree = new Funnel('modules', { - include: ['**/**'], - exclude: ['**/*.cjs', 'angular1_router/**', 'benchmarks/e2e_test/**'], - destDir: '/' - }); + var es6PolyfillTypings = + new Funnel('modules', {include: ['angular2/typings/es6-*/**'], destDir: '/'}); + + var es5ModulesTree = mergeTrees([modulesTree, es6PolyfillTypings]); + + es5ModulesTree = stew.debug(es5ModulesTree, {name: 'debug-es5'}); var scriptPathPatternReplacement = { match: '@@PATH', @@ -119,7 +148,7 @@ module.exports = function makeBrowserTree(options, destinationPath) { experimentalDecorators: true, mapRoot: '', // force sourcemaps to use relative path noEmitOnError: false, - rootDir: '.', + rootDir: './', rootFilePaths: ['angular2/manual_typings/globals-es6.d.ts'], sourceMap: true, sourceRoot: '.', @@ -127,7 +156,7 @@ module.exports = function makeBrowserTree(options, destinationPath) { }); // Use TypeScript to transpile the *.ts files to ES5 - var typescriptOptions = { + var es5Tree = compileWithTypescript(es5ModulesTree, { declaration: false, emitDecoratorMetadata: true, experimentalDecorators: true, @@ -135,13 +164,12 @@ module.exports = function makeBrowserTree(options, destinationPath) { module: 'commonjs', moduleResolution: 'classic', noEmitOnError: true, - rootDir: '.', + rootDir: './', rootFilePaths: ['angular2/manual_typings/globals.d.ts'], sourceMap: true, sourceRoot: '.', target: 'es5' - }; - var es5Tree = compileWithTypescript(es5ModulesTree, typescriptOptions); + }); var vendorScriptsTree = flatten(new Funnel('.', { files: [ @@ -173,61 +201,80 @@ module.exports = function makeBrowserTree(options, destinationPath) { return funnels; } + + if (modules.angular2_material || modules.benchmarks || modules.benchmarks_external || + modules.playground) { + var assetsTree = new Funnel( + modulesTree, {include: ['**/*'], exclude: ['**/*.{html,ts,dart}'], destDir: '/'}); + } + var htmlTree = new Funnel( modulesTree, {include: ['*/src/**/*.html', '**/playground/**/*.html'], destDir: '/'}); - htmlTree = replace(htmlTree, { - files: ['playground*/**/*.html'], - patterns: [ - {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS')}, - scriptPathPatternReplacement, - scriptFilePatternReplacement - ] - }); + if (modules.benchmarks || modules.benchmarks_external || modules.playground) { + htmlTree = replace(htmlTree, { + files: ['playground*/**/*.html'], + patterns: [ + {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS')}, + scriptPathPatternReplacement, + scriptFilePatternReplacement + ] + }); + } - htmlTree = replace(htmlTree, { - files: ['benchmarks/**'], - patterns: [ - {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks')}, - scriptPathPatternReplacement, - scriptFilePatternReplacement - ] - }); + if (modules.benchmarks) { + htmlTree = replace(htmlTree, { + files: ['benchmarks/**'], + patterns: [ + {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks')}, + scriptPathPatternReplacement, + scriptFilePatternReplacement + ] + }); + } - htmlTree = replace(htmlTree, { - files: ['benchmarks_external/**'], - patterns: [ - {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks_external')}, - scriptPathPatternReplacement, - scriptFilePatternReplacement - ] - }); + if (modules.benchmarks_external) { + htmlTree = replace(htmlTree, { + files: ['benchmarks_external/**'], + patterns: [ + {match: /\$SCRIPTS\$/, replacement: htmlReplace('SCRIPTS_benchmarks_external')}, + scriptPathPatternReplacement, + scriptFilePatternReplacement + ] + }); + } - // We need to replace the regular angular bundle with the web-worker bundle - // for web-worker e2e tests. - htmlTree = replace(htmlTree, { - files: ['playground*/**/web_workers/**/*.html'], - patterns: [{match: "/bundle/angular2.dev.js", replacement: "/bundle/web_worker/ui.dev.js"}] - }); + if (modules.playground) { + // We need to replace the regular angular bundle with the web-worker bundle + // for web-worker e2e tests. + htmlTree = replace(htmlTree, { + files: ['playground*/**/web_workers/**/*.html'], + patterns: [{match: "/bundle/angular2.dev.js", replacement: "/bundle/web_worker/ui.dev.js"}] + }); + } - var assetsTree = - new Funnel(modulesTree, {include: ['**/*'], exclude: ['**/*.{html,ts,dart}'], destDir: '/'}); + if (modules.benchmarks || modules.benchmarks_external) { + var scripts = mergeTrees(servingTrees); + } - var scripts = mergeTrees(servingTrees); - var polymerFiles = new Funnel('.', { - files: [ - 'bower_components/polymer/polymer.html', - 'bower_components/polymer/polymer-micro.html', - 'bower_components/polymer/polymer-mini.html', - 'tools/build/snippets/url_params_to_form.js' - ] - }); - var polymer = stew.mv(flatten(polymerFiles), 'benchmarks_external/src/tree/polymer'); + if (modules.benchmarks_external) { + var polymerFiles = new Funnel('.', { + files: [ + 'bower_components/polymer/polymer.html', + 'bower_components/polymer/polymer-micro.html', + 'bower_components/polymer/polymer-mini.html', + 'tools/build/snippets/url_params_to_form.js' + ] + }); + var polymer = stew.mv(flatten(polymerFiles), 'benchmarks_external/src/tree/polymer'); - var reactFiles = new Funnel('.', {files: ['node_modules/react/dist/react.min.js']}); - var react = stew.mv(flatten(reactFiles), 'benchmarks_external/src/tree/react'); + var reactFiles = new Funnel('.', {files: ['node_modules/react/dist/react.min.js']}); + var react = stew.mv(flatten(reactFiles), 'benchmarks_external/src/tree/react'); + } - htmlTree = mergeTrees([htmlTree, scripts, polymer, react]); + if (modules.benchmarks || modules.benchmarks_external || modules.playground) { + htmlTree = mergeTrees([htmlTree, scripts, polymer, react]); + } es5Tree = mergeTrees([es5Tree, htmlTree, assetsTree, clientModules]); es6Tree = mergeTrees([es6Tree, htmlTree, assetsTree, clientModules]); diff --git a/tools/broccoli/trees/node_tree.ts b/tools/broccoli/trees/node_tree.ts index 3ff5f7c1f8e6..ef45433c5cfb 100644 --- a/tools/broccoli/trees/node_tree.ts +++ b/tools/broccoli/trees/node_tree.ts @@ -12,7 +12,7 @@ var stew = require('broccoli-stew'); var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..', '..')); -module.exports = function makeNodeTree(destinationPath) { +module.exports = function makeNodeTree(projects, destinationPath) { // list of npm packages that this build will create var outputPackages = ['angular2', 'benchpress'];