From a3decad4c2646bc120b0dcee1e2c86f365458109 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 10 Apr 2015 14:30:35 -0700 Subject: [PATCH] feat(build): Use broccoli for ts2dart transpilation. --- Brocfile-dart.js | 43 ++++++++++++++++++++++ gulpfile.js | 11 +++--- modules/angular2/globals.dart | 2 ++ package.json | 3 +- tools/broccoli/broccoli-ts2dart.ts | 56 +++++++++++++++++++++++++++++ tools/broccoli/broccoli-writer.d.ts | 2 +- tools/broccoli/ts2dart.d.ts | 14 ++++++++ 7 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 Brocfile-dart.js create mode 100644 modules/angular2/globals.dart create mode 100644 tools/broccoli/broccoli-ts2dart.ts create mode 100644 tools/broccoli/ts2dart.d.ts diff --git a/Brocfile-dart.js b/Brocfile-dart.js new file mode 100644 index 0000000000..3bc9d4d33a --- /dev/null +++ b/Brocfile-dart.js @@ -0,0 +1,43 @@ +// Brocfile to transpile sources from TypeScript to Dart using ts2dart. +var Funnel = require('broccoli-funnel'); +var stew = require('broccoli-stew'); +var ts2dart = require('./dist/broccoli/broccoli-ts2dart'); +var path = require('path'); + +// Transpile everything in 'modules'... +var modulesTree = new Funnel('modules', { + include: ['**/*.js', '**/*.ts', '**/*.dart'], // .dart file available means don't translate. + exclude: ['rtts_assert/**/*'], // ... except for the rtts_asserts (don't apply to Dart). + destDir: '/', // Remove the 'modules' prefix. +}); + +// Transpile to dart. +var dartTree = ts2dart.transpile(modulesTree); + +// Move around files to match Dart's layout expectations. +dartTree = stew.rename(dartTree, function(relativePath) { + // If a file matches the `pattern`, insert the given `insertion` as the second path part. + var replacements = [ + {pattern: /^benchmarks\/test\//, insertion: ''}, + {pattern: /^benchmarks\//, insertion: 'web'}, + {pattern: /^benchmarks_external\/test\//, insertion: ''}, + {pattern: /^benchmarks_external\//, insertion: 'web'}, + {pattern: /^example.?\//, insertion: 'web/'}, + {pattern: /^example.?\/test\//, insertion: ''}, + {pattern: /^[^\/]*\/test\//, insertion: ''}, + {pattern: /^./, insertion: 'lib'}, // catch all. + ]; + + for (var i = 0; i < replacements.length; i++) { + var repl = replacements[i]; + if (relativePath.match(repl.pattern)) { + var parts = relativePath.split('/'); + parts.splice(1, 0, repl.insertion); + return path.join.apply(path, parts); + } + } + throw new Error('Failed to match any path', relativePath); +}); + +// Move the tree under the 'dart' folder. +module.exports = stew.mv(dartTree, 'dart'); diff --git a/gulpfile.js b/gulpfile.js index 0a2e9a33c6..e0463d0e19 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -29,7 +29,6 @@ var runServerDartTests = require('./tools/build/run_server_dart_tests'); var sourcemaps = require('gulp-sourcemaps'); var transformCJSTests = require('./tools/build/transformCJSTests'); var tsc = require('gulp-typescript'); -var ts2dart = require('gulp-ts2dart'); var util = require('./tools/build/util'); var bundler = require('./tools/build/bundle'); var replace = require('gulp-replace'); @@ -373,11 +372,8 @@ gulp.task('build/transformCJSTests', function() { .pipe(gulp.dest(CONFIG.dest.js.cjs + '/angular2/test/')); }); -gulp.task('build/transpile.dart', function() { - return gulp.src(CONFIG.transpile.src.dart) - .pipe(ts2dart.transpile()) - .pipe(util.insertSrcFolder(gulpPlugins, CONFIG.srcFolderInsertion.dart)) - .pipe(gulp.dest(CONFIG.dest.dart)); +gulp.task('build/transpile.dart', ['build.broccoli.tools'], function() { + return broccoliBuild(require('./Brocfile-dart.js'), 'dart'); }); // ------------ @@ -720,7 +716,8 @@ gulp.task('test.transpiler.unittest', function() { // Builds all Dart packages, but does not compile them gulp.task('build/packages.dart', function(done) { runSequence( - ['build/transpile.dart', 'build/html.dart', 'build/copy.dart', 'build/multicopy.dart'], + 'build/transpile.dart', // Creates the folder structure needed by subsequent tasks. + ['build/html.dart', 'build/copy.dart', 'build/multicopy.dart'], 'build/format.dart', 'build/pubspec.dart', done diff --git a/modules/angular2/globals.dart b/modules/angular2/globals.dart new file mode 100644 index 0000000000..6f7bcd7000 --- /dev/null +++ b/modules/angular2/globals.dart @@ -0,0 +1,2 @@ +// Globals are provided by lang.dart in Dart. +// This file exists to prevent global.ts from being transpiled. diff --git a/package.json b/package.json index b1803424c2..1c55a6eb74 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "gulp-sourcemaps": "1.3.*", "gulp-template": "^3.0.0", "gulp-traceur": "0.17.*", - "gulp-ts2dart": "^1.0.6", "gulp-typescript": "ivogabe/gulp-typescript#3422fbff06532ccc57368f3b4c8801de8f72ef27", "gulp-webserver": "^0.8.7", "js-yaml": "^3.2.7", @@ -97,7 +96,7 @@ "ternary-stream": "^1.2.3", "through2": "^0.6.1", "typescript": "alexeagle/TypeScript#93dbbe2a2d0b42cefd02ac949e4bc8ab6b5b5823", - "ts2dart": "^0.2.0", + "ts2dart": "^0.3.0", "vinyl": "^0.4.6", "walk-sync": "^0.1.3", "xtend": "^4.0.0", diff --git a/tools/broccoli/broccoli-ts2dart.ts b/tools/broccoli/broccoli-ts2dart.ts new file mode 100644 index 0000000000..70fed135d2 --- /dev/null +++ b/tools/broccoli/broccoli-ts2dart.ts @@ -0,0 +1,56 @@ +/// +/// +/// + +import Writer = require('broccoli-writer'); +import fs = require('fs'); +import fse = require('fs-extra'); +import path = require('path'); +import ts2dart = require('ts2dart'); + +type Set = { + [s:string]: boolean +}; + +class TypeScriptToDartTranspiler extends Writer { + constructor(private inputTree, private includePattern = /\.(js|ts)$/) { super(); } + + write(readTree, destDir): Promise { + return readTree(this.inputTree).then(dir => this.transpile(dir, destDir)); + } + + private transpile(inputDir: string, destDir: string) { + var files = this.listRecursive(inputDir); + var toTranspile = []; + for (var f in files) { + // If it's not matching, don't translate. + if (!f.match(this.includePattern)) continue; + var dartVariant = f.replace(this.includePattern, '.dart'); + // A .dart file of the same name takes precedence over transpiled code. + if (files.hasOwnProperty(dartVariant)) continue; + toTranspile.push(f); + } + var transpiler = new ts2dart.Transpiler( + {generateLibraryName: true, generateSourceMap: false, basePath: inputDir}); + transpiler.transpile(toTranspile, destDir); + } + + private listRecursive(root: string, res: Set = {}): Set { + var paths = fs.readdirSync(root); + paths.forEach((p) => { + p = path.join(root, p); + var stat = fs.statSync(p); + if (stat.isDirectory()) { + this.listRecursive(p, res); + } else { + // Collect *all* files so we can check .dart files that already exist and exclude them. + res[p] = true; + } + }); + return res; + } +} + +export function transpile(inputTree) { + return new TypeScriptToDartTranspiler(inputTree); +} diff --git a/tools/broccoli/broccoli-writer.d.ts b/tools/broccoli/broccoli-writer.d.ts index ee2555c5d5..1505e4745d 100644 --- a/tools/broccoli/broccoli-writer.d.ts +++ b/tools/broccoli/broccoli-writer.d.ts @@ -2,7 +2,7 @@ declare class Writer { - write(readTree: (tree) => Promise, destDir: string); + write(readTree: (tree) => Promise, destDir: string): Promise; } export = Writer; diff --git a/tools/broccoli/ts2dart.d.ts b/tools/broccoli/ts2dart.d.ts new file mode 100644 index 0000000000..5b93f4cc60 --- /dev/null +++ b/tools/broccoli/ts2dart.d.ts @@ -0,0 +1,14 @@ +// TODO(martinprobst): This is a hand-written declarations file. Replace with an automatically +// generated one when TypeScript has a strategy to distribute TS source via npm. + +export interface TranspilerOptions { + failFast?: boolean; + generateLibraryName?: boolean; + generateSourceMap?: boolean; + basePath?: string; +} + +export class Transpiler{ + constructor(options: TranspilerOptions); + transpile(fileNames: string[], outdir?: string); +}