angular-cn/gulpfile.js

374 lines
10 KiB
JavaScript

var benchpress = require('angular-benchpress/lib/cli');
var es = require('event-stream');
var file2moduleName = require('./file2modulename');
var fs = require('fs');
var glob = require('glob');
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var merge = require('merge');
var mergeStreams = require('event-stream').merge;
var path = require('path');
var Q = require('q');
var readline = require('readline');
var runSequence = require('run-sequence');
var spawn = require('child_process').spawn;
var through2 = require('through2');
var js2es5Options = {
sourceMaps: true,
annotations: true, // parse annotations
types: true, // parse types
script: false, // parse as a module
memberVariables: true, // parse class fields
modules: 'instantiate'
};
var js2es5OptionsProd = merge(true, js2es5Options, {
typeAssertions: false
});
var js2es5OptionsDev = merge(true, js2es5Options, {
typeAssertionModule: 'rtts_assert/rtts_assert',
typeAssertions: true
});
var js2dartOptions = {
sourceMaps: true,
annotations: true, // parse annotations
types: true, // parse types
script: false, // parse as a module
memberVariables: true, // parse class fields
outputLanguage: 'dart'
};
var PUB_CMD = process.platform === 'win32' ? 'pub.bat' : 'pub';
var gulpTraceur = require('./tools/transpiler/gulp-traceur');
// ---------
// traceur runtime
gulp.task('jsRuntime/build', function() {
var traceurRuntime = gulp.src([
gulpTraceur.RUNTIME_PATH,
"node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js",
"node_modules/systemjs/dist/system.src.js",
"node_modules/systemjs/lib/extension-register.js"
]).pipe(gulp.dest('build/js'));
return traceurRuntime;
});
// -----------------------
// modules
var sourceTypeConfigs = {
dart: {
transpileSrc: ['modules/**/*.js'],
// pub serve uses project_root/web for static serving.
htmlSrc: ['modules/*/src/**/*.html', 'modules/*/web/*.html'],
copySrc: ['modules/**/*.dart'],
outputDir: 'build/dart',
outputExt: 'dart',
mimeType: 'application/dart'
},
js: {
transpileSrc: ['modules/**/*.js', 'modules/**/*.es6'],
htmlSrc: ['modules/*/src/**/*.html'],
copySrc: ['modules/**/*.es5'],
outputDir: 'build/js',
outputExt: 'js'
}
};
gulp.task('modules/clean', function() {
return gulp.src('build', {read: false})
.pipe($.rimraf());
});
gulp.task('modules/build.dart/src', function() {
return createModuleTask(merge(sourceTypeConfigs.dart, {compilerOptions: js2dartOptions}));
});
gulp.task('modules/build.dart/pubspec', function() {
var outputDir = sourceTypeConfigs.dart.outputDir;
var files = [];
var changedStream = gulp.src('modules/*/pubspec.yaml')
.pipe($.changed(outputDir)) // Only forward files that changed.
.pipe(through2.obj(function(file, enc, done) {
files.push(path.resolve(process.cwd(), outputDir, file.relative));
this.push(file);
done();
}))
.pipe(gulp.dest(outputDir));
// We need to wait for all pubspecs to be present before executing
// `pub get` as it checks the folders of the dependencies!
return streamToPromise(changedStream)
.then(function() {
return Q.all(files.map(function(file) {
return processToPromise(spawn(PUB_CMD, ['get'], {
stdio: 'inherit',
cwd: path.dirname(file)
}));
}));
});
});
function processToPromise(process) {
var defer = Q.defer();
process.on('close', function(code) {
if (code) {
defer.reject(code);
} else {
defer.resolve();
}
});
return defer.promise;
}
function streamToPromise(stream) {
var defer = Q.defer();
stream.on('end', defer.resolve);
stream.on('error', defer.reject);
return defer.promise;
}
gulp.task('modules/build.dart', ['modules/build.dart/src', 'modules/build.dart/pubspec']);
gulp.task('modules/build.dev.js', function() {
return createModuleTask(merge(true, sourceTypeConfigs.js, {compilerOptions: js2es5OptionsDev}));
});
gulp.task('modules/build.prod.js', function() {
return createModuleTask(merge(true, sourceTypeConfigs.js, {compilerOptions: js2es5OptionsProd}));
});
function renameSrcToLib(file) {
file.dirname = file.dirname.replace(/\bsrc\b/, 'lib');
}
function renameEs5ToJs(file) {
if (file.extname == '.es5') {
file.extname = '.js';
}
}
function createModuleTask(sourceTypeConfig) {
var transpile = gulp.src(sourceTypeConfig.transpileSrc)
.pipe($.rename({extname: '.'+sourceTypeConfig.outputExt}))
.pipe($.rename(renameSrcToLib))
.pipe(gulpTraceur(sourceTypeConfig.compilerOptions, file2moduleName))
.pipe(gulp.dest(sourceTypeConfig.outputDir));
var copy = gulp.src(sourceTypeConfig.copySrc)
.pipe($.rename(renameSrcToLib))
.pipe($.rename(renameEs5ToJs))
.pipe(gulp.dest(sourceTypeConfig.outputDir));
// TODO: provide the list of files to the template
// automatically!
var html = gulp.src(sourceTypeConfig.htmlSrc)
.pipe($.rename(renameSrcToLib))
.pipe($.ejs({
type: sourceTypeConfig.outputExt
}))
.pipe(gulp.dest(sourceTypeConfig.outputDir));
return mergeStreams(transpile, copy, html);
}
// ------------------
// ANALYZE
gulp.task('analyze/dartanalyzer', function(done) {
var pubSpecs = [].slice.call(glob.sync('build/dart/*/pubspec.yaml', {
cwd: __dirname
}));
var tempFile = '_analyzer.dart';
// analyze in parallel!
return Q.all(pubSpecs.map(function(pubSpecFile) {
var dir = path.dirname(pubSpecFile);
var srcFiles = [].slice.call(glob.sync('lib/**/*.dart', {
cwd: dir
}));
var testFiles = [].slice.call(glob.sync('test/**/*_spec.dart', {
cwd: dir
}));
var analyzeFile = ['library _analyzer;'];
srcFiles.concat(testFiles).forEach(function(fileName, index) {
if (fileName !== tempFile) {
analyzeFile.push('import "./'+fileName+'" as mod'+index+';');
}
});
fs.writeFileSync(path.join(dir, tempFile), analyzeFile.join('\n'));
var defer = Q.defer();
analyze(dir, defer.makeNodeResolver());
return defer.promise;
}));
function analyze(dirName, done) {
var dartanalyzerCmd = (process.platform === "win32" ? "dartanalyzer.bat" : "dartanalyzer");
var stream = spawn(dartanalyzerCmd, ['--fatal-warnings', tempFile], {
// inherit stdin and stderr, but filter stdout
stdio: [process.stdin, 'pipe', process.stderr],
cwd: dirName
});
// Filter out unused imports from our generated file.
// We don't reexports from the generated file
// as this could lead to name clashes when two files
// export the same thing.
var rl = readline.createInterface({
input: stream.stdout,
output: process.stdout,
terminal: false
});
var hintCount = 0;
rl.on('line', function(line) {
if (line.match(/Unused import/)) {
return;
}
if (line.match(/\[hint\]/)) {
hintCount++;
}
console.log(dirName + ':' + line);
});
stream.on('close', function(code) {
var error;
if (code !== 0) {
error = new Error('Dartanalyzer failed with exit code ' + code);
}
if (hintCount > 0) {
error = new Error('Dartanalyzer showed hints');
}
done(error);
});
}
});
// ------------------
// BENCHMARKS JS
gulp.task('benchmarks/internal.benchpress.js', function () {
benchpress.build({
benchmarksPath: 'build/js/benchmarks/lib',
buildPath: 'build/benchpress/js'
})
});
gulp.task('benchmarks/external.benchpress.js', function () {
benchpress.build({
benchmarksPath: 'build/js/benchmarks_external/lib',
buildPath: 'build/benchpress/js'
})
});
gulp.task('benchmarks/internal.js', function() {
runSequence(
['jsRuntime/build', 'modules/build.prod.js'],
'benchmarks/internal.benchpress.js'
);
});
gulp.task('benchmarks/external.js', function() {
runSequence(
['jsRuntime/build', 'modules/build.prod.js'],
'benchmarks/external.benchpress.js'
);
});
// ------------------
// BENCHMARKS DART
function benchmarkDart2Js(buildPath, done) {
mergeStreams(dart2jsStream(), bpConfStream())
.on('end', function() {
runBenchpress();
done();
});
function dart2jsStream() {
return gulp.src([
buildPath+"/lib/**/benchmark.dart"
]).pipe($.shell(['dart2js --package-root="'+buildPath+'/packages" -o "<%= file.path %>.js" <%= file.path %>']));
}
function bpConfStream() {
var bpConfContent = "module.exports = function(c) {c.set({scripts: [{src: 'benchmark.dart.js'}]});}";
var createBpConfJs = es.map(function(file, cb) {
var dir = path.dirname(file.path);
fs.writeFileSync(path.join(dir, "bp.conf.js"), bpConfContent);
cb();
});
return gulp.src([
buildPath+"/lib/**/benchmark.dart"
]).pipe(createBpConfJs);
}
function runBenchpress() {
benchpress.build({
benchmarksPath: buildPath+'/lib',
buildPath: 'build/benchpress/dart'
});
}
}
gulp.task('benchmarks/internal.dart', ['modules/build.dart'], function(done) {
benchmarkDart2Js('build/dart/benchmarks', done);
});
gulp.task('benchmarks/external.dart', ['modules/build.dart'], function(done) {
benchmarkDart2Js('build/dart/benchmarks_external', done);
});
gulp.task('benchmarks/build.dart', ['benchmarks/internal.dart', 'benchmarks/external.dart']);
// ------------------
// WEB SERVERS
gulp.task('serve', function() {
$.connect.server({
root: [__dirname+'/build'],
port: 8000,
livereload: false,
open: false,
middleware: function() {
return [function(req, resp, next){
if (req.url.match(/\.dart$/)) {
resp.setHeader("Content-Type", "application/dart");
}
next();
}];
}
})();
});
gulp.task('examples/pub.serve', function(done) {
spawn(PUB_CMD, ['serve'], {cwd: 'build/dart/examples', stdio: 'inherit'})
.on('done', done);
});
// --------------
// general targets
gulp.task('clean', ['modules/clean']);
gulp.task('build', function(done) {
runSequence(
// parallel
['jsRuntime/build', 'modules/build.dart', 'modules/build.dev.js'],
// sequential
'analyze/dartanalyzer'
);
});
gulp.task('analyze', function(done) {
runSequence('analyze/dartanalyzer');
});