From 96e387b1968a36a2ad6105a5ddf7c2c5d83f6cf1 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Mon, 1 Feb 2016 14:56:07 -0800 Subject: [PATCH 001/108] fix(test): Move e2e tests from deprecated Dart unittest package to test package --- test/e2e/helloworld.ts | 4 ++-- test/e2e/pubspec.yaml | 2 +- test/e2e/{unittest.d.ts => test.d.ts} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename test/e2e/{unittest.d.ts => test.d.ts} (75%) diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index 0eb963c..a25b251 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,5 +1,5 @@ -/// -import t = require("unittest/unittest"); +/// +import t = require("test/test"); import {MyClass, MySubclass, SomeArray} from './lib'; diff --git a/test/e2e/pubspec.yaml b/test/e2e/pubspec.yaml index 181663f..cebfd21 100644 --- a/test/e2e/pubspec.yaml +++ b/test/e2e/pubspec.yaml @@ -2,4 +2,4 @@ name: e2e description: Transpiled end-to-end tests for ts2dart. dependencies: - unittest: any + test: 0.12.8 diff --git a/test/e2e/unittest.d.ts b/test/e2e/test.d.ts similarity index 75% rename from test/e2e/unittest.d.ts rename to test/e2e/test.d.ts index 71050d4..1e9dd66 100644 --- a/test/e2e/unittest.d.ts +++ b/test/e2e/test.d.ts @@ -1,4 +1,4 @@ -declare module 'unittest/unittest' { +declare module 'test/test' { function test(msg: string, fn: () => void); function expect(a: any, b: any); function equals(a: any): any; From 78914a0aee9243d769f40852fe772c82e70135d0 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Sun, 31 Jan 2016 11:47:38 -0800 Subject: [PATCH 002/108] feat: add .idea/ as an IDE file to ignore in gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c894330..59da8ce 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ node_modules # Users Environment Variables .lock-wscript + +# IDEs +.idea/ From f03eeb87ab704b79dbfe69fc40a3cf823b6b0937 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 1 Feb 2016 09:16:13 -0800 Subject: [PATCH 003/108] feat(): Support for-of statements. --- lib/statement.ts | 9 +++++++++ test/statement_test.ts | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/statement.ts b/lib/statement.ts index 5d37b3f..7cf9ca1 100644 --- a/lib/statement.ts +++ b/lib/statement.ts @@ -91,6 +91,15 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit(')'); this.visit(forInStmt.statement); break; + case ts.SyntaxKind.ForOfStatement: + var forOfStmt = node; + this.emit('for ('); + if (forOfStmt.initializer) this.visit(forOfStmt.initializer); + this.emit('in'); + this.visit(forOfStmt.expression); + this.emit(')'); + this.visit(forOfStmt.statement); + break; case ts.SyntaxKind.WhileStatement: var whileStmt = node; this.emit('while ('); diff --git a/test/statement_test.ts b/test/statement_test.ts index bdc91e8..c277c84 100644 --- a/test/statement_test.ts +++ b/test/statement_test.ts @@ -33,6 +33,14 @@ describe('statements', () => { }`); expectTranslate('for (x in 1) { 2 }').to.equal(`for (x in 1) { 2; +}`); + }); + it('translates for-of loops', () => { + expectTranslate('for (var x of 1) { 2 }').to.equal(`for (var x in 1) { + 2; +}`); + expectTranslate('for (x of 1) { 2 }').to.equal(`for (x in 1) { + 2; }`); }); it('translates while loops', () => { From 93e4ee565f8c55ff11642c63c5b1c38cde01408d Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Tue, 26 Jan 2016 18:31:02 -0800 Subject: [PATCH 004/108] Integrate Dart Formatter directly into ts2dart for cleaner output and more readable test cases. --- gulpfile.js | 8 +- lib/base.ts | 9 +- lib/expression.ts | 2 + lib/facade_converter.ts | 2 +- lib/main.ts | 14 +- package.json | 3 +- test/call_test.ts | 63 ++++--- test/declaration_test.ts | 169 +++++++++++------- test/decorator_test.ts | 70 +++++--- test/expression_test.ts | 100 ++++++----- test/facade_converter_test.ts | 316 ++++++++++++++++++++-------------- test/function_test.ts | 41 +++-- test/literal_test.ts | 64 +++---- test/main_test.ts | 59 +++---- test/module_test.ts | 29 ++-- test/statement_test.ts | 100 ++++++++--- test/test_support.ts | 5 + test/type_test.ts | 35 ++-- 18 files changed, 655 insertions(+), 434 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 9fd2fc5..c0923f5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -12,6 +12,7 @@ var sourcemaps = require('gulp-sourcemaps'); var spawn = require('child_process').spawn; var ts = require('gulp-typescript'); var typescript = require('typescript'); +var style = require('dart-style'); var which = require('which'); gulp.task('test.check-format', function() { @@ -54,7 +55,10 @@ gulp.task('test.compile', ['compile'], function(done) { done(); return; } - return gulp.src(['test/*.ts', 'typings/**/*.d.ts'], {base: '.'}) + return gulp + .src( + ['test/*.ts', 'typings/**/*.d.ts', 'node_modules/dart-style/dart-style.d.ts'], + {base: '.'}) .pipe(sourcemaps.init()) .pipe(ts(tsProject)) .on('error', onError) @@ -84,7 +88,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { // run node with a shell so we can wildcard all the .ts files var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + - '*.ts angular2/src/facade/lang.d.ts'; + '*.ts angular2/src/facade/lang.d.ts'; // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { if (code > 0) { diff --git a/lib/base.ts b/lib/base.ts index 85365a6..5c21ee4 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -62,10 +62,11 @@ export class TranspilerBase { } isConst(decl: ClassLike) { - return this.hasAnnotation(decl.decorators, 'CONST') || decl.members.some((m) => { - if (m.kind !== ts.SyntaxKind.Constructor) return false; - return this.hasAnnotation(m.decorators, 'CONST'); - }); + return this.hasAnnotation(decl.decorators, 'CONST') || + (>decl.members).some((m) => { + if (m.kind !== ts.SyntaxKind.Constructor) return false; + return this.hasAnnotation(m.decorators, 'CONST'); + }); } getRelativeFileName(fileName: string): string { diff --git a/lib/expression.ts b/lib/expression.ts index a2d7ba7..9d974ea 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -24,6 +24,8 @@ export default class ExpressionTranspiler extends base.TranspilerBase { if (operatorKind === ts.SyntaxKind.InstanceOfKeyword) { this.emit('is'); this.fc.visitTypeName(binExpr.right); + } else if (operatorKind == ts.SyntaxKind.InKeyword) { + this.reportError(node, 'in operator is unsupported'); } else { this.emit(ts.tokenToString(binExpr.operatorToken.kind)); this.visit(binExpr.right); diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 6d01a61..619fef9 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -197,7 +197,7 @@ export class FacadeConverter extends base.TranspilerBase { private reportMissingType(n: ts.Node, ident: string) { this.reportError( n, `Untyped property access to "${ident}" which could be ` + `a special ts2dart builtin. ` + - `Please add type declarations to disambiguate.`); + `Please add type declarations to disambiguate.`); } isInsideConstExpr(node: ts.Node): boolean { diff --git a/lib/main.ts b/lib/main.ts index ffbf672..bd1f69f 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -14,6 +14,7 @@ import StatementTranspiler from './statement'; import TypeTranspiler from './type'; import LiteralTranspiler from './literal'; import {FacadeConverter} from './facade_converter'; +import * as dartStyle from 'dart-style'; export interface TranspilerOptions { /** @@ -173,7 +174,16 @@ export class Transpiler { new Output(sourceFile, this.getRelativeFileName(), this.options.generateSourceMap); this.lastCommentIdx = -1; this.visit(sourceFile); - return this.output.getResult(); + var result = this.output.getResult(); + return this.formatCode(result, sourceFile); + } + + private formatCode(code: string, context: ts.Node) { + var result = dartStyle.formatCode(code); + if (result.error) { + this.reportError(context, result.error); + } + return result.code; } private checkForErrors(program: ts.Program) { @@ -324,7 +334,7 @@ class Output { } } - getResult(): string { return this.result + this.generateSourceMapComment(); } + getResult(): string { return this.result; } addSourceMapping(n: ts.Node) { if (!this.sourceMap) return; // source maps disabled. diff --git a/package.json b/package.json index 54a1343..92cbed2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "test": "test" }, "dependencies": { + "dart-style": "^0.2.6", "minimist": "^1.1.1", "source-map": "^0.4.2", "source-map-support": "^0.3.1", @@ -15,7 +16,7 @@ }, "devDependencies": { "chai": "^2.1.1", - "clang-format": "^1.0.25", + "clang-format": "^1.0.34", "fs-extra": "^0.18.0", "gulp": "^3.8.11", "gulp-clang-format": "^1.0.21", diff --git a/test/call_test.ts b/test/call_test.ts index 6bc6852..a8521af 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -4,50 +4,59 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('calls', () => { it('translates destructuring parameters', () => { expectTranslate('function x({p = null, d = false} = {}) {}') - .to.equal(' x ( { p : null , d : false } ) { }'); + .to.equal('x({p: null, d: false}) {}'); expectErroneousCode('function x({a=false}={a:true})') .to.throw('initializers for named parameters must be empty object literals'); expectErroneousCode('function x({a=false}=true)') .to.throw('initializers for named parameters must be empty object literals'); - expectTranslate('class X { constructor() { super({p: 1}); } }') - .to.equal( - ' class X { X ( ) : super ( p : 1 ) {' + - ' /* super call moved to initializer */ ; } }'); + expectTranslate('class X { constructor() { super({p: 1}); } }').to.equal(`class X { + X() : super(p: 1) { + /* super call moved to initializer */; + } +}`); }); it('hacks last object literal parameters into named parameter', () => { - expectTranslate('f(x, {a: 12, b: 4});').to.equal(' f ( x , a : 12 , b : 4 ) ;'); - expectTranslate('f({a: 12});').to.equal(' f ( a : 12 ) ;'); - expectTranslate('f({"a": 12});').to.equal(' f ( { "a" : 12 } ) ;'); - expectTranslate('new X(x, {a: 12, b: 4});').to.equal(' new X ( x , a : 12 , b : 4 ) ;'); - expectTranslate('f(x, {});').to.equal(' f ( x , { } ) ;'); + expectTranslate('f(x, {a: 12, b: 4});').to.equal('f(x, a: 12, b: 4);'); + expectTranslate('f({a: 12});').to.equal('f(a: 12);'); + expectTranslate('f({"a": 12});').to.equal('f({"a": 12});'); + expectTranslate('new X(x, {a: 12, b: 4});').to.equal('new X(x, a: 12, b: 4);'); + expectTranslate('f(x, {});').to.equal('f(x, {});'); }); it('translates calls', () => { - expectTranslate('foo();').to.equal(' foo ( ) ;'); - expectTranslate('foo(1, 2);').to.equal(' foo ( 1 , 2 ) ;'); + expectTranslate('foo();').to.equal('foo();'); + expectTranslate('foo(1, 2);').to.equal('foo(1, 2);'); }); it('translates new calls', () => { - expectTranslate('new Foo();').to.equal(' new Foo ( ) ;'); - expectTranslate('new Foo(1, 2);').to.equal(' new Foo ( 1 , 2 ) ;'); - expectTranslate('new Foo(1, 2);') - .to.equal(' new Foo < num , String > ( 1 , 2 ) ;'); + expectTranslate('new Foo();').to.equal('new Foo();'); + expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); + expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); }); it('throws away generic type parameters', - () => { expectTranslate('var s = foo();').to.equal(' var s = foo ( ) ;'); }); + () => { expectTranslate('var s = foo();').to.equal('var s = foo();'); }); it('translates "super()" constructor calls', () => { - expectTranslate('class X { constructor() { super(1); } }') - .to.equal(' class X { X ( ) : super ( 1 ) { /* super call moved to initializer */ ; } }'); + expectTranslate('class X { constructor() { super(1); } }').to.equal(`class X { + X() : super(1) { + /* super call moved to initializer */; + } +}`); expectErroneousCode('class X { constructor() { if (y) super(1, 2); } }') .to.throw('super calls must be immediate children of their constructors'); - expectTranslate('class X { constructor() { a(); super(1); b(); } }') - .to.equal( - ' class X { X ( ) : super ( 1 ) {' + - ' a ( ) ; /* super call moved to initializer */ ; b ( ) ;' + - ' } }'); + expectTranslate('class X { constructor() { a(); super(1); b(); } }').to.equal(`class X { + X() : super(1) { + a(); + /* super call moved to initializer */ + ; + b(); + } +}`); }); it('translates "super.x()" super method calls', () => { - expectTranslate('class X { y() { super.z(1); } }') - .to.equal(' class X { y ( ) { super . z ( 1 ) ; } }'); + expectTranslate('class X { y() { super.z(1); } }').to.equal(`class X { + y() { + super.z(1); + } +}`); }); it('transpiles new calls without arguments', - () => { expectTranslate('new Foo;').to.equal(' new Foo ( ) ;'); }); + () => { expectTranslate('new Foo;').to.equal('new Foo();'); }); }); diff --git a/test/declaration_test.ts b/test/declaration_test.ts index 41a4c2d..bcbfab3 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -3,20 +3,20 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('variables', () => { it('should print variable declaration with initializer', - () => { expectTranslate('var a:number = 1;').to.equal(' num a = 1 ;'); }); + () => { expectTranslate('var a:number = 1;').to.equal('num a = 1;'); }); it('should print variable declaration', () => { - expectTranslate('var a:number;').to.equal(' num a ;'); - expectTranslate('var a;').to.equal(' var a ;'); - expectTranslate('var a:any;').to.equal(' dynamic a ;'); + expectTranslate('var a:number;').to.equal('num a;'); + expectTranslate('var a;').to.equal('var a;'); + expectTranslate('var a:any;').to.equal('dynamic a;'); }); it('should transpile variable declaration lists', () => { - expectTranslate('var a: A;').to.equal(' A a ;'); - expectTranslate('var a, b;').to.equal(' var a , b ;'); + expectTranslate('var a: A;').to.equal('A a;'); + expectTranslate('var a, b;').to.equal('var a, b;'); }); it('should transpile variable declaration lists with initializers', () => { - expectTranslate('var a = 0;').to.equal(' var a = 0 ;'); - expectTranslate('var a, b = 0;').to.equal(' var a , b = 0 ;'); - expectTranslate('var a = 1, b = 0;').to.equal(' var a = 1 , b = 0 ;'); + expectTranslate('var a = 0;').to.equal('var a = 0;'); + expectTranslate('var a, b = 0;').to.equal('var a, b = 0;'); + expectTranslate('var a = 1, b = 0;').to.equal('var a = 1, b = 0;'); }); it('does not support vardecls containing more than one type (implicit or explicit)', () => { var msg = 'Variables in a declaration list of more than one variable cannot by typed'; @@ -27,39 +27,48 @@ describe('variables', () => { }); it('supports const', () => { - expectTranslate('const A = 1, B = 2;').to.equal(' const A = 1 , B = 2 ;'); - expectTranslate('const A: number = 1;').to.equal(' const num A = 1 ;'); + expectTranslate('const A = 1, B = 2;').to.equal('const A = 1, B = 2;'); + expectTranslate('const A: number = 1;').to.equal('const num A = 1;'); }); }); describe('classes', () => { - it('should translate classes', () => { expectTranslate('class X {}').to.equal(' class X { }'); }); + it('should translate classes', () => { expectTranslate('class X {}').to.equal('class X {}'); }); it('should support extends', - () => { expectTranslate('class X extends Y {}').to.equal(' class X extends Y { }'); }); + () => { expectTranslate('class X extends Y {}').to.equal('class X extends Y {}'); }); it('should support implements', () => { - expectTranslate('class X implements Y, Z {}').to.equal(' class X implements Y , Z { }'); + expectTranslate('class X implements Y, Z {}').to.equal('class X implements Y, Z {}'); }); it('should support implements', () => { expectTranslate('class X extends Y implements Z {}') - .to.equal(' class X extends Y implements Z { }'); + .to.equal('class X extends Y implements Z {}'); }); it('should support abstract', - () => { expectTranslate('abstract class X {}').to.equal(' abstract class X { }'); }); + () => { expectTranslate('abstract class X {}').to.equal('abstract class X {}'); }); describe('members', () => { it('supports empty declarations', - () => { expectTranslate('class X { ; }').to.equal(' class X { }'); }); + () => { expectTranslate('class X { ; }').to.equal('class X {}'); }); it('supports fields', () => { - expectTranslate('class X { x: number; y: string; }') - .to.equal(' class X { num x ; String y ; }'); - expectTranslate('class X { x; }').to.equal(' class X { var x ; }'); + expectTranslate('class X { x: number; y: string; }').to.equal(`class X { + num x; + String y; +}`); + expectTranslate('class X { x; }').to.equal(`class X { + var x; +}`); }); it('supports field initializers', () => { - expectTranslate('class X { x: number = 42; }').to.equal(' class X { num x = 42 ; }'); + expectTranslate('class X { x: number = 42; }').to.equal(`class X { + num x = 42; +}`); }); // TODO(martinprobst): Re-enable once Angular is migrated to TS. it('supports visibility modifiers', () => { - expectTranslate('class X { private _x; x; }').to.equal(' class X { var _x ; var x ; }'); + expectTranslate('class X { private _x; x; }').to.equal(`class X { + var _x; + var x; +}`); expectErroneousCode('class X { private x; }') .to.throw('private members must be prefixed with "_"'); expectErroneousCode('class X { constructor (private x) {} }') @@ -72,42 +81,63 @@ describe('classes', () => { .to.throw('protected declarations are unsupported'); }); it('supports static fields', () => { - expectTranslate('class X { static x: number = 42; }') - .to.equal(' class X { static num x = 42 ; }'); + expectTranslate('class X { static x: number = 42; }').to.equal(`class X { + static num x = 42; +}`); }); it('supports methods', () => { - expectTranslate('class X { x() { return 42; } }') - .to.equal(' class X { x ( ) { return 42 ; } }'); + expectTranslate('class X { x() { return 42; } }').to.equal(`class X { + x() { + return 42; + } +}`); }); it('supports abstract methods', () => { - expectTranslate('abstract class X { abstract x(); }') - .to.equal(' abstract class X { x ( ) ; }'); + expectTranslate('abstract class X { abstract x(); }').to.equal(`abstract class X { + x(); +}`); }); it('supports method return types', () => { - expectTranslate('class X { x(): number { return 42; } }') - .to.equal(' class X { num x ( ) { return 42 ; } }'); + expectTranslate('class X { x(): number { return 42; } }').to.equal(`class X { + num x() { + return 42; + } +}`); }); it('supports method params', () => { - expectTranslate('class X { x(a, b) { return 42; } }') - .to.equal(' class X { x ( a , b ) { return 42 ; } }'); + expectTranslate('class X { x(a, b) { return 42; } }').to.equal(`class X { + x(a, b) { + return 42; + } +}`); }); it('supports method return types', () => { - expectTranslate('class X { x( a : number, b : string ) { return 42; } }') - .to.equal(' class X { x ( num a , String b ) { return 42 ; } }'); + expectTranslate('class X { x( a : number, b : string ) { return 42; } }').to.equal(`class X { + x(num a, String b) { + return 42; + } +}`); }); it('supports get methods', () => { - expectTranslate('class X { get y(): number {} }').to.equal(' class X { num get y { } }'); - expectTranslate('class X { static get Y(): number {} }') - .to.equal(' class X { static num get Y { } }'); + expectTranslate('class X { get y(): number {} }').to.equal(`class X { + num get y {} +}`); + expectTranslate('class X { static get Y(): number {} }').to.equal(`class X { + static num get Y {} +}`); }); it('supports set methods', () => { - expectTranslate('class X { set y(n: number) {} }') - .to.equal(' class X { set y ( num n ) { } }'); - expectTranslate('class X { static get Y(): number {} }') - .to.equal(' class X { static num get Y { } }'); + expectTranslate('class X { set y(n: number) {} }').to.equal(`class X { + set y(num n) {} +}`); + expectTranslate('class X { static get Y(): number {} }').to.equal(`class X { + static num get Y {} +}`); }); it('supports constructors', () => { - expectTranslate('class X { constructor() { } }').to.equal(' class X { X ( ) { } }'); + expectTranslate('class X { constructor() {} }').to.equal(`class X { + X() {} +}`); }); it('supports parameter properties', () => { expectTranslate( @@ -115,59 +145,70 @@ describe('classes', () => { ' constructor(private _bar: B, ' + 'public foo: string = "hello", ' + 'private _goggles: boolean = true) {} }') - .to.equal( - ' class X { B _bar ; String foo ; bool _goggles ; num c ;' + - ' X ( this . _bar , [ this . foo = \"hello\" , this . _goggles = true ] ) { } }'); + .to.equal(`class X { + B _bar; + String foo; + bool _goggles; + num c; + X(this._bar, [this.foo = "hello", this._goggles = true]) {} +}`); expectTranslate( '@CONST class X { ' + 'constructor(public foo: string, b: number, private _marbles: boolean = true) {} }') - .to.equal( - ' class X { final String foo ; final bool _marbles ;' + - ' const X ( this . foo , num b , [ this . _marbles = true ] ) ; }'); + .to.equal(`class X { + final String foo; + final bool _marbles; + const X(this.foo, num b, [this._marbles = true]); +}`); }); }); }); describe('interfaces', () => { it('translates interfaces to abstract classes', - () => { expectTranslate('interface X {}').to.equal(' abstract class X { }'); }); + () => { expectTranslate('interface X {}').to.equal('abstract class X {}'); }); it('translates interface extends to class implements', () => { - expectTranslate('interface X extends Y, Z {}') - .to.equal(' abstract class X implements Y , Z { }'); + expectTranslate('interface X extends Y, Z {}').to.equal('abstract class X implements Y, Z {}'); + }); + it('supports abstract methods', () => { + expectTranslate('interface X { x(); }').to.equal(`abstract class X { + x(); +}`); }); - it('supports abstract methods', - () => { expectTranslate('interface X { x(); }').to.equal(' abstract class X { x ( ) ; }'); }); it('supports interface properties', () => { - expectTranslate('interface X { x: string; y; }') - .to.equal(' abstract class X { String x ; var y ; }'); + expectTranslate('interface X { x: string; y; }').to.equal(`abstract class X { + String x; + var y; +}`); }); }); describe('single call signature interfaces', () => { it('should support declaration', () => { - expectTranslate('interface F { (n: number): boolean; }') - .to.equal(' typedef bool F ( num n ) ;'); + expectTranslate('interface F { (n: number): boolean; }').to.equal('typedef bool F(num n);'); }); it('should support generics', () => { - expectTranslate('interface F { (a: A): B; }') - .to.equal(' typedef B F < A , B > ( A a ) ;'); + expectTranslate('interface F { (a: A): B; }').to.equal('typedef B F(A a);'); }); }); describe('enums', () => { it('should support basic enum declaration', () => { - expectTranslate('enum Color { Red, Green, Blue }') - .to.equal(' enum Color { Red , Green , Blue }'); + expectTranslate('enum Color { Red, Green, Blue }').to.equal('enum Color { Red, Green, Blue }'); }); it('does not support empty enum', - () => { expectErroneousCode('enum Empty { }').to.throw('empty enums are not supported'); }); + () => { expectErroneousCode('enum Empty {}').to.throw('empty enums are not supported'); }); it('does not support enum with initializer', () => { expectErroneousCode('enum Color { Red = 1, Green, Blue = 4 }') .to.throw('enum initializers are not supported'); }); it('should support switch over enum', () => { - expectTranslate('switch(c) { case Color.Red: break; default: break; }') - .to.equal(' switch ( c ) { case Color . Red : break ; default : break ; }'); + expectTranslate('switch(c) { case Color.Red: break; default: break; }').to.equal(`switch (c) { + case Color.Red: + break; + default: + break; +}`); }); it('does not support const enum', () => { expectErroneousCode('const enum Color { Red }').to.throw('const enums are not supported'); diff --git a/test/decorator_test.ts b/test/decorator_test.ts index eb4a45e..954b2c9 100644 --- a/test/decorator_test.ts +++ b/test/decorator_test.ts @@ -2,38 +2,63 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('decorators', () => { - it('translates plain decorators', - () => { expectTranslate('@A class X {}').to.equal(' @ A class X { }'); }); - it('translates arguments', - () => { expectTranslate('@A(a, b) class X {}').to.equal(' @ A ( a , b ) class X { }'); }); + it('translates plain decorators', () => { + expectTranslate('@A class X {}').to.equal(`@A +class X {}`); + }); + it('translates arguments', () => { + expectTranslate('@A(a, b) class X {}').to.equal(`@A(a, b) +class X {}`); + }); it('translates const arguments', () => { - expectTranslate('@A([1]) class X {}').to.equal(' @ A ( const [ 1 ] ) class X { }'); - expectTranslate('@A({"a": 1}) class X {}').to.equal(' @ A ( const { "a" : 1 } ) class X { }'); - expectTranslate('@A(new B()) class X {}').to.equal(' @ A ( const B ( ) ) class X { }'); + expectTranslate('@A([1]) class X {}').to.equal(`@A(const [1]) +class X {}`); + expectTranslate('@A({"a": 1}) class X {}').to.equal(`@A(const {"a": 1}) +class X {}`); + expectTranslate('@A(new B()) class X {}').to.equal(`@A(const B()) +class X {}`); + }); + it('translates on functions', () => { + expectTranslate('@A function f() {}').to.equal(`@A +f() {}`); + }); + it('translates on properties', () => { + expectTranslate('class X { @A p; }').to.equal(`class X { + @A + var p; +}`); }); - it('translates on functions', - () => { expectTranslate('@A function f() {}').to.equal(' @ A f ( ) { }'); }); - it('translates on properties', - () => { expectTranslate('class X { @A p; }').to.equal(' class X { @ A var p ; }'); }); it('translates on parameters', - () => { expectTranslate('function f (@A p) {}').to.equal(' f ( @ A p ) { }'); }); + () => { expectTranslate('function f (@A p) {}').to.equal('f(@A p) {}'); }); it('special cases @CONST', () => { - expectTranslate('@CONST class X {}').to.equal(' class X { const X (); }'); - expectTranslate('@CONST() class X {}').to.equal(' class X { const X (); }'); + expectTranslate('@CONST class X {}').to.equal(`class X { + const X(); +}`); + expectTranslate('@CONST() class X {}').to.equal(`class X { + const X(); +}`); expectTranslate(`@CONST class X { x: number; y; constructor() { super(3); this.x = 1; this.y = 2; } }`) - .to.equal( - ' class X {' + - ' final num x ; final y ;' + - ' const X ( ) : x = 1 , y = 2 , super ( 3 ) ; }'); + .to.equal(`class X { + final num x; + final y; + const X() + : x = 1, + y = 2, + super(3); +}`); // @CONST constructors. - expectTranslate('@CONST class X { constructor() {} }').to.equal(' class X { const X ( ) ; }'); + expectTranslate('@CONST class X { constructor() {} }').to.equal(`class X { + const X(); +}`); // For backwards-compatibility for traceur inputs (not valid TS input) - expectTranslate('class X { @CONST constructor() {} }').to.equal(' class X { const X ( ) ; }'); + expectTranslate('class X { @CONST constructor() {} }').to.equal(`class X { + const X(); +}`); expectErroneousCode('@CONST class X { constructor() { if (1); } }') .to.throw('const constructors can only contain assignments and super calls'); expectErroneousCode('@CONST class X { constructor() { f(); } }') @@ -46,7 +71,8 @@ describe('decorators', () => { .to.throw('assignments in const constructors must assign into this.'); // @CONST properties. - expectTranslate('class Foo { @CONST() static foo = 1; }') - .to.equal(' class Foo { static const foo = 1 ; }'); + expectTranslate('class Foo { @CONST() static foo = 1; }').to.equal(`class Foo { + static const foo = 1; +}`); }); }); diff --git a/test/expression_test.ts b/test/expression_test.ts index 7d2be31..ed1da8f 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -7,83 +7,89 @@ function expectTranslates(cases: any) { } } +// TODO(jacobr): we don't really need to be specifying separate code for the +// JS and Dart version for these tests as the code formatting is identical. describe('expressions', () => { it('does math', () => { expectTranslates({ - '1 + 2': ' 1 + 2 ;', - '1 - 2': ' 1 - 2 ;', - '1 * 2': ' 1 * 2 ;', - '1 / 2': ' 1 / 2 ;', - '1 % 2': ' 1 % 2 ;', - 'x++': ' x ++ ;', - 'x--': ' x -- ;', - '++x': ' ++ x ;', - '--x': ' -- x ;', - '-x': ' - x ;', + '1 + 2': '1 + 2;', + '1 - 2': '1 - 2;', + '1 * 2': '1 * 2;', + '1 / 2': '1 / 2;', + '1 % 2': '1 % 2;', + 'x++': 'x++;', + 'x--': 'x--;', + '++x': '++x;', + '--x': '--x;', + '-x': '-x;', }); }); it('assigns', () => { expectTranslates({ - 'x += 1': ' x += 1 ;', - 'x -= 1': ' x -= 1 ;', - 'x *= 1': ' x *= 1 ;', - 'x /= 1': ' x /= 1 ;', - 'x %= 1': ' x %= 1 ;', - 'x <<= 1': ' x <<= 1 ;', - 'x >>= 1': ' x >>= 1 ;', - 'x >>>= 1': ' x >>>= 1 ;', - 'x &= 1': ' x &= 1 ;', - 'x ^= 1': ' x ^= 1 ;', - 'x |= 1': ' x |= 1 ;', + 'x += 1': 'x += 1;', + 'x -= 1': 'x -= 1;', + 'x *= 1': 'x *= 1;', + 'x /= 1': 'x /= 1;', + 'x %= 1': 'x %= 1;', + 'x <<= 1': 'x <<= 1;', + 'x >>= 1': 'x >>= 1;', + // 'x >>>= 1': 'x >>>= 1;', // This doesn't appear to be a valid operator in Dart. + 'x &= 1': 'x &= 1;', + 'x ^= 1': 'x ^= 1;', + 'x |= 1': 'x |= 1;', }); }); it('compares', () => { expectTranslates({ - '1 == 2': ' 1 == 2 ;', - '1 != 2': ' 1 != 2 ;', - '1 > 2': ' 1 > 2 ;', - '1 < 2': ' 1 < 2 ;', - '1 >= 2': ' 1 >= 2 ;', - '1 <= 2': ' 1 <= 2 ;', + '1 == 2': '1 == 2;', + '1 != 2': '1 != 2;', + '1 > 2': '1 > 2;', + '1 < 2': '1 < 2;', + '1 >= 2': '1 >= 2;', + '1 <= 2': '1 <= 2;', }); }); it('compares identity', () => { - expectTranslate('1 === 2').to.equal(' identical ( 1 , 2 ) ;'); - expectTranslate('1 !== 2').to.equal(' ! identical ( 1 , 2 ) ;'); + expectTranslate('1 === 2').to.equal('identical(1, 2);'); + expectTranslate('1 !== 2').to.equal('!identical(1, 2);'); }); it('bit fiddles', () => { expectTranslates({ - '1 & 2': ' 1 & 2 ;', - '1 | 2': ' 1 | 2 ;', - '1 ^ 2': ' 1 ^ 2 ;', - '~ 1': ' ~ 1 ;', - '1 << 2': ' 1 << 2 ;', - '1 >> 2': ' 1 >> 2 ;', - '1 >>> 2': ' 1 >>> 2 ;', + '1 & 2': '1 & 2;', + '1 | 2': '1 | 2;', + '1 ^ 2': '1 ^ 2;', + '~1': '~1;', + '1 << 2': '1 << 2;', + '1 >> 2': '1 >> 2;', + // '1 >>> 2': '1 >>> 2;', // This doesn't appear to be a valid operator in Dart. }); }); it('translates logic', () => { expectTranslates({ - '1 && 2': ' 1 && 2 ;', - '1 || 2': ' 1 || 2 ;', - '!1': ' ! 1 ;', + '1 && 2': '1 && 2;', + '1 || 2': '1 || 2;', + '!1': '!1;', }); }); - it('translates ternary', () => { expectTranslate('1 ? 2 : 3').to.equal(' 1 ? 2 : 3 ;'); }); - it('translates the comma operator', () => { expectTranslate('1 , 2').to.equal(' 1 , 2 ;'); }); - it('translates "in"', () => { expectTranslate('1 in 2').to.equal(' 1 in 2 ;'); }); - it('translates "instanceof"', () => { expectTranslate('1 instanceof 2').to.equal(' 1 is 2 ;'); }); - it('translates "this"', () => { expectTranslate('this.x').to.equal(' this . x ;'); }); + it('translates ternary', + () => { expectTranslate('var x = 1 ? 2 : 3').to.equal('var x = 1 ? 2 : 3;'); }); + it('translates the comma operator', + () => { expectTranslate('var x = [1, 2]').to.equal('var x = [1, 2];'); }); + it('translates "in"', + () => { expectErroneousCode('x in y').to.throw('in operator is unsupported'); }); + it('translates "instanceof"', + () => { expectTranslate('1 instanceof Foo').to.equal('1 is Foo;'); }); + it('translates "this"', () => { expectTranslate('this.x').to.equal('this.x;'); }); it('translates "delete"', () => { expectErroneousCode('delete x[y];').to.throw('delete operator is unsupported'); }); it('translates "typeof"', () => { expectErroneousCode('typeof x;').to.throw('typeof operator is unsupported'); }); it('translates "void"', () => { expectErroneousCode('void x;').to.throw('void operator is unsupported'); }); - it('translates parens', () => { expectTranslate('(1)').to.equal(' ( 1 ) ;'); }); + it('translates parens', () => { expectTranslate('(1)').to.equal('(1);'); }); it('translates property paths', () => { - expectTranslate('foo.bar;').to.equal(' foo . bar ;'); - expectTranslate('foo[bar];').to.equal(' foo [ bar ] ;'); + expectTranslate('foo.bar;').to.equal('foo.bar;'); + expectTranslate('foo[bar];').to.equal('foo[bar];'); }); }); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 67618c3..48e696c 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -78,159 +78,219 @@ describe('type based translation', () => { it('finds registered substitutions', () => { expectWithTypes( 'import {Promise, Observable} from "angular2/src/facade/async"; var p: Promise;') - .to.equal( - ' import "package:angular2/src/facade/async.dart" show Future , Stream ; Future < DateTime > p ;'); - expectWithTypes('import {Promise} from "angular2/src/facade/async"; x instanceof Promise;') - .to.equal(' import "package:angular2/src/facade/async.dart" show Future ; x is Future ;'); - expectWithTypes('var n: Node;').to.equal(' dynamic n ;'); - expectWithTypes('var xhr: XMLHttpRequest;') - .to.equal(' import "dart:html"; HttpRequest xhr ;'); - expectWithTypes('var intArray: Uint8Array;') - .to.equal(' import "dart:typed_arrays"; Uint8List intArray ;'); - expectWithTypes('var buff: ArrayBuffer;') - .to.equal(' import "dart:typed_arrays"; ByteBuffer buff ;'); + .to.equal(`import "package:angular2/src/facade/async.dart" show Future, Stream; + +Future p;`); + expectWithTypes( + 'import {Promise} from "angular2/src/facade/async"; var y = x instanceof Promise;') + .to.equal(`import "package:angular2/src/facade/async.dart" show Future; + +var y = x is Future;`); + expectWithTypes('var n: Node;').to.equal('dynamic n;'); + expectWithTypes('var xhr: XMLHttpRequest;').to.equal(`import "dart:html"; + +HttpRequest xhr;`); + expectWithTypes('var intArray: Uint8Array;').to.equal(`import "dart:typed_arrays"; + +Uint8List intArray;`); + expectWithTypes('var buff: ArrayBuffer;').to.equal(`import "dart:typed_arrays"; + +ByteBuffer buff;`); }); - it('allows undeclared types', - () => { expectWithTypes('var t: Thing;').to.equal(' Thing t ;'); }); + it('allows undeclared types', () => { expectWithTypes('var t: Thing;').to.equal('Thing t;'); }); it('does not substitute matching name from different file', () => { - expectWithTypes('import {Promise} from "other/file"; x instanceof Promise;') - .to.equal(' import "package:other/file.dart" show Promise ; x is Promise ;'); + expectWithTypes('import {Promise} from "other/file"; var y = x instanceof Promise;') + .to.equal(`import "package:other/file.dart" show Promise; + +var y = x is Promise;`); }); }); describe('collection façade', () => { it('translates array operations to dartisms', () => { - expectWithTypes('var x: Array = []; x.push(1); x.pop();') - .to.equal(' List < num > x = [ ] ; x . add ( 1 ) ; x . removeLast ( ) ;'); - expectWithTypes('var x: Array = []; x.map((e) => e);') - .to.equal(' List < num > x = [ ] ; x . map ( ( e ) => e ) . toList ( ) ;'); - expectWithTypes('var x: Array = []; x.filter((e) => true);') - .to.equal(' List < num > x = [ ] ; x . where ( ( e ) => true ) . toList ( ) ;'); - expectWithTypes('var x: Array = []; x.unshift(1, 2, 3); x.shift();') - .to.equal( - ' List < num > x = [ ] ; ( x .. insertAll ' + - '( 0, [ 1 , 2 , 3 ]) ) . length ; x . removeAt ( 0 ) ;'); - expectWithTypes('var x: Array = []; x.unshift(1);') - .to.equal(' List < num > x = [ ] ; ( x .. insert ( 0, 1 ) ) . length ;'); - expectWithTypes('var x: Array = []; x.concat([1], x).length;') - .to.equal( - ' List < num > x = [ ] ; ( new List . from ( x ) .. addAll ( [ 1 ] ) .. addAll ( x ) ) . length ;'); + expectWithTypes('function f() { var x: Array = []; x.push(1); x.pop(); }') + .to.equal(`f() { + List x = []; + x.add(1); + x.removeLast(); +}`); + expectWithTypes('function f() { var x: Array = []; x.map((e) => e); }') + .to.equal(`f() { + List x = []; + x.map((e) => e).toList(); +}`); + expectWithTypes('function f() { var x: Array = []; x.filter((e) => true); }') + .to.equal(`f() { + List x = []; + x.where((e) => true).toList(); +}`); + expectWithTypes('function f() { var x: Array = []; x.unshift(1, 2, 3); x.shift(); }') + .to.equal(`f() { + List x = []; + (x..insertAll(0, [1, 2, 3])).length; + x.removeAt(0); +}`); + expectWithTypes('function f() { var x: Array = []; x.unshift(1); }').to.equal(`f() { + List x = []; + (x..insert(0, 1)).length; +}`); + expectWithTypes('function f() { var x: Array = []; x.concat([1], x).length; }') + .to.equal(`f() { + List x = []; + (new List.from(x)..addAll([1])..addAll(x)).length; +}`); expectWithTypes('var x: Array = []; var y: Array = x.slice(0);') - .to.equal(' List < num > x = [ ] ; List < num > y = ListWrapper.slice ( x , 0 ) ;'); + .to.equal(`List x = []; +List y = ListWrapper.slice(x, 0);`); expectWithTypes('var x: Array = []; var y: Array = x.splice(0,1);') - .to.equal(' List < num > x = [ ] ; List < num > y = ListWrapper.splice ( x , 0 , 1 ) ;'); + .to.equal(`List x = []; +List y = ListWrapper.splice(x, 0, 1);`); expectWithTypes('var x: Array = []; var y: string = x.join("-");') - .to.equal(' List < num > x = [ ] ; String y = x . join ( "-" ) ;'); + .to.equal(`List x = []; +String y = x.join("-");`); expectWithTypes('var x: Array = []; var y: string = x.join();') - .to.equal(' List < num > x = [ ] ; String y = x . join ( "," ) ;'); + .to.equal(`List x = []; +String y = x.join(",");`); expectWithTypes('var x: Array = []; var y: number = x.find((e) => e == 0);') - .to.equal( - ' List < num > x = [ ] ; num y = x . firstWhere ( ( e ) => e == 0 , orElse : ( ) => null ) ;'); + .to.equal(`List x = []; +num y = x.firstWhere((e) => e == 0, orElse: () => null);`); expectWithTypes('var x: Array = []; var y: boolean = x.some((e) => e == 0);') - .to.equal(' List < num > x = [ ] ; bool y = x . any ( ( e ) => e == 0 ) ;'); + .to.equal(`List x = []; +bool y = x.any((e) => e == 0);`); expectWithTypes('var x: Array = []; var y: number = x.reduce((a, b) => a + b, 0);') - .to.equal(' List < num > x = [ ] ; num y = x . fold ( 0 , ( a , b ) => a + b ) ;'); + .to.equal(`List x = []; +num y = x.fold(0, (a, b) => a + b);`); expectWithTypes('var x: Array = []; var y: number = x.reduce((a, b) => a + b);') - .to.equal(' List < num > x = [ ] ; num y = x . fold ( null , ( a , b ) => a + b ) ;'); + .to.equal(`List x = []; +num y = x.fold(null, (a, b) => a + b);`); }); it('translates map operations to dartisms', () => { - expectWithTypes('var x = new Map(); x.set("k", "v");') - .to.equal(' var x = new Map < String , String > ( ) ; x [ "k" ] = "v" ;'); - expectWithTypes('var x = new Map(); x.get("k");') - .to.equal(' var x = new Map < String , String > ( ) ; x [ "k" ] ;'); - expectWithTypes('var x = new Map(); x.has("k");') - .to.equal(' var x = new Map < String , String > ( ) ; x . containsKey ( "k" ) ;'); - expectWithTypes('var x = new Map(); x.delete("k");') - .to.equal( - ' var x = new Map < String , String > ( ) ; ' + - '( x . containsKey ( "k" ) && ( x . remove ( "k" ) != null || true ) ) ;'); - expectWithTypes('var x = new Map(); x.forEach((v, k) => null);') - .to.equal( - ' var x = new Map < String , String > ( ) ; ' + - 'x . forEach ( ( k , v ) => null ) ;'); + expectWithTypes('function f() { var x = new Map(); x.set("k", "v"); }') + .to.equal(`f() { + var x = new Map(); + x["k"] = "v"; +}`); + expectWithTypes('function f() { var x = new Map(); x.get("k"); }') + .to.equal(`f() { + var x = new Map(); + x["k"]; +}`); + expectWithTypes('function f() { var x = new Map(); x.has("k"); }') + .to.equal(`f() { + var x = new Map(); + x.containsKey("k"); +}`); + expectWithTypes('function f() { var x = new Map(); x.delete("k"); }') + .to.equal(`f() { + var x = new Map(); + (x.containsKey("k") && (x.remove("k") != null || true)); +}`); + expectWithTypes( + 'function f() { var x = new Map(); x.forEach((v, k) => null); }') + .to.equal(`f() { + var x = new Map(); + x.forEach((k, v) => null); +}`); expectWithTypes( - 'var x = new Map(); x.forEach(function (v, k) { return null; });') - .to.equal( - ' var x = new Map < String , String > ( ) ; ' + - 'x . forEach ( ( k , v ) { return null ; } ) ;'); - expectWithTypes('var x = new Map(); x.forEach((v, k) => { return null; });') - .to.equal( - ' var x = new Map < String , String > ( ) ; ' + - 'x . forEach ( ( k , v ) { return null ; } ) ;'); - - expectWithTypes('var x = new Map(); x.forEach(fn);') - .to.equal( - ' var x = new Map < String , String > ( ) ; ' + - 'x . forEach ( ( k , v ) => ( fn ) ( v , k ) ) ;'); + 'function f() { var x = new Map(); x.forEach(function (v, k) { return null; }); }') + .to.equal(`f() { + var x = new Map(); + x.forEach((k, v) { + return null; + }); +}`); + expectWithTypes( + 'function f() { var x = new Map(); var y = x.forEach((v, k) => { return null; }); }') + .to.equal(`f() { + var x = new Map(); + var y = x.forEach((k, v) { + return null; + }); +}`); + + expectWithTypes('function f() { var x = new Map(); x.forEach(fn); }') + .to.equal(`f() { + var x = new Map(); + x.forEach((k, v) => (fn)(v, k)); +}`); }); it('translates map properties to dartisms', () => { - expectWithTypes('var x = new Map(); x.size;') - .to.equal(' var x = new Map < String , String > ( ) ; x . length ;'); + expectWithTypes('var x = new Map();var y = x.size;') + .to.equal(`var x = new Map(); +var y = x.length;`); }); }); describe('regexp', () => { - expectWithTypes('var x = /a/g; x.test("a");') - .to.equal(' var x = new RegExp ( r\'a\' ) ; x . hasMatch ( "a" ) ;'); + expectWithTypes('function f() { var x = /a/g; x.test("a"); }').to.equal(`f() { + var x = new RegExp(r'a'); + x.hasMatch("a"); +}`); }); - describe('builtin functions', () => { - it('translates CONST_EXPR(...) to const (...)', () => { - expectWithTypes( - 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + - 'const x = CONST_EXPR([]);') - .to.equal(' const x = const [ ] ;'); - expectWithTypes( - 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + - 'class Person {}' + - 'const x = CONST_EXPR(new Person());') - .to.equal(' class Person { } const x = const Person ( ) ;'); - expectWithTypes( - 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + - 'const x = CONST_EXPR({"one":1});') - .to.equal(' const x = const { "one" : 1 } ;'); - expectWithTypes( - 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + - 'import {Map} from "angular2/src/facade/collection";\n' + - 'const x = CONST_EXPR(new Map());') - .to.equal( - ' import "package:angular2/src/facade/collection.dart" show Map ;' + - ' const x = const { } ;'); - expectWithTypes( - 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + - 'import {Map} from "angular2/src/facade/collection";\n' + - 'const x = CONST_EXPR(new Map());') - .to.equal( - ' import "package:angular2/src/facade/collection.dart" show Map ;' + - ' const x = const < num , String > { } ;'); - }); + describe( + 'builtin functions', () => { + it('translates CONST_EXPR(...) to const (...)', () => { + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'const x = CONST_EXPR([]);') + .to.equal('const x = const [];'); + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'class Person {}' + + 'const x = CONST_EXPR(new Person());') + .to.equal(`class Person {} - it('translates forwardRef(() => T) to T', () => { - expectWithTypes( - 'import {forwardRef} from "angular2/src/core/di/forward_ref";\n' + - 'var SomeType = 1;\n' + - 'var x = forwardRef(() => SomeType);') - .to.equal(' var SomeType = 1 ; var x = SomeType ;'); - expectErroneousWithType( - 'import {forwardRef} from "angular2/src/core/di/forward_ref";\n' + - 'forwardRef(1)') - .to.throw(/only arrow functions/); - }); +const x = const Person();`); + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'const x = CONST_EXPR({"one":1});') + .to.equal('const x = const {"one": 1};'); + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'import {Map} from "angular2/src/facade/collection";\n' + + 'const x = CONST_EXPR(new Map());') + .to.equal(`import "package:angular2/src/facade/collection.dart" show Map; - it('erases calls to normalizeBlank', () => { - expectWithTypes( - 'import {normalizeBlank} from "angular2/src/facade/lang";\n' + - 'var x = normalizeBlank([]);') - .to.equal(' var x = [ ] ;'); - }); - }); +const x = const {};`); + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'import {Map} from "angular2/src/facade/collection";\n' + + 'const x = CONST_EXPR(new Map());') + .to.equal(`import "package:angular2/src/facade/collection.dart" show Map; + +const x = const {};`); + }); + + it('translates forwardRef(() => T) to T', + () => { + expectWithTypes( + 'import {forwardRef} from "angular2/src/core/di/forward_ref";\n' + + 'var SomeType = 1;\n' + + 'var x = forwardRef(() => SomeType);') + .to.equal(`var SomeType = 1; +var x = SomeType;`); + expectErroneousWithType(`import {forwardRef} from "angular2/src/core/di/forward_ref"; +forwardRef(1)`).to.throw(/only arrow functions/); + }); + + it('erases calls to normalizeBlank', () => { + expectWithTypes( + 'import {normalizeBlank} from "angular2/src/facade/lang";\n' + + 'var x = normalizeBlank([]);') + .to.equal('var x = [];'); + }); + }); it('translates array façades', () => { - expectWithTypes('var x = []; Array.isArray(x);').to.equal(' var x = [ ] ; ( ( x ) is List ) ;'); + expectWithTypes('function f() { var x = []; Array.isArray(x); }').to.equal(`f() { + var x = []; + ((x) is List); +}`); }); describe('error detection', () => { @@ -259,14 +319,16 @@ describe('type based translation', () => { it('allows unrelated methods', () => { expectWithTypes( 'import {X} from "other/file";\n' + - 'new X().map(1)') - .to.equal(' import "package:other/file.dart" show X ; new X ( ) . map ( 1 ) ;'); - expectWithTypes( - 'import {X} from "other/file";\n' + - 'X.get({"a": 1}, "a");') - .to.equal(' import "package:other/file.dart" show X ; X . get ( { "a" : 1 } , "a" ) ;'); - expectWithTypes('["a", "b"].map((x) => x);') - .to.equal(' [ "a" , "b" ] . map ( ( x ) => x ) . toList ( ) ;'); + 'var y = new X().map(1)') + .to.equal(`import "package:other/file.dart" show X; + +var y = new X().map(1);`); + expectWithTypes(`import {X} from "other/file"; +var y = X.get({"a": 1}, "a");`) + .to.equal(`import "package:other/file.dart" show X; + +var y = X.get({"a": 1}, "a");`); + expectWithTypes('["a", "b"].map((x) => x);').to.equal('["a", "b"].map((x) => x).toList();'); }); }); }); diff --git a/test/function_test.ts b/test/function_test.ts index e68238b..7208bab 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -2,24 +2,35 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('functions', () => { - it('supports declarations', () => { expectTranslate('function x() {}').to.equal(' x ( ) { }'); }); + it('supports declarations', () => { expectTranslate('function x() {}').to.equal('x() {}'); }); it('supports param default values', () => { - expectTranslate('function x(a = 42, b = 1) { return 42; }') - .to.equal(' x ( [ a = 42 , b = 1 ] ) { return 42 ; }'); + expectTranslate('function x(a = 42, b = 1) { return 42; }').to.equal(`x([a = 42, b = 1]) { + return 42; +}`); expectTranslate('function x(p1, a = 42, b = 1, p2) { return 42; }') - .to.equal(' x ( p1 , [ a = 42 , b = 1 , p2 ] ) { return 42 ; }'); + .to.equal(`x(p1, [a = 42, b = 1, p2]) { + return 42; +}`); }); it('translates optional parameters', () => { expectTranslate('function x(a?: number, b?: number) { return 42; }') - .to.equal(' x ( [ num a , num b ] ) { return 42 ; }'); + .to.equal(`x([num a, num b]) { + return 42; +}`); expectTranslate('function x(p1, a?: number, b?: number, p2) { return 42; }') - .to.equal(' x ( p1 , [ num a , num b , p2 ] ) { return 42 ; }'); + .to.equal(`x(p1, [num a, num b, p2]) { + return 42; +}`); + }); + it('supports empty returns', () => { + expectTranslate('function x() { return; }').to.equal(`x() { + return; +}`); }); - it('supports empty returns', - () => { expectTranslate('function x() { return; }').to.equal(' x ( ) { return ; }'); }); it('supports named parameters', () => { - expectTranslate('function x({a = "x", b}) { return a + b; }') - .to.equal(' x ( { a : "x" , b } ) { return a + b ; }'); + expectTranslate('function x({a = "x", b}) { return a + b; }').to.equal(`x({a: "x", b}) { + return a + b; +}`); }); // TODO(martinprobst): Support types on named parameters. it.skip('fails for types on named parameters', () => { @@ -35,12 +46,12 @@ describe('functions', () => { .to.throw('generic functions are unsupported'); }); it('translates function expressions', - () => { expectTranslate('var a = function() {}').to.equal(' var a = ( ) { } ;'); }); + () => { expectTranslate('var a = function() {}').to.equal('var a = () {};'); }); it('translates fat arrow operator', () => { - expectTranslate('var a = () => {}').to.equal(' var a = ( ) { } ;'); - expectTranslate('var a = (): string => {}').to.equal(' var a = /* String */ ( ) { } ;'); - expectTranslate('var a = (p) => isBlank(p)').to.equal(' var a = ( p ) => isBlank ( p ) ;'); + expectTranslate('var a = () => {}').to.equal('var a = () {};'); + expectTranslate('var a = (): string => {}').to.equal('var a = /* String */ () {};'); + expectTranslate('var a = (p) => isBlank(p)').to.equal('var a = (p) => isBlank(p);'); expectTranslate('var a = (p = null) => isBlank(p)') - .to.equal(' var a = ( [ p = null ] ) => isBlank ( p ) ;'); + .to.equal('var a = ([p = null]) => isBlank(p);'); }); }); diff --git a/test/literal_test.ts b/test/literal_test.ts index b8270ce..9e0565c 100644 --- a/test/literal_test.ts +++ b/test/literal_test.ts @@ -3,62 +3,62 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('literals', () => { it('translates string literals', () => { - expectTranslate(`'hello\\' "world'`).to.equal(` "hello' \\"world" ;`); - expectTranslate(`"hello\\" 'world"`).to.equal(` "hello\\" 'world" ;`); + expectTranslate(`'hello\\' "world'`).to.equal(`"hello' \\"world";`); + expectTranslate(`"hello\\" 'world"`).to.equal(`"hello\\" 'world";`); }); it('translates string templates', () => { - expectTranslate("`hello \nworld`").to.equal(" '''hello \nworld''' ;"); - expectTranslate("`hello ${world}`").to.equal(" '''hello ${ world}''' ;"); - expectTranslate("`${a}$b${$c}`").to.equal(" '''${ a}\\$b${ $c}''' ;"); - expectTranslate("`'${a}'`").to.equal(" '''\\'${ a}\\'''' ;"); - expectTranslate("`'a'`").to.equal(" '''\\'a\\'''' ;"); + expectTranslate("`hello \nworld`").to.equal("'''hello \nworld''';"); + expectTranslate("`hello ${world}`").to.equal("'''hello ${ world}''';"); + expectTranslate("`${a}$b${$c}`").to.equal("'''${ a}\\$b${ $c}''';"); + expectTranslate("`'${a}'`").to.equal("'''\\'${ a}\\'''';"); + expectTranslate("`'a'`").to.equal("'''\\'a\\'''';"); // https://github.com/angular/angular/issues/509 - expectTranslate('"${a}"').to.equal(' "\\${a}" ;'); - expectTranslate('"\\${a}"').to.equal(' "\\${a}" ;'); - expectTranslate("'\\${a}'").to.equal(' "\\${a}" ;'); - expectTranslate("'$a'").to.equal(' "\\$a" ;'); - expectTranslate("`$a`").to.equal(" '''\\$a''' ;"); - expectTranslate("`\\$a`").to.equal(" '''\\$a''' ;"); + expectTranslate('"${a}"').to.equal('"\\${a}";'); + expectTranslate('"\\${a}"').to.equal('"\\${a}";'); + expectTranslate("'\\${a}'").to.equal('"\\${a}";'); + expectTranslate("'$a'").to.equal('"\\$a";'); + expectTranslate("`$a`").to.equal("'''\\$a''';"); + expectTranslate("`\\$a`").to.equal("'''\\$a''';"); }); it('escapes escape sequences', - () => { expectTranslate("`\\\\u1234`").to.equal(" '''\\\\u1234''' ;"); }); + () => { expectTranslate("`\\\\u1234`").to.equal("'''\\\\u1234''';"); }); it('translates boolean literals', () => { - expectTranslate('true').to.equal(' true ;'); - expectTranslate('false').to.equal(' false ;'); - expectTranslate('var b:boolean = true;').to.equal(' bool b = true ;'); + expectTranslate('true').to.equal('true;'); + expectTranslate('false').to.equal('false;'); + expectTranslate('var b:boolean = true;').to.equal('bool b = true;'); }); - it('translates the null literal', () => { expectTranslate('null').to.equal(' null ;'); }); + it('translates the null literal', () => { expectTranslate('null').to.equal('null;'); }); it('translates number literals', () => { // Negative numbers are handled by unary minus expressions. - expectTranslate('1234').to.equal(' 1234 ;'); - expectTranslate('12.34').to.equal(' 12.34 ;'); - expectTranslate('1.23e-4').to.equal(' 1.23e-4 ;'); + expectTranslate('1234').to.equal('1234;'); + expectTranslate('12.34').to.equal('12.34;'); + expectTranslate('1.23e-4').to.equal('1.23e-4;'); }); it('translates regexp literals', () => { - expectTranslate('/wo\\/t?/g').to.equal(' new RegExp ( r\'wo\\/t?\' ) ;'); - expectTranslate('/\'/g').to.equal(' new RegExp ( r\'\' + "\'" + r\'\' ) ;'); - expectTranslate('/\'o\'/g').to.equal(' new RegExp ( r\'\' + "\'" + r\'o\' + "\'" + r\'\' ) ;'); + expectTranslate('/wo\\/t?/g').to.equal('new RegExp(r\'wo\\/t?\');'); + expectTranslate('/\'/g').to.equal('new RegExp(r\'\' + "\'" + r\'\');'); + expectTranslate('/\'o\'/g').to.equal('new RegExp(r\'\' + "\'" + r\'o\' + "\'" + r\'\');'); expectTranslate('/abc/gmi') - .to.equal(' new RegExp ( r\'abc\' , multiLine: true , caseSensitive: false ) ;'); + .to.equal('new RegExp(r\'abc\', multiLine: true, caseSensitive: false);'); expectErroneousCode('/abc/').to.throw(/Regular Expressions must use the \/\/g flag/); }); it('translates array literals', () => { - expectTranslate('[1,2]').to.equal(' [ 1 , 2 ] ;'); - expectTranslate('[1,]').to.equal(' [ 1 ] ;'); - expectTranslate('[]').to.equal(' [ ] ;'); + expectTranslate('[1,2]').to.equal('[1, 2];'); + expectTranslate('[1,]').to.equal('[1];'); + expectTranslate('[]').to.equal('[];'); }); it('translates object literals', () => { - expectTranslate('var x = {a: 1, b: 2}').to.equal(' var x = { "a" : 1 , "b" : 2 } ;'); - expectTranslate('var x = {a: 1, }').to.equal(' var x = { "a" : 1 } ;'); - expectTranslate('var x = {}').to.equal(' var x = { } ;'); - expectTranslate('var x = {y}').to.equal(' var x = { "y" : y } ;'); + expectTranslate('var x = {a: 1, b: 2}').to.equal('var x = {"a": 1, "b": 2};'); + expectTranslate('var x = {a: 1, }').to.equal('var x = {"a": 1};'); + expectTranslate('var x = {}').to.equal('var x = {};'); + expectTranslate('var x = {y}').to.equal('var x = {"y": y};'); }); }); diff --git a/test/main_test.ts b/test/main_test.ts index a107606..9d24918 100644 --- a/test/main_test.ts +++ b/test/main_test.ts @@ -11,16 +11,35 @@ import {expectTranslate, expectErroneousCode, translateSources} from './test_sup describe('main transpiler functionality', () => { describe('comments', () => { it('keeps leading comments', () => { - expectTranslate('/* A */ a\n /* B */ b').to.equal('\n /* A */ a ;\n /* B */ b ;'); - expectTranslate('// A\na\n// B\nb').to.equal('\n // A\n a ;\n // B\n b ;'); + expectTranslate(` +function f() { +/* A */ a; +/* B */ b; +}`).to.equal(`f() { + /* A */ a; + /* B */ b; +}`); + expectTranslate(`function f() { +// A +a +// B +b +}`).to.equal(`f() { + // A + a; + // B + b; +}`); }); it('keeps ctor comments', () => { - expectTranslate('/** A */ class A {\n /** ctor */ constructor() {}}') - .to.equal('\n /** A */ class A {\n /** ctor */ A ( ) { } }'); + expectTranslate('/** A */ class A {\n /** ctor */ constructor() {}}').to.equal(`/** A */ +class A { + /** ctor */ A() {} +}`); }); it('translates links to dart doc format', () => { - expectTranslate('/** {@link this/place} */ a').to.equal('\n /** [this/place] */ a ;'); - expectTranslate('/* {@link 1} {@link 2} */ a').to.equal('\n /* [1] [2] */ a ;'); + expectTranslate('/** {@link this/place} */ a').to.equal('/** [this/place] */ a;'); + expectTranslate('/* {@link 1} {@link 2} */ a').to.equal('/* [1] [2] */ a;'); }); }); @@ -37,8 +56,9 @@ describe('main transpiler functionality', () => { .to.throw(/^b\/c.ts:1/); }); it('reports errors across multiple files', () => { - expectErroneousCode({'a.ts': 'delete x["y"];', 'b.ts': 'delete x["y"];'}, {failFast: false}) - .to.throw(/^a\.ts.*\nb\.ts/); + expectErroneousCode({'a.ts': 'delete x["y"];', 'b.ts': 'delete x["y"];'}, { + failFast: false + }).to.throw(/^a\.ts.*\nb\.ts/); }); }); @@ -62,27 +82,4 @@ describe('main transpiler functionality', () => { (n) => { chai.expect(transpiler.getOutputPath(n, '')).to.equal('a.dart'); }); }); }); - - describe('source maps', () => { - function translateWithSourceMap(source: string): string { - var results = translateSources( - {'/absolute/path/test.ts': source}, {generateSourceMap: true, basePath: '/absolute/'}); - return results['/absolute/path/test.ts']; - } - it('generates a source map', () => { - chai.expect(translateWithSourceMap('var x;')) - .to.contain('//# sourceMappingURL=data:application/json;base64,'); - }); - it('maps locations', () => { - var withMap = translateWithSourceMap('var xVar: number;\nvar yVar: string;'); - chai.expect(withMap).to.contain(' num xVar ; String yVar ;'); - var b64string = withMap.match(/sourceMappingURL=data:application\/json;base64,(.*)/)[1]; - var mapString = new Buffer(b64string, 'base64').toString(); - var consumer = new SourceMap.SourceMapConsumer(JSON.parse(mapString)); - var expectedColumn = ' num xVar ; String yVar ;'.indexOf('yVar') + 1; - var pos = consumer.originalPositionFor({line: 1, column: expectedColumn}); - chai.expect(pos).to.include({line: 2, column: 4}); - chai.expect(consumer.sourceContentFor('path/test.ts')).to.contain('yVar: string'); - }); - }); }); diff --git a/test/module_test.ts b/test/module_test.ts index 05c26f2..dec9f4f 100644 --- a/test/module_test.ts +++ b/test/module_test.ts @@ -8,22 +8,22 @@ import {expectTranslate, expectErroneousCode, translateSources} from './test_sup describe('imports', () => { it('translates import equals statements', () => { - expectTranslate('import x = require("y");').to.equal(' import "package:y.dart" as x ;'); + expectTranslate('import x = require("y");').to.equal('import "package:y.dart" as x;'); }); it('translates import from statements', () => { - expectTranslate('import {x,y} from "z";').to.equal(' import "package:z.dart" show x , y ;'); + expectTranslate('import {x,y} from "z";').to.equal('import "package:z.dart" show x, y;'); }); it('translates import star', () => { - expectTranslate('import * as foo from "z";').to.equal(' import "package:z.dart" as foo ;'); + expectTranslate('import * as foo from "z";').to.equal('import "package:z.dart" as foo;'); }); it('allows import dart file from relative path', () => { - expectTranslate('import x = require("./y")').to.equal(' import "y.dart" as x ;'); - expectTranslate('import {x} from "./y"').to.equal(' import "y.dart" show x ;'); - expectTranslate('import {x} from "../y"').to.equal(' import "../y.dart" show x ;'); + expectTranslate('import x = require("./y")').to.equal('import "y.dart" as x;'); + expectTranslate('import {x} from "./y"').to.equal('import "y.dart" show x;'); + expectTranslate('import {x} from "../y"').to.equal('import "../y.dart" show x;'); }); it('handles ignored annotations in imports', () => { expectTranslate('import {CONST, CONST_EXPR, IMPLEMENTS, ABSTRACT} from "x"').to.equal(''); - expectTranslate('import {x, IMPLEMENTS} from "./x"').to.equal(' import "x.dart" show x ;'); + expectTranslate('import {x, IMPLEMENTS} from "./x"').to.equal('import "x.dart" show x;'); }); it('fails for renamed imports', () => { expectErroneousCode('import {Foo as Bar} from "baz";') @@ -36,15 +36,15 @@ describe('imports', () => { describe('exports', () => { // Dart exports are implicit, everything non-private is exported by the library. it('allows variable exports', - () => { expectTranslate('export var x = 12;').to.equal(' var x = 12 ;'); }); + () => { expectTranslate('export var x = 12;').to.equal('var x = 12;'); }); it('allows class exports', - () => { expectTranslate('export class X {}').to.equal(' class X { }'); }); + () => { expectTranslate('export class X {}').to.equal('class X {}'); }); it('allows export declarations', - () => { expectTranslate('export * from "X";').to.equal(' export "package:X.dart" ;'); }); + () => { expectTranslate('export * from "X";').to.equal('export "package:X.dart";'); }); it('allows export declarations', - () => { expectTranslate('export * from "./X";').to.equal(' export "X.dart" ;'); }); + () => { expectTranslate('export * from "./X";').to.equal('export "X.dart";'); }); it('allows named export declarations', () => { - expectTranslate('export {a, b} from "X";').to.equal(' export "package:X.dart" show a , b ;'); + expectTranslate('export {a, b} from "X";').to.equal('export "package:X.dart" show a, b;'); }); it('fails for renamed exports', () => { expectErroneousCode('export {Foo as Bar} from "baz";') @@ -67,7 +67,10 @@ describe('library name', () => { it('adds a library name', () => { var results = translateSources( {'/a/b/c.ts': 'var x;'}, {failFast: true, generateLibraryName: true, basePath: '/a'}); - chai.expect(results['/a/b/c.ts']).to.equal(' library b.c ; var x ;'); + chai.expect(results['/a/b/c.ts']).to.equal(`library b.c; + +var x; +`); }); it('leaves relative paths alone', () => { chai.expect(modTranspiler.getLibraryName('a/b')).to.equal('a.b'); }); diff --git a/test/statement_test.ts b/test/statement_test.ts index 0145720..bdc91e8 100644 --- a/test/statement_test.ts +++ b/test/statement_test.ts @@ -4,50 +4,94 @@ import {expectTranslate, expectErroneousCode} from './test_support'; describe('statements', () => { it('translates switch', () => { expectTranslate('switch(x) { case 1: break; case 2: break; default: break; }') - .to.equal(' switch ( x ) { case 1 : break ; case 2 : break ; default : break ; }'); + .to.equal(`switch (x) { + case 1: + break; + case 2: + break; + default: + break; +}`); }); it('translates for loops', () => { - expectTranslate('for (1; 2; 3) { 4 }').to.equal(' for ( 1 ; 2 ; 3 ) { 4 ; }'); - expectTranslate('for (var x = 1; 2; 3) { 4 }').to.equal(' for ( var x = 1 ; 2 ; 3 ) { 4 ; }'); - expectTranslate('for (var x, y = 1; 2; 3) { 4 }') - .to.equal(' for ( var x , y = 1 ; 2 ; 3 ) { 4 ; }'); - expectTranslate('for (var x = 0, y = 1; 2; 3) { 4 }') - .to.equal(' for ( var x = 0 , y = 1 ; 2 ; 3 ) { 4 ; }'); + expectTranslate('for (1; 2; 3) { 4 }').to.equal(`for (1; 2; 3) { + 4; +}`); + expectTranslate('for (var x = 1; 2; 3) { 4 }').to.equal(`for (var x = 1; 2; 3) { + 4; +}`); + expectTranslate('for (var x, y = 1; 2; 3) { 4 }').to.equal(`for (var x, y = 1; 2; 3) { + 4; +}`); + expectTranslate('for (var x = 0, y = 1; 2; 3) { 4 }').to.equal(`for (var x = 0, y = 1; 2; 3) { + 4; +}`); }); it('translates for-in loops', () => { - expectTranslate('for (var x in 1) { 2 }').to.equal(' for ( var x in 1 ) { 2 ; }'); - expectTranslate('for (x in 1) { 2 }').to.equal(' for ( x in 1 ) { 2 ; }'); + expectTranslate('for (var x in 1) { 2 }').to.equal(`for (var x in 1) { + 2; +}`); + expectTranslate('for (x in 1) { 2 }').to.equal(`for (x in 1) { + 2; +}`); }); it('translates while loops', () => { - expectTranslate('while (1) { 2 }').to.equal(' while ( 1 ) { 2 ; }'); - expectTranslate('do 1; while (2);').to.equal(' do 1 ; while ( 2 ) ;'); + expectTranslate('while (1) { 2 }').to.equal(`while (1) { + 2; +}`); + expectTranslate('do 1; while (2);').to.equal('do 1; while (2);'); }); it('translates if/then/else', () => { - expectTranslate('if (x) { 1 }').to.equal(' if ( x ) { 1 ; }'); - expectTranslate('if (x) { 1 } else { 2 }').to.equal(' if ( x ) { 1 ; } else { 2 ; }'); - expectTranslate('if (x) 1;').to.equal(' if ( x ) 1 ;'); - expectTranslate('if (x) 1; else 2;').to.equal(' if ( x ) 1 ; else 2 ;'); + expectTranslate('if (x) { 1 }').to.equal(`if (x) { + 1; +}`); + expectTranslate('if (x) { 1 } else { 2 }').to.equal(`if (x) { + 1; +} else { + 2; +}`); + expectTranslate('if (x) 1;').to.equal('if (x) 1;'); + expectTranslate('if (x) 1; else 2;').to.equal(`if (x) + 1; +else + 2;`); }); it('translates try/catch', () => { expectTranslate('try {} catch(e) {} finally {}') - .to.equal(' try { } catch ( e , e_stack ) { } finally { }'); + .to.equal('try {} catch (e, e_stack) {} finally {}'); expectTranslate('try {} catch(e: MyException) {}') - .to.equal(' try { } on MyException catch ( e , e_stack ) { }'); + .to.equal('try {} on MyException catch (e, e_stack) {}'); }); - it('translates throw', () => { - expectTranslate('throw new Error("oops")').to.equal(' throw new Error ( "oops" ) ;'); - }); - it('translates empty statements', () => { expectTranslate(';').to.equal(' ;'); }); + it('translates throw', + () => { expectTranslate('throw new Error("oops")').to.equal('throw new Error("oops");'); }); + it('translates empty statements', () => { expectTranslate(';').to.equal(';'); }); it('translates break & continue', () => { - expectTranslate('break;').to.equal(' break ;'); - expectTranslate('continue;').to.equal(' continue ;'); - expectTranslate('break foo ;').to.equal(' break foo ;'); + expectTranslate(`while (true) { + break; +}`).to.equal(`while (true) { + break; +}`); + expectTranslate(`while (true) { + continue; +}`).to.equal(`while (true) { + continue; +}`); + expectTranslate(`while (true) { + break foo; +}`).to.equal(`while (true) { + break foo; +}`); }); it('rewrites catch block to preserve stack trace', () => { - expectTranslate('try {} catch (e) { console.log(e, e.stack); }') - .to.equal(' try { } catch ( e , e_stack ) { console . log ( e , e_stack ) ; }'); + expectTranslate(`try {} catch (e) { + console.log(e, e.stack); +}`).to.equal(`try {} catch (e, e_stack) { + console.log(e, e_stack); +}`); }); it('rewrites rethrow to preserve stack trace', - () => {expectTranslate('try {} catch (ex) { throw ex; }') - .to.equal(' try { } catch ( ex , ex_stack ) { rethrow ; }')}); + () => { + expectTranslate('try {} catch (ex) { throw ex; }').to.equal(`try {} catch (ex, ex_stack) { + rethrow; +}`)}); }); diff --git a/test/test_support.ts b/test/test_support.ts index fa0ef39..53507c5 100644 --- a/test/test_support.ts +++ b/test/test_support.ts @@ -14,6 +14,11 @@ export type Input = string | StringMap; export function expectTranslate(tsCode: Input, options: main.TranspilerOptions = {}) { var result = translateSource(tsCode, options); + // The Dart formatter is aggressive at terminating statements with \n + // which clutters the expectation output without providing value. + if (result[result.length - 1] == '\n') { + result = result.slice(0, -1); + } return chai.expect(result); } diff --git a/test/type_test.ts b/test/type_test.ts index f6482ad..107b7ed 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -3,47 +3,46 @@ import {expectTranslate} from './test_support'; describe('types', () => { it('supports qualified names', - () => { expectTranslate('var x: foo.Bar;').to.equal(' foo . Bar x ;'); }); + () => { expectTranslate('var x: foo.Bar;').to.equal('foo.Bar x;'); }); it('drops type literals', - () => { expectTranslate('var x: {x: string, y: number};').to.equal(' dynamic x ;'); }); + () => { expectTranslate('var x: {x: string, y: number};').to.equal('dynamic x;'); }); it('translates string index signatures to dartisms', () => { - expectTranslate('var x: {[k: string]: any[]};') - .to.equal(' Map < String , List < dynamic > > x ;'); - expectTranslate('var x: {[k: number]: number};').to.equal(' Map < num , num > x ;'); + expectTranslate('var x: {[k: string]: any[]};').to.equal('Map> x;'); + expectTranslate('var x: {[k: number]: number};').to.equal('Map x;'); }); - it('drops type literals with index signatures and other properties', () => { - expectTranslate('var x: {a: number, [k: string]: number};').to.equal(' dynamic x ;'); - }); - it('allows typecasts', - () => { expectTranslate('ref').to.equal(' ( ref as MyType ) ;'); }); + it('drops type literals with index signatures and other properties', + () => { expectTranslate('var x: {a: number, [k: string]: number};').to.equal('dynamic x;'); }); + it('allows typecasts', () => { expectTranslate('ref').to.equal('(ref as MyType);'); }); it('does not mangle prototype names', () => { expectTranslate('import toString = require("./somewhere");') - .to.equal(' import "somewhere.dart" as toString ;'); + .to.equal('import "somewhere.dart" as toString;'); }); it('should support union types', () => { expectTranslate('var x: number|List = 11;') - .to.equal(' dynamic /* num | List < String > */ x = 11 ;'); + .to.equal('dynamic /* num | List < String > */ x = 11;'); }); it('should support array types', - () => { expectTranslate('var x: string[] = [];').to.equal(' List < String > x = [ ] ;'); }); + () => { expectTranslate('var x: string[] = [];').to.equal('List x = [];'); }); it('should support function types (by ignoring them)', () => { expectTranslate('var x: (a: string) => string;') - .to.equal(' dynamic /* (a: string) => string */ x ;'); + .to.equal('dynamic /* (a: string) => string */ x;'); }); }); describe('type arguments', () => { it('should support declaration', () => { - expectTranslate('class X { a: A; }').to.equal(' class X < A , B > { A a ; }'); + expectTranslate('class X { a: A; }').to.equal(`class X { + A a; +}`); }); it('should support nested extends', () => { - expectTranslate('class X> { }').to.equal(' class X < A extends B < C > > { }'); + expectTranslate('class X> { }').to.equal('class X> {}'); }); it('should multiple extends', () => { expectTranslate('class X { }') - .to.equal(' class X < A extends A1 , B extends B1 > { }'); + .to.equal('class X {}'); }); it('should support use', () => { - expectTranslate('class X extends Y { }').to.equal(' class X extends Y < A , B > { }'); + expectTranslate('class X extends Y { }').to.equal('class X extends Y {}'); }); }); From 615031126ce5571a269c4cfd53a2530b05ec6320 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Mon, 1 Feb 2016 14:56:07 -0800 Subject: [PATCH 005/108] fix(test): Move e2e tests from deprecated Dart unittest package to test package --- test/e2e/helloworld.ts | 4 ++-- test/e2e/pubspec.yaml | 2 +- test/e2e/{unittest.d.ts => test.d.ts} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename test/e2e/{unittest.d.ts => test.d.ts} (75%) diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index 0eb963c..a25b251 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,5 +1,5 @@ -/// -import t = require("unittest/unittest"); +/// +import t = require("test/test"); import {MyClass, MySubclass, SomeArray} from './lib'; diff --git a/test/e2e/pubspec.yaml b/test/e2e/pubspec.yaml index 181663f..cebfd21 100644 --- a/test/e2e/pubspec.yaml +++ b/test/e2e/pubspec.yaml @@ -2,4 +2,4 @@ name: e2e description: Transpiled end-to-end tests for ts2dart. dependencies: - unittest: any + test: 0.12.8 diff --git a/test/e2e/unittest.d.ts b/test/e2e/test.d.ts similarity index 75% rename from test/e2e/unittest.d.ts rename to test/e2e/test.d.ts index 71050d4..1e9dd66 100644 --- a/test/e2e/unittest.d.ts +++ b/test/e2e/test.d.ts @@ -1,4 +1,4 @@ -declare module 'unittest/unittest' { +declare module 'test/test' { function test(msg: string, fn: () => void); function expect(a: any, b: any); function equals(a: any): any; From 6f521823510fbe4d893283ac684e4e4fc9bc7de1 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Sun, 31 Jan 2016 11:47:38 -0800 Subject: [PATCH 006/108] feat: add .idea/ as an IDE file to ignore in gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c894330..59da8ce 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ node_modules # Users Environment Variables .lock-wscript + +# IDEs +.idea/ From 894aac044cb0232a965b4af8a8b078bd0ab33be7 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 1 Feb 2016 09:16:13 -0800 Subject: [PATCH 007/108] feat(): Support for-of statements. --- lib/statement.ts | 9 +++++++++ test/statement_test.ts | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/statement.ts b/lib/statement.ts index 5d37b3f..7cf9ca1 100644 --- a/lib/statement.ts +++ b/lib/statement.ts @@ -91,6 +91,15 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit(')'); this.visit(forInStmt.statement); break; + case ts.SyntaxKind.ForOfStatement: + var forOfStmt = node; + this.emit('for ('); + if (forOfStmt.initializer) this.visit(forOfStmt.initializer); + this.emit('in'); + this.visit(forOfStmt.expression); + this.emit(')'); + this.visit(forOfStmt.statement); + break; case ts.SyntaxKind.WhileStatement: var whileStmt = node; this.emit('while ('); diff --git a/test/statement_test.ts b/test/statement_test.ts index bdc91e8..c277c84 100644 --- a/test/statement_test.ts +++ b/test/statement_test.ts @@ -33,6 +33,14 @@ describe('statements', () => { }`); expectTranslate('for (x in 1) { 2 }').to.equal(`for (x in 1) { 2; +}`); + }); + it('translates for-of loops', () => { + expectTranslate('for (var x of 1) { 2 }').to.equal(`for (var x in 1) { + 2; +}`); + expectTranslate('for (x of 1) { 2 }').to.equal(`for (x in 1) { + 2; }`); }); it('translates while loops', () => { From a560bce694f5d5e6104abadcad3286cd553fdcbc Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 1 Feb 2016 09:16:13 -0800 Subject: [PATCH 008/108] feat(): Add support for void generic argument, which translates to dynamic. --- lib/base.ts | 6 ++++++ test/type_test.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/lib/base.ts b/lib/base.ts index 5c21ee4..ee72450 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -75,6 +75,12 @@ export class TranspilerBase { maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray}) { if (n.typeArguments) { + // If it's a single type argument ``, ignore it and emit nothing. + // This is particularly useful for `Promise`, see + // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639 + if (n.typeArguments.length == 1 && n.typeArguments[0].kind == ts.SyntaxKind.VoidKeyword) { + return; + } this.emit('<'); this.visitList(n.typeArguments); this.emit('>'); diff --git a/test/type_test.ts b/test/type_test.ts index 107b7ed..849da32 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -45,4 +45,9 @@ describe('type arguments', () => { it('should support use', () => { expectTranslate('class X extends Y { }').to.equal('class X extends Y {}'); }); + it('should remove single generic argument', () => { + expectTranslate('var x: X;').to.equal('X x;'); + expectTranslate('class X extends Y { }').to.equal('class X extends Y {}'); + expectTranslate('var x = new Promise();').to.equal('var x = new Promise();'); + }); }); From 917e01a2ede385cdd11925d186e93e6eebef144b Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 4 Feb 2016 11:37:26 -0800 Subject: [PATCH 009/108] fix(decorators): support decorators applied to abstract classes --- lib/declaration.ts | 5 +++-- test/decorator_test.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 8ceaf05..8024222 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -29,9 +29,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { case ts.SyntaxKind.ClassDeclaration: var classDecl = node; if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abstract)) { - this.emit('abstract'); + this.visitClassLike('abstract class', classDecl); + } else { + this.visitClassLike('class', classDecl); } - this.visitClassLike('class', classDecl); break; case ts.SyntaxKind.InterfaceDeclaration: var ifDecl = node; diff --git a/test/decorator_test.ts b/test/decorator_test.ts index 954b2c9..72e0086 100644 --- a/test/decorator_test.ts +++ b/test/decorator_test.ts @@ -5,6 +5,10 @@ describe('decorators', () => { it('translates plain decorators', () => { expectTranslate('@A class X {}').to.equal(`@A class X {}`); + }); + it('translates plain decorators when applied to abstract classes', () => { + expectTranslate('@A abstract class X {}').to.equal(`@A +abstract class X {}`); }); it('translates arguments', () => { expectTranslate('@A(a, b) class X {}').to.equal(`@A(a, b) From 3a18077de5d3efaafab1f3bfb23d845bb6c099f8 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 1 Feb 2016 09:16:13 -0800 Subject: [PATCH 010/108] feat(): Add support for void generic argument, which translates to dynamic. --- lib/base.ts | 6 ++++++ test/type_test.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/lib/base.ts b/lib/base.ts index 5c21ee4..ee72450 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -75,6 +75,12 @@ export class TranspilerBase { maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray}) { if (n.typeArguments) { + // If it's a single type argument ``, ignore it and emit nothing. + // This is particularly useful for `Promise`, see + // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639 + if (n.typeArguments.length == 1 && n.typeArguments[0].kind == ts.SyntaxKind.VoidKeyword) { + return; + } this.emit('<'); this.visitList(n.typeArguments); this.emit('>'); diff --git a/test/type_test.ts b/test/type_test.ts index 107b7ed..849da32 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -45,4 +45,9 @@ describe('type arguments', () => { it('should support use', () => { expectTranslate('class X extends Y { }').to.equal('class X extends Y {}'); }); + it('should remove single generic argument', () => { + expectTranslate('var x: X;').to.equal('X x;'); + expectTranslate('class X extends Y { }').to.equal('class X extends Y {}'); + expectTranslate('var x = new Promise();').to.equal('var x = new Promise();'); + }); }); From 05e49ea9e49382283c84f68e4bfee0a738c30182 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 4 Feb 2016 11:37:26 -0800 Subject: [PATCH 011/108] fix(decorators): support decorators applied to abstract classes --- lib/declaration.ts | 5 +++-- test/decorator_test.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 21af07e..16c9840 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -29,9 +29,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { case ts.SyntaxKind.ClassDeclaration: var classDecl = node; if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abstract)) { - this.emit('abstract'); + this.visitClassLike('abstract class', classDecl); + } else { + this.visitClassLike('class', classDecl); } - this.visitClassLike('class', classDecl); break; case ts.SyntaxKind.InterfaceDeclaration: var ifDecl = node; diff --git a/test/decorator_test.ts b/test/decorator_test.ts index 954b2c9..72e0086 100644 --- a/test/decorator_test.ts +++ b/test/decorator_test.ts @@ -5,6 +5,10 @@ describe('decorators', () => { it('translates plain decorators', () => { expectTranslate('@A class X {}').to.equal(`@A class X {}`); + }); + it('translates plain decorators when applied to abstract classes', () => { + expectTranslate('@A abstract class X {}').to.equal(`@A +abstract class X {}`); }); it('translates arguments', () => { expectTranslate('@A(a, b) class X {}').to.equal(`@A(a, b) From 4afcb15ec3dd59d8aee695dfda35260a1b52f315 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Thu, 4 Feb 2016 11:47:55 -0800 Subject: [PATCH 012/108] rel: 0.7.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92cbed2..c5d4e8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.22", + "version": "0.7.23", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From f5da225b2bbce75daa9005dbf6391fc5b1dbd203 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Thu, 4 Feb 2016 11:54:10 -0800 Subject: [PATCH 013/108] rel: 0.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c68fac..f19c638 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.0", + "version": "0.8.1", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 42cc4c27870e8418bfbf541c41b30ae722c07557 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Sun, 7 Feb 2016 12:31:41 -0800 Subject: [PATCH 014/108] feat(facade): translate the Promise type without explicit export Needed for https://github.com/angular/angular/issues/6468 --- lib/facade_converter.ts | 4 +++- test/facade_converter_test.ts | 16 +++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 619fef9..c17ed34 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -97,7 +97,8 @@ export class FacadeConverter extends base.TranspilerBase { "XMLHttpRequest": "dart:html", "KeyboardEvent": "dart:html", "Uint8Array": "dart:typed_arrays", - "ArrayBuffer": "dart:typed_arrays" + "ArrayBuffer": "dart:typed_arrays", + "Promise": "dart:async" }; var emitted: Set = {}; this.emitImports(sourceFile, libraries, emitted, sourceFile); @@ -227,6 +228,7 @@ export class FacadeConverter extends base.TranspilerBase { 'XMLHttpRequest': 'HttpRequest', 'Uint8Array': 'Uint8List', 'ArrayBuffer': 'ByteBuffer', + 'Promise': 'Future', // Dart has two different incompatible DOM APIs // https://github.com/angular/angular/issues/2770 diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 48e696c..f0c84b1 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -36,11 +36,11 @@ function getSources(str: string): {[k: string]: string} { 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, 'angular2/typings/es6-promise/es6-promise.d.ts': ` - export declare class Promise {}`, + declare class Promise {} + declare module Promise {}`, 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, 'angular2/src/facade/async.ts': ` - export {Promise} from 'angular2/typings/es6-promise/es6-promise'; export {Observable} from 'rxjs/Observable';`, 'angular2/src/facade/collection.ts': ` export declare var Map;`, @@ -76,16 +76,14 @@ function expectErroneousWithType(str: string) { describe('type based translation', () => { describe('Dart type substitution', () => { it('finds registered substitutions', () => { - expectWithTypes( - 'import {Promise, Observable} from "angular2/src/facade/async"; var p: Promise;') - .to.equal(`import "package:angular2/src/facade/async.dart" show Future, Stream; + expectWithTypes('import {Observable} from "angular2/src/facade/async"; var p: Promise;') + .to.equal(`import "dart:async"; +import "package:angular2/src/facade/async.dart" show Stream; Future p;`); - expectWithTypes( - 'import {Promise} from "angular2/src/facade/async"; var y = x instanceof Promise;') - .to.equal(`import "package:angular2/src/facade/async.dart" show Future; + expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; -var y = x is Future;`); +Future y;`); expectWithTypes('var n: Node;').to.equal('dynamic n;'); expectWithTypes('var xhr: XMLHttpRequest;').to.equal(`import "dart:html"; From eb70bf8837d7eb7c4ca98d5b4f3851ba60034142 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Sun, 7 Feb 2016 12:31:41 -0800 Subject: [PATCH 015/108] feat(facade): translate the Promise type without explicit export Needed for https://github.com/angular/angular/issues/6468 --- lib/facade_converter.ts | 4 +++- test/facade_converter_test.ts | 16 +++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 619fef9..c17ed34 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -97,7 +97,8 @@ export class FacadeConverter extends base.TranspilerBase { "XMLHttpRequest": "dart:html", "KeyboardEvent": "dart:html", "Uint8Array": "dart:typed_arrays", - "ArrayBuffer": "dart:typed_arrays" + "ArrayBuffer": "dart:typed_arrays", + "Promise": "dart:async" }; var emitted: Set = {}; this.emitImports(sourceFile, libraries, emitted, sourceFile); @@ -227,6 +228,7 @@ export class FacadeConverter extends base.TranspilerBase { 'XMLHttpRequest': 'HttpRequest', 'Uint8Array': 'Uint8List', 'ArrayBuffer': 'ByteBuffer', + 'Promise': 'Future', // Dart has two different incompatible DOM APIs // https://github.com/angular/angular/issues/2770 diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 48e696c..f0c84b1 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -36,11 +36,11 @@ function getSources(str: string): {[k: string]: string} { 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, 'angular2/typings/es6-promise/es6-promise.d.ts': ` - export declare class Promise {}`, + declare class Promise {} + declare module Promise {}`, 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, 'angular2/src/facade/async.ts': ` - export {Promise} from 'angular2/typings/es6-promise/es6-promise'; export {Observable} from 'rxjs/Observable';`, 'angular2/src/facade/collection.ts': ` export declare var Map;`, @@ -76,16 +76,14 @@ function expectErroneousWithType(str: string) { describe('type based translation', () => { describe('Dart type substitution', () => { it('finds registered substitutions', () => { - expectWithTypes( - 'import {Promise, Observable} from "angular2/src/facade/async"; var p: Promise;') - .to.equal(`import "package:angular2/src/facade/async.dart" show Future, Stream; + expectWithTypes('import {Observable} from "angular2/src/facade/async"; var p: Promise;') + .to.equal(`import "dart:async"; +import "package:angular2/src/facade/async.dart" show Stream; Future p;`); - expectWithTypes( - 'import {Promise} from "angular2/src/facade/async"; var y = x instanceof Promise;') - .to.equal(`import "package:angular2/src/facade/async.dart" show Future; + expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; -var y = x is Future;`); +Future y;`); expectWithTypes('var n: Node;').to.equal('dynamic n;'); expectWithTypes('var xhr: XMLHttpRequest;').to.equal(`import "dart:html"; From e7f7317f1c4780dde6dc5add394eb029ad284850 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Fri, 5 Feb 2016 15:34:12 -0800 Subject: [PATCH 016/108] fix(): allow facades to be in node_modules. --- lib/facade_converter.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index c17ed34..228f83b 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -10,6 +10,8 @@ type Set = { const FACADE_DEBUG = false; +const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; + export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; @@ -149,6 +151,9 @@ export class FacadeConverter extends base.TranspilerBase { var loc = this.getFileAndName(n, symbol); if (!loc) return null; var {fileName, qname} = loc; + if (FACADE_NODE_MODULES_PREFIX.test(fileName)) { + fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); + } var fileSubs = m[fileName]; if (!fileSubs) return null; return fileSubs[qname]; From 672422a9bfe77ea926e7a826ae5d866f747653f8 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Fri, 5 Feb 2016 15:34:12 -0800 Subject: [PATCH 017/108] fix(): allow facades to be in node_modules. --- lib/facade_converter.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index c17ed34..228f83b 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -10,6 +10,8 @@ type Set = { const FACADE_DEBUG = false; +const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; + export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; @@ -149,6 +151,9 @@ export class FacadeConverter extends base.TranspilerBase { var loc = this.getFileAndName(n, symbol); if (!loc) return null; var {fileName, qname} = loc; + if (FACADE_NODE_MODULES_PREFIX.test(fileName)) { + fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); + } var fileSubs = m[fileName]; if (!fileSubs) return null; return fileSubs[qname]; From e9dbe7c7a7498e415d4d152861d82fd91a54e74a Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 8 Feb 2016 11:58:39 -0800 Subject: [PATCH 018/108] feat(build): add npm run release shortcut --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f19c638..6afa0ec 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,15 @@ "gulp-typescript": "^2.7.6", "gulp-util": "^3.0.4", "merge2": "^0.3.1", + "npm-release": "^1.0.0", "temp": "^0.8.1", "tsd": "^0.6.0", "which": "^1.0.9" }, "scripts": { "prepublish": "npm install tsd@^0.6.0 && tsd reinstall --overwrite && gulp compile", - "test": "gulp test" + "test": "gulp test", + "release": "npm-release" }, "repository": { "type": "git", From 067f634e0e16a88fb213c684fd1d8dcb39dbbecd Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 8 Feb 2016 11:58:42 -0800 Subject: [PATCH 019/108] Release v0.8.2. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6afa0ec..15fef0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.1", + "version": "0.8.2", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From ac0088511d19f1b4bb936c591e57a6970f58c451 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 8 Feb 2016 11:58:39 -0800 Subject: [PATCH 020/108] feat(build): add npm run release shortcut --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c5d4e8c..e2a61f9 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,15 @@ "gulp-typescript": "^2.7.6", "gulp-util": "^3.0.4", "merge2": "^0.3.1", + "npm-release": "^1.0.0", "temp": "^0.8.1", "tsd": "^0.6.0", "which": "^1.0.9" }, "scripts": { "prepublish": "npm install tsd@^0.6.0 && tsd reinstall --overwrite && gulp compile", - "test": "gulp test" + "test": "gulp test", + "release": "npm-release" }, "repository": { "type": "git", From 5858b8fe4ebb2f55ee6c0e18c98888bada29047c Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Mon, 8 Feb 2016 12:02:08 -0800 Subject: [PATCH 021/108] Release v0.7.24. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2a61f9..a78c02e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.23", + "version": "0.7.24", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From d9bdd4204cb870cfed61fdacf9a6609826fc7843 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 8 Feb 2016 14:45:24 -0800 Subject: [PATCH 022/108] fix(): remove `(../)*node_modules` from every file name, and use FC for identifiers on new expressions. --- lib/call.ts | 6 +++++- lib/facade_converter.ts | 10 ++-------- test/facade_converter_test.ts | 13 ++++++++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/call.ts b/lib/call.ts index 2c39743..9f69708 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -44,7 +44,11 @@ export default class CallTranspiler extends base.TranspilerBase { } private visitCall(c: ts.CallExpression) { - this.visit(c.expression); + if (c.expression.kind == ts.SyntaxKind.Identifier) { + this.fc.visitTypeName(c.expression); + } else { + this.visit(c.expression); + } // Type arguments on methods are ignored. Dart doesn't support // generic methods, and while we don't allow them to be declared // in ts2dart, it's possible the method being called is not diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 228f83b..9c558b4 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -151,9 +151,6 @@ export class FacadeConverter extends base.TranspilerBase { var loc = this.getFileAndName(n, symbol); if (!loc) return null; var {fileName, qname} = loc; - if (FACADE_NODE_MODULES_PREFIX.test(fileName)) { - fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); - } var fileSubs = m[fileName]; if (!fileSubs) return null; return fileSubs[qname]; @@ -176,6 +173,7 @@ export class FacadeConverter extends base.TranspilerBase { var fileName = decl.getSourceFile().fileName; fileName = this.getRelativeFileName(fileName); fileName = fileName.replace(/(\.d)?\.ts$/, ''); + fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); var qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, @@ -255,11 +253,7 @@ export class FacadeConverter extends base.TranspilerBase { 'lib.es6': this.stdlibTypeReplacements, 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, - '../../node_modules/rxjs/Observable': {'Observable': 'Stream'}, - // TODO(martinprobst): It turns out the angular2 build is too eccentric to reproduce in our test - // suite. The ../../ path above is what happens in Angular2, the path below is what our test - // suite spits out. - 'node_modules/rxjs/Observable': {'Observable': 'Stream'}, + 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, }; diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index f0c84b1..1f5df13 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -76,11 +76,18 @@ function expectErroneousWithType(str: string) { describe('type based translation', () => { describe('Dart type substitution', () => { it('finds registered substitutions', () => { - expectWithTypes('import {Observable} from "angular2/src/facade/async"; var p: Promise;') + expectWithTypes( + 'import {Observable} from "angular2/src/facade/async"; var o: Observable;') + .to.equal(`import "package:angular2/src/facade/async.dart" show Stream; + +Stream o;`); + expectWithTypes('var p: Promise = new Promise();') .to.equal(`import "dart:async"; -import "package:angular2/src/facade/async.dart" show Stream; -Future p;`); +Future p = new Future();`); + expectWithTypes('var p: Promise = new Promise();').to.equal(`import "dart:async"; + +Future p = new Future();`); expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; Future y;`); From bc0d5382461f98622d3cd4a3c06ae7306d2e43e7 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 8 Feb 2016 14:45:24 -0800 Subject: [PATCH 023/108] fix(): remove `(../)*node_modules` from every file name, and use FC for identifiers on new expressions. --- gulpfile.js | 3 +- lib/base.ts | 13 +++ lib/call.ts | 7 +- lib/facade_converter.ts | 199 +++++++++++++++++++++++++++------- lib/type.ts | 2 +- test/e2e/helloworld.ts | 6 + test/facade_converter_test.ts | 111 +++++++++++++++++-- tsd.json | 3 + 8 files changed, 291 insertions(+), 53 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index c0923f5..951e699 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -85,10 +85,11 @@ gulp.task('test.e2e', ['test.compile'], function(done) { if (fs.existsSync(dir)) fsx.removeSync(dir); fs.mkdirSync(dir); fsx.copySync(__dirname + '/test/e2e', dir); + fsx.copySync(__dirname + '/typings', dir + '/typings'); // run node with a shell so we can wildcard all the .ts files var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + - '*.ts angular2/src/facade/lang.d.ts'; + '*.ts angular2/src/facade/lang.d.ts typings/es6-promise/es6-promise.d.ts'; // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { if (code > 0) { diff --git a/lib/base.ts b/lib/base.ts index ee72450..5c2c79a 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -14,6 +14,7 @@ export function ident(n: ts.Node): string { } export class TranspilerBase { + private id_: number = 0; constructor(private transpiler: Transpiler) {} visit(n: ts.Node) { this.transpiler.visit(n); } @@ -36,6 +37,18 @@ export class TranspilerBase { } } + uniqueId(name: string): string { + const id = this.id_++; + return `_${name}\$\$ts2dart\$${id}`; + } + + assert(c: ts.Node, condition: boolean, reason: string): void { + if (!condition) { + this.reportError(c, reason); + throw new Error(reason); + } + } + getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node { for (var parent = n; parent; parent = parent.parent) { if (parent.kind === kind) return parent; diff --git a/lib/call.ts b/lib/call.ts index 9f69708..f854a95 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -16,15 +16,18 @@ export default class CallTranspiler extends base.TranspilerBase { } return false; case ts.SyntaxKind.NewExpression: + var newExpr = node; if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) { // Constructor calls in annotations must be const constructor calls. this.emit('const'); } else if (this.isInsideConstExpr(node)) { this.emit('const'); } else { - this.emit('new'); + // Some implementations can replace the `new` keyword. + if (this.fc.shouldEmitNew(newExpr)) { + this.emit('new'); + } } - var newExpr = node; if (this.fc.maybeHandleCall(newExpr)) break; this.visitCall(newExpr); break; diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 9c558b4..35ea1b5 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -12,6 +12,17 @@ const FACADE_DEBUG = false; const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; +function merge(...args: {[key: string]: any}[]): {[key: string]: any} { + let returnObject: {[key: string]: any} = {}; + for (let arg of args) { + for (let key of Object.getOwnPropertyNames(arg)) { + returnObject[key] = arg[key]; + } + } + return returnObject; +} + + export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; @@ -37,42 +48,11 @@ export class FacadeConverter extends base.TranspilerBase { maybeHandleCall(c: ts.CallExpression): boolean { if (!this.tc) return false; - - var symbol: ts.Symbol; - var context: ts.Expression; - var ident: string; - - if (c.expression.kind === ts.SyntaxKind.Identifier) { - // Function call. - ident = base.ident(c.expression); - if (!this.candidateProperties.hasOwnProperty(ident)) return false; - symbol = this.tc.getSymbolAtLocation(c.expression); - if (FACADE_DEBUG) console.log('s:', symbol); - - if (!symbol) { - this.reportMissingType(c, ident); - return false; - } - - context = null; - } else if (c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) { - // Method call. - var pa = c.expression; - ident = base.ident(pa.name); - if (!this.candidateProperties.hasOwnProperty(ident)) return false; - - symbol = this.tc.getSymbolAtLocation(pa); - if (FACADE_DEBUG) console.log('s:', symbol); - - // Error will be reported by PropertyAccess handling below. - if (!symbol) return false; - - context = pa.expression; - } else { - // Not a call we recognize. + let {context, symbol} = this.getCallInformation(c); + if (!symbol) { + // getCallInformation returns a symbol if we understand this call. return false; } - var handler = this.getHandler(c, symbol, this.callHandlers); return handler && !handler(c, context); } @@ -128,6 +108,7 @@ export class FacadeConverter extends base.TranspilerBase { this.visit(typeName); return; } + var identifier = typeName; var ident = base.ident(typeName); if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { var symbol = this.tc.getSymbolAtLocation(typeName); @@ -147,6 +128,59 @@ export class FacadeConverter extends base.TranspilerBase { this.emit(ident); } + shouldEmitNew(c: ts.CallExpression): boolean { + if (!this.tc) return true; + + let {context, symbol} = this.getCallInformation(c); + if (!symbol) { + // getCallInformation returns a symbol if we understand this call. + return true; + } + + var loc = this.getFileAndName(c, symbol); + if (!loc) return true; + var {fileName, qname} = loc; + var fileSubs = this.callHandlerReplaceNew[fileName]; + if (!fileSubs) return true; + return !fileSubs[qname]; + } + + private getCallInformation(c: ts.CallExpression): {context?: ts.Expression, symbol?: ts.Symbol} { + var symbol: ts.Symbol; + var context: ts.Expression; + var ident: string; + var expr = c.expression; + + if (expr.kind === ts.SyntaxKind.Identifier) { + // Function call. + ident = base.ident(expr); + if (!this.candidateProperties.hasOwnProperty(ident)) return {}; + symbol = this.tc.getSymbolAtLocation(expr); + if (FACADE_DEBUG) console.log('s:', symbol); + + if (!symbol) { + this.reportMissingType(c, ident); + return {}; + } + + context = null; + } else if (expr.kind === ts.SyntaxKind.PropertyAccessExpression) { + // Method call. + var pa = expr; + ident = base.ident(pa.name); + if (!this.candidateProperties.hasOwnProperty(ident)) return {}; + + symbol = this.tc.getSymbolAtLocation(pa); + if (FACADE_DEBUG) console.log('s:', symbol); + + // Error will be reported by PropertyAccess handling below. + if (!symbol) return {}; + + context = pa.expression; + } + return {context, symbol}; + } + private getHandler(n: ts.Node, symbol: ts.Symbol, m: ts.Map>): T { var loc = this.getFileAndName(n, symbol); if (!loc) return null; @@ -251,13 +285,79 @@ export class FacadeConverter extends base.TranspilerBase { private TS_TO_DART_TYPENAMES: ts.Map> = { 'lib': this.stdlibTypeReplacements, 'lib.es6': this.stdlibTypeReplacements, + 'typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, }; - private stdlibHandlers: ts.Map = { + private es6Promises: ts.Map = { + 'Promise.catch': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('.catchError('); + this.visitList(c.arguments); + this.emit(')'); + }, + 'Promise.then': (c: ts.CallExpression, context: ts.Expression) => { + // then() in Dart doesn't support 2 arguments. + this.visit(context); + this.emit('.then('); + this.visit(c.arguments[0]); + this.emit(')'); + if (c.arguments.length > 1) { + this.emit('.catchError('); + this.visit(c.arguments[1]); + this.emit(')'); + } + }, + 'Promise': (c: ts.CallExpression, context: ts.Expression) => { + if (c.kind != ts.SyntaxKind.NewExpression) return true; + this.assert(c, c.arguments.length == 1, 'Promise construction must take 2 arguments.'); + this.assert( + c, c.arguments[0].kind == ts.SyntaxKind.ArrowFunction || + c.arguments[0].kind == ts.SyntaxKind.FunctionExpression, + 'Promise argument must be a function expression (or arrow function).'); + let callback: ts.FunctionLikeDeclaration; + if (c.arguments[0].kind == ts.SyntaxKind.ArrowFunction) { + callback = (c.arguments[0]); + } else if (c.arguments[0].kind == ts.SyntaxKind.FunctionExpression) { + callback = (c.arguments[0]); + } + this.assert( + c, callback.parameters.length > 0 && callback.parameters.length < 3, + 'Promise executor must take 1 or 2 arguments (resolve and reject).'); + + const completerVarName = this.uniqueId('completer'); + this.assert( + c, callback.parameters[0].name.kind == ts.SyntaxKind.Identifier, + 'First argument of the Promise executor is not a straight parameter.'); + let resolveParameterIdent = (callback.parameters[0].name); + + this.emit('(() {'); // Create a new scope. + this.emit(`Completer ${completerVarName} = new Completer();`); + this.emit('var'); + this.emit(resolveParameterIdent.text); + this.emit(`= ${completerVarName}.complete;`); + + if (callback.parameters.length == 2) { + this.assert( + c, callback.parameters[1].name.kind == ts.SyntaxKind.Identifier, + 'First argument of the Promise executor is not a straight parameter.'); + let rejectParameterIdent = (callback.parameters[1].name); + this.emit('var'); + this.emit(rejectParameterIdent.text); + this.emit(`= ${completerVarName}.completeError;`) + } + this.emit('(()'); + this.visit(callback.body); + this.emit(')();'); + this.emit(`return ${completerVarName}.future;`); + this.emit('})()'); + }, + }; + + private stdlibHandlers: ts.Map = merge(this.es6Promises, { 'Array.push': (c: ts.CallExpression, context: ts.Expression) => { this.visit(context); this.emitMethodCall('add', c.arguments); @@ -352,7 +452,7 @@ export class FacadeConverter extends base.TranspilerBase { this.emitMethodCall('allMatches', c.arguments); this.emitMethodCall('toList'); }, - }; + }); private es6Collections: ts.Map = { 'Map.set': (c: ts.CallExpression, context: ts.Expression) => { @@ -442,13 +542,22 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('. firstWhere ('); this.visit(c.arguments[0]); this.emit(', orElse : ( ) => null )'); - } + }, + }; + + private callHandlerReplaceNew: ts.Map> = { + 'typings/es6-promise/es6-promise': {'Promise': true}, + 'angular2/typings/es6-promise/es6-promise': {'Promise': true}, }; private callHandlers: ts.Map> = { 'lib': this.stdlibHandlers, 'lib.es6': this.stdlibHandlers, - 'angular2/typings/es6-shim/es6-shim': this.es6Collections, + 'typings/es6-promise/es6-promise': this.es6Promises, + 'typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), + 'typings/es6-collections/es6-collections': this.es6Collections, + 'angular2/typings/es6-promise/es6-promise': this.es6Promises, + 'angular2/typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), 'angular2/typings/es6-collections/es6-collections': this.es6Collections, 'angular2/manual_typings/globals': this.es6Collections, 'angular2/src/facade/collection': { @@ -497,9 +606,23 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('length'); }, }; + private es6PromisesProp: ts.Map = { + 'resolve': (p: ts.PropertyAccessExpression) => { + this.visit(p.expression); + this.emit('.value'); + }, + 'reject': (p: ts.PropertyAccessExpression) => { + this.visit(p.expression); + this.emit('.error'); + }, + }; private propertyHandlers: ts.Map> = { + 'typings/es6-shim/es6-shim': this.es6CollectionsProp, 'angular2/typings/es6-shim/es6-shim': this.es6CollectionsProp, + 'typings/es6-collections/es6-collections': this.es6CollectionsProp, 'angular2/typings/es6-collections/es6-collections': this.es6CollectionsProp, + 'typings/es6-promise/es6-promise': this.es6PromisesProp, + 'angular2/typings/es6-promise/es6-promise': this.es6PromisesProp, }; } diff --git a/lib/type.ts b/lib/type.ts index 8373495..5d95362 100644 --- a/lib/type.ts +++ b/lib/type.ts @@ -70,7 +70,7 @@ export default class TypeTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.Identifier: var ident = node; - this.emit(ident.text); + this.fc.visitTypeName(ident); break; case ts.SyntaxKind.NumberKeyword: this.emit('num'); diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index a25b251..6136c20 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,4 +1,5 @@ /// +/// import t = require("test/test"); import {MyClass, MySubclass, SomeArray} from './lib'; @@ -26,4 +27,9 @@ function main(): void { t.expect(/o/g.exec("fo.o").length, t.equals(2)); }); t.test("const expr", function() { t.expect(SomeArray[0], t.equals(1)); }); + + t.test("promises", function() { + let p: Promise = new Promise((resolve) => { resolve(1); }); + p.then((n) => { t.expect(n, t.equals(1)); }); + }); } diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 1f5df13..19b304c 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,4 +1,5 @@ /// +import * as fs from 'fs'; import { parseFiles, expectTranslate, @@ -35,9 +36,8 @@ function getSources(str: string): {[k: string]: string} { 'angular2/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, - 'angular2/typings/es6-promise/es6-promise.d.ts': ` - declare class Promise {} - declare module Promise {}`, + 'typings/es6-promise/es6-promise.d.ts': + fs.readFileSync('typings/es6-promise/es6-promise.d.ts', 'utf-8'), 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, 'angular2/src/facade/async.ts': ` @@ -53,8 +53,8 @@ function getSources(str: string): {[k: string]: string} { map(x: number): string { return String(x); } static get(m: any, k: string): number { return m[k]; } } - var global: any; - export var Promise = global.Promise;`, + export class Promise {} + `, }; srcs[FAKE_MAIN] = str; return srcs; @@ -81,13 +81,9 @@ describe('type based translation', () => { .to.equal(`import "package:angular2/src/facade/async.dart" show Stream; Stream o;`); - expectWithTypes('var p: Promise = new Promise();') - .to.equal(`import "dart:async"; - -Future p = new Future();`); - expectWithTypes('var p: Promise = new Promise();').to.equal(`import "dart:async"; + expectWithTypes('var p: Promise = x;').to.equal(`import "dart:async"; -Future p = new Future();`); +Future p = x;`); expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; Future y;`); @@ -237,6 +233,99 @@ var y = x.length;`); }`); }); + describe('promises', () => { + it('translates into Futures', () => { + expectWithTypes('let x: Promise = Promise.resolve(1);').to.equal(`import "dart:async"; + +Future x = Future.value(1);`); + expectWithTypes('let x: Promise = Promise.reject(1);').to.equal(`import "dart:async"; + +Future x = Future.error(1);`); + expectWithTypes('let x: Promise = new Promise((resolve) => {resolve(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes('let x: Promise = new Promise((resolve, reject) => {resolve(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + var reject = _completer$$ts2dart$0.completeError; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes('let x: Promise = new Promise((myParam1, myParam2) => {myParam1(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var myParam1 = _completer$$ts2dart$0.complete; + var myParam2 = _completer$$ts2dart$0.completeError; + (() { + myParam1(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes( + 'let x: Promise = new Promise((resolve, reject) => {resolve(1);});' + + 'function fn(): void { x.then((v) => { console.log(v) }).catch((err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + var reject = _completer$$ts2dart$0.completeError; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})(); +void fn() { + x.then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + expectWithTypes( + 'var fn: () => Promise;' + + 'function main() { fn().then((v) => { console.log(v) }).catch((err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +dynamic /* () => Promise */ fn; +main() { + fn().then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + expectWithTypes( + 'var fn: () => Promise;' + + 'function main() { fn().then((v) => { console.log(v) }, (err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +dynamic /* () => Promise */ fn; +main() { + fn().then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + }); + }); + describe( 'builtin functions', () => { it('translates CONST_EXPR(...) to const (...)', () => { diff --git a/tsd.json b/tsd.json index 4f66e9b..ace9d02 100644 --- a/tsd.json +++ b/tsd.json @@ -25,6 +25,9 @@ }, "minimist/minimist.d.ts": { "commit": "8b7cc13f6dbabd0a49de7ccba75c342160e600ad" + }, + "es6-promise/es6-promise.d.ts": { + "commit": "bcd5761826eb567876c197ccc6a87c4d05731054" } } } From d9b881f9cceb0af54f017a14da68c62d5350dd43 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Fri, 12 Feb 2016 17:22:26 -0800 Subject: [PATCH 024/108] Release v0.8.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 15fef0b..41ce222 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.2", + "version": "0.8.3", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From a3f457f1e82614d16b158948feedd625842c5081 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 8 Feb 2016 14:45:24 -0800 Subject: [PATCH 025/108] fix(): remove `(../)*node_modules` from every file name, and use FC for identifiers on new expressions. --- lib/call.ts | 6 +++++- lib/facade_converter.ts | 10 ++-------- test/facade_converter_test.ts | 13 ++++++++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/call.ts b/lib/call.ts index 2c39743..9f69708 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -44,7 +44,11 @@ export default class CallTranspiler extends base.TranspilerBase { } private visitCall(c: ts.CallExpression) { - this.visit(c.expression); + if (c.expression.kind == ts.SyntaxKind.Identifier) { + this.fc.visitTypeName(c.expression); + } else { + this.visit(c.expression); + } // Type arguments on methods are ignored. Dart doesn't support // generic methods, and while we don't allow them to be declared // in ts2dart, it's possible the method being called is not diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 228f83b..9c558b4 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -151,9 +151,6 @@ export class FacadeConverter extends base.TranspilerBase { var loc = this.getFileAndName(n, symbol); if (!loc) return null; var {fileName, qname} = loc; - if (FACADE_NODE_MODULES_PREFIX.test(fileName)) { - fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); - } var fileSubs = m[fileName]; if (!fileSubs) return null; return fileSubs[qname]; @@ -176,6 +173,7 @@ export class FacadeConverter extends base.TranspilerBase { var fileName = decl.getSourceFile().fileName; fileName = this.getRelativeFileName(fileName); fileName = fileName.replace(/(\.d)?\.ts$/, ''); + fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); var qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, @@ -255,11 +253,7 @@ export class FacadeConverter extends base.TranspilerBase { 'lib.es6': this.stdlibTypeReplacements, 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, - '../../node_modules/rxjs/Observable': {'Observable': 'Stream'}, - // TODO(martinprobst): It turns out the angular2 build is too eccentric to reproduce in our test - // suite. The ../../ path above is what happens in Angular2, the path below is what our test - // suite spits out. - 'node_modules/rxjs/Observable': {'Observable': 'Stream'}, + 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, }; diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index f0c84b1..1f5df13 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -76,11 +76,18 @@ function expectErroneousWithType(str: string) { describe('type based translation', () => { describe('Dart type substitution', () => { it('finds registered substitutions', () => { - expectWithTypes('import {Observable} from "angular2/src/facade/async"; var p: Promise;') + expectWithTypes( + 'import {Observable} from "angular2/src/facade/async"; var o: Observable;') + .to.equal(`import "package:angular2/src/facade/async.dart" show Stream; + +Stream o;`); + expectWithTypes('var p: Promise = new Promise();') .to.equal(`import "dart:async"; -import "package:angular2/src/facade/async.dart" show Stream; -Future p;`); +Future p = new Future();`); + expectWithTypes('var p: Promise = new Promise();').to.equal(`import "dart:async"; + +Future p = new Future();`); expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; Future y;`); From 6dcab16f9e819a7675d9edf02d19c77cda4697df Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 8 Feb 2016 14:45:24 -0800 Subject: [PATCH 026/108] fix(): remove `(../)*node_modules` from every file name, and use FC for identifiers on new expressions. --- gulpfile.js | 3 +- lib/base.ts | 13 +++ lib/call.ts | 7 +- lib/facade_converter.ts | 199 +++++++++++++++++++++++++++------- lib/type.ts | 2 +- test/e2e/helloworld.ts | 6 + test/facade_converter_test.ts | 111 +++++++++++++++++-- tsd.json | 3 + 8 files changed, 291 insertions(+), 53 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index c0923f5..951e699 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -85,10 +85,11 @@ gulp.task('test.e2e', ['test.compile'], function(done) { if (fs.existsSync(dir)) fsx.removeSync(dir); fs.mkdirSync(dir); fsx.copySync(__dirname + '/test/e2e', dir); + fsx.copySync(__dirname + '/typings', dir + '/typings'); // run node with a shell so we can wildcard all the .ts files var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + - '*.ts angular2/src/facade/lang.d.ts'; + '*.ts angular2/src/facade/lang.d.ts typings/es6-promise/es6-promise.d.ts'; // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { if (code > 0) { diff --git a/lib/base.ts b/lib/base.ts index ee72450..5c2c79a 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -14,6 +14,7 @@ export function ident(n: ts.Node): string { } export class TranspilerBase { + private id_: number = 0; constructor(private transpiler: Transpiler) {} visit(n: ts.Node) { this.transpiler.visit(n); } @@ -36,6 +37,18 @@ export class TranspilerBase { } } + uniqueId(name: string): string { + const id = this.id_++; + return `_${name}\$\$ts2dart\$${id}`; + } + + assert(c: ts.Node, condition: boolean, reason: string): void { + if (!condition) { + this.reportError(c, reason); + throw new Error(reason); + } + } + getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node { for (var parent = n; parent; parent = parent.parent) { if (parent.kind === kind) return parent; diff --git a/lib/call.ts b/lib/call.ts index 9f69708..f854a95 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -16,15 +16,18 @@ export default class CallTranspiler extends base.TranspilerBase { } return false; case ts.SyntaxKind.NewExpression: + var newExpr = node; if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) { // Constructor calls in annotations must be const constructor calls. this.emit('const'); } else if (this.isInsideConstExpr(node)) { this.emit('const'); } else { - this.emit('new'); + // Some implementations can replace the `new` keyword. + if (this.fc.shouldEmitNew(newExpr)) { + this.emit('new'); + } } - var newExpr = node; if (this.fc.maybeHandleCall(newExpr)) break; this.visitCall(newExpr); break; diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 9c558b4..35ea1b5 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -12,6 +12,17 @@ const FACADE_DEBUG = false; const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; +function merge(...args: {[key: string]: any}[]): {[key: string]: any} { + let returnObject: {[key: string]: any} = {}; + for (let arg of args) { + for (let key of Object.getOwnPropertyNames(arg)) { + returnObject[key] = arg[key]; + } + } + return returnObject; +} + + export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; @@ -37,42 +48,11 @@ export class FacadeConverter extends base.TranspilerBase { maybeHandleCall(c: ts.CallExpression): boolean { if (!this.tc) return false; - - var symbol: ts.Symbol; - var context: ts.Expression; - var ident: string; - - if (c.expression.kind === ts.SyntaxKind.Identifier) { - // Function call. - ident = base.ident(c.expression); - if (!this.candidateProperties.hasOwnProperty(ident)) return false; - symbol = this.tc.getSymbolAtLocation(c.expression); - if (FACADE_DEBUG) console.log('s:', symbol); - - if (!symbol) { - this.reportMissingType(c, ident); - return false; - } - - context = null; - } else if (c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) { - // Method call. - var pa = c.expression; - ident = base.ident(pa.name); - if (!this.candidateProperties.hasOwnProperty(ident)) return false; - - symbol = this.tc.getSymbolAtLocation(pa); - if (FACADE_DEBUG) console.log('s:', symbol); - - // Error will be reported by PropertyAccess handling below. - if (!symbol) return false; - - context = pa.expression; - } else { - // Not a call we recognize. + let {context, symbol} = this.getCallInformation(c); + if (!symbol) { + // getCallInformation returns a symbol if we understand this call. return false; } - var handler = this.getHandler(c, symbol, this.callHandlers); return handler && !handler(c, context); } @@ -128,6 +108,7 @@ export class FacadeConverter extends base.TranspilerBase { this.visit(typeName); return; } + var identifier = typeName; var ident = base.ident(typeName); if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { var symbol = this.tc.getSymbolAtLocation(typeName); @@ -147,6 +128,59 @@ export class FacadeConverter extends base.TranspilerBase { this.emit(ident); } + shouldEmitNew(c: ts.CallExpression): boolean { + if (!this.tc) return true; + + let {context, symbol} = this.getCallInformation(c); + if (!symbol) { + // getCallInformation returns a symbol if we understand this call. + return true; + } + + var loc = this.getFileAndName(c, symbol); + if (!loc) return true; + var {fileName, qname} = loc; + var fileSubs = this.callHandlerReplaceNew[fileName]; + if (!fileSubs) return true; + return !fileSubs[qname]; + } + + private getCallInformation(c: ts.CallExpression): {context?: ts.Expression, symbol?: ts.Symbol} { + var symbol: ts.Symbol; + var context: ts.Expression; + var ident: string; + var expr = c.expression; + + if (expr.kind === ts.SyntaxKind.Identifier) { + // Function call. + ident = base.ident(expr); + if (!this.candidateProperties.hasOwnProperty(ident)) return {}; + symbol = this.tc.getSymbolAtLocation(expr); + if (FACADE_DEBUG) console.log('s:', symbol); + + if (!symbol) { + this.reportMissingType(c, ident); + return {}; + } + + context = null; + } else if (expr.kind === ts.SyntaxKind.PropertyAccessExpression) { + // Method call. + var pa = expr; + ident = base.ident(pa.name); + if (!this.candidateProperties.hasOwnProperty(ident)) return {}; + + symbol = this.tc.getSymbolAtLocation(pa); + if (FACADE_DEBUG) console.log('s:', symbol); + + // Error will be reported by PropertyAccess handling below. + if (!symbol) return {}; + + context = pa.expression; + } + return {context, symbol}; + } + private getHandler(n: ts.Node, symbol: ts.Symbol, m: ts.Map>): T { var loc = this.getFileAndName(n, symbol); if (!loc) return null; @@ -251,13 +285,79 @@ export class FacadeConverter extends base.TranspilerBase { private TS_TO_DART_TYPENAMES: ts.Map> = { 'lib': this.stdlibTypeReplacements, 'lib.es6': this.stdlibTypeReplacements, + 'typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, }; - private stdlibHandlers: ts.Map = { + private es6Promises: ts.Map = { + 'Promise.catch': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('.catchError('); + this.visitList(c.arguments); + this.emit(')'); + }, + 'Promise.then': (c: ts.CallExpression, context: ts.Expression) => { + // then() in Dart doesn't support 2 arguments. + this.visit(context); + this.emit('.then('); + this.visit(c.arguments[0]); + this.emit(')'); + if (c.arguments.length > 1) { + this.emit('.catchError('); + this.visit(c.arguments[1]); + this.emit(')'); + } + }, + 'Promise': (c: ts.CallExpression, context: ts.Expression) => { + if (c.kind != ts.SyntaxKind.NewExpression) return true; + this.assert(c, c.arguments.length == 1, 'Promise construction must take 2 arguments.'); + this.assert( + c, c.arguments[0].kind == ts.SyntaxKind.ArrowFunction || + c.arguments[0].kind == ts.SyntaxKind.FunctionExpression, + 'Promise argument must be a function expression (or arrow function).'); + let callback: ts.FunctionLikeDeclaration; + if (c.arguments[0].kind == ts.SyntaxKind.ArrowFunction) { + callback = (c.arguments[0]); + } else if (c.arguments[0].kind == ts.SyntaxKind.FunctionExpression) { + callback = (c.arguments[0]); + } + this.assert( + c, callback.parameters.length > 0 && callback.parameters.length < 3, + 'Promise executor must take 1 or 2 arguments (resolve and reject).'); + + const completerVarName = this.uniqueId('completer'); + this.assert( + c, callback.parameters[0].name.kind == ts.SyntaxKind.Identifier, + 'First argument of the Promise executor is not a straight parameter.'); + let resolveParameterIdent = (callback.parameters[0].name); + + this.emit('(() {'); // Create a new scope. + this.emit(`Completer ${completerVarName} = new Completer();`); + this.emit('var'); + this.emit(resolveParameterIdent.text); + this.emit(`= ${completerVarName}.complete;`); + + if (callback.parameters.length == 2) { + this.assert( + c, callback.parameters[1].name.kind == ts.SyntaxKind.Identifier, + 'First argument of the Promise executor is not a straight parameter.'); + let rejectParameterIdent = (callback.parameters[1].name); + this.emit('var'); + this.emit(rejectParameterIdent.text); + this.emit(`= ${completerVarName}.completeError;`) + } + this.emit('(()'); + this.visit(callback.body); + this.emit(')();'); + this.emit(`return ${completerVarName}.future;`); + this.emit('})()'); + }, + }; + + private stdlibHandlers: ts.Map = merge(this.es6Promises, { 'Array.push': (c: ts.CallExpression, context: ts.Expression) => { this.visit(context); this.emitMethodCall('add', c.arguments); @@ -352,7 +452,7 @@ export class FacadeConverter extends base.TranspilerBase { this.emitMethodCall('allMatches', c.arguments); this.emitMethodCall('toList'); }, - }; + }); private es6Collections: ts.Map = { 'Map.set': (c: ts.CallExpression, context: ts.Expression) => { @@ -442,13 +542,22 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('. firstWhere ('); this.visit(c.arguments[0]); this.emit(', orElse : ( ) => null )'); - } + }, + }; + + private callHandlerReplaceNew: ts.Map> = { + 'typings/es6-promise/es6-promise': {'Promise': true}, + 'angular2/typings/es6-promise/es6-promise': {'Promise': true}, }; private callHandlers: ts.Map> = { 'lib': this.stdlibHandlers, 'lib.es6': this.stdlibHandlers, - 'angular2/typings/es6-shim/es6-shim': this.es6Collections, + 'typings/es6-promise/es6-promise': this.es6Promises, + 'typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), + 'typings/es6-collections/es6-collections': this.es6Collections, + 'angular2/typings/es6-promise/es6-promise': this.es6Promises, + 'angular2/typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), 'angular2/typings/es6-collections/es6-collections': this.es6Collections, 'angular2/manual_typings/globals': this.es6Collections, 'angular2/src/facade/collection': { @@ -497,9 +606,23 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('length'); }, }; + private es6PromisesProp: ts.Map = { + 'resolve': (p: ts.PropertyAccessExpression) => { + this.visit(p.expression); + this.emit('.value'); + }, + 'reject': (p: ts.PropertyAccessExpression) => { + this.visit(p.expression); + this.emit('.error'); + }, + }; private propertyHandlers: ts.Map> = { + 'typings/es6-shim/es6-shim': this.es6CollectionsProp, 'angular2/typings/es6-shim/es6-shim': this.es6CollectionsProp, + 'typings/es6-collections/es6-collections': this.es6CollectionsProp, 'angular2/typings/es6-collections/es6-collections': this.es6CollectionsProp, + 'typings/es6-promise/es6-promise': this.es6PromisesProp, + 'angular2/typings/es6-promise/es6-promise': this.es6PromisesProp, }; } diff --git a/lib/type.ts b/lib/type.ts index 8373495..5d95362 100644 --- a/lib/type.ts +++ b/lib/type.ts @@ -70,7 +70,7 @@ export default class TypeTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.Identifier: var ident = node; - this.emit(ident.text); + this.fc.visitTypeName(ident); break; case ts.SyntaxKind.NumberKeyword: this.emit('num'); diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index a25b251..6136c20 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,4 +1,5 @@ /// +/// import t = require("test/test"); import {MyClass, MySubclass, SomeArray} from './lib'; @@ -26,4 +27,9 @@ function main(): void { t.expect(/o/g.exec("fo.o").length, t.equals(2)); }); t.test("const expr", function() { t.expect(SomeArray[0], t.equals(1)); }); + + t.test("promises", function() { + let p: Promise = new Promise((resolve) => { resolve(1); }); + p.then((n) => { t.expect(n, t.equals(1)); }); + }); } diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 1f5df13..19b304c 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,4 +1,5 @@ /// +import * as fs from 'fs'; import { parseFiles, expectTranslate, @@ -35,9 +36,8 @@ function getSources(str: string): {[k: string]: string} { 'angular2/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, - 'angular2/typings/es6-promise/es6-promise.d.ts': ` - declare class Promise {} - declare module Promise {}`, + 'typings/es6-promise/es6-promise.d.ts': + fs.readFileSync('typings/es6-promise/es6-promise.d.ts', 'utf-8'), 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, 'angular2/src/facade/async.ts': ` @@ -53,8 +53,8 @@ function getSources(str: string): {[k: string]: string} { map(x: number): string { return String(x); } static get(m: any, k: string): number { return m[k]; } } - var global: any; - export var Promise = global.Promise;`, + export class Promise {} + `, }; srcs[FAKE_MAIN] = str; return srcs; @@ -81,13 +81,9 @@ describe('type based translation', () => { .to.equal(`import "package:angular2/src/facade/async.dart" show Stream; Stream o;`); - expectWithTypes('var p: Promise = new Promise();') - .to.equal(`import "dart:async"; - -Future p = new Future();`); - expectWithTypes('var p: Promise = new Promise();').to.equal(`import "dart:async"; + expectWithTypes('var p: Promise = x;').to.equal(`import "dart:async"; -Future p = new Future();`); +Future p = x;`); expectWithTypes('var y: Promise;').to.equal(`import "dart:async"; Future y;`); @@ -237,6 +233,99 @@ var y = x.length;`); }`); }); + describe('promises', () => { + it('translates into Futures', () => { + expectWithTypes('let x: Promise = Promise.resolve(1);').to.equal(`import "dart:async"; + +Future x = Future.value(1);`); + expectWithTypes('let x: Promise = Promise.reject(1);').to.equal(`import "dart:async"; + +Future x = Future.error(1);`); + expectWithTypes('let x: Promise = new Promise((resolve) => {resolve(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes('let x: Promise = new Promise((resolve, reject) => {resolve(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + var reject = _completer$$ts2dart$0.completeError; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes('let x: Promise = new Promise((myParam1, myParam2) => {myParam1(1);});') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var myParam1 = _completer$$ts2dart$0.complete; + var myParam2 = _completer$$ts2dart$0.completeError; + (() { + myParam1(1); + })(); + return _completer$$ts2dart$0.future; +})();`); + expectWithTypes( + 'let x: Promise = new Promise((resolve, reject) => {resolve(1);});' + + 'function fn(): void { x.then((v) => { console.log(v) }).catch((err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +Future x = (() { + Completer _completer$$ts2dart$0 = new Completer(); + var resolve = _completer$$ts2dart$0.complete; + var reject = _completer$$ts2dart$0.completeError; + (() { + resolve(1); + })(); + return _completer$$ts2dart$0.future; +})(); +void fn() { + x.then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + expectWithTypes( + 'var fn: () => Promise;' + + 'function main() { fn().then((v) => { console.log(v) }).catch((err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +dynamic /* () => Promise */ fn; +main() { + fn().then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + expectWithTypes( + 'var fn: () => Promise;' + + 'function main() { fn().then((v) => { console.log(v) }, (err) => { console.log(err); }); }') + .to.equal(`import "dart:async"; + +dynamic /* () => Promise */ fn; +main() { + fn().then((v) { + console.log(v); + }).catchError((err) { + console.log(err); + }); +}`); + }); + }); + describe( 'builtin functions', () => { it('translates CONST_EXPR(...) to const (...)', () => { diff --git a/tsd.json b/tsd.json index 4f66e9b..ace9d02 100644 --- a/tsd.json +++ b/tsd.json @@ -25,6 +25,9 @@ }, "minimist/minimist.d.ts": { "commit": "8b7cc13f6dbabd0a49de7ccba75c342160e600ad" + }, + "es6-promise/es6-promise.d.ts": { + "commit": "bcd5761826eb567876c197ccc6a87c4d05731054" } } } From 076fd23ec0f1f2dee12fc6c7af692ce8a6531153 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Fri, 12 Feb 2016 17:39:30 -0800 Subject: [PATCH 027/108] Release v0.7.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a78c02e..83c3b57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.24", + "version": "0.7.25", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 08999ccaa498144f37186b2955e7c0df9bc5e960 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 17 Feb 2016 00:33:57 -0800 Subject: [PATCH 028/108] Sanitize TypeScript doc strings to remove tags not recognized by dartdoc --- lib/main.ts | 14 ++++++++++++- test/main_test.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/main.ts b/lib/main.ts index 3f117bd..5387ec6 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -275,7 +275,19 @@ export class Transpiler { private normalizeSlashes(path: string) { return path.replace(/\\/g, '/'); } private translateComment(comment: string): string { - return comment.replace(/\{@link ([^\}]+)\}/g, '[$1]'); + comment = comment.replace(/\{@link ([^\}]+)\}/g, '[$1]'); + + // Remove the following tags and following comments till end of line. + comment = comment.replace(/@param.*$/gm, ''); + comment = comment.replace(/@throws.*$/gm, ''); + comment = comment.replace(/@return.*$/gm, ''); + + // Remove the following tags. + comment = comment.replace(/@module/g, ''); + comment = comment.replace(/@description/g, ''); + comment = comment.replace(/@deprecated/g, ''); + + return comment; } } diff --git a/test/main_test.ts b/test/main_test.ts index 9d24918..1a1b663 100644 --- a/test/main_test.ts +++ b/test/main_test.ts @@ -41,6 +41,56 @@ class A { expectTranslate('/** {@link this/place} */ a').to.equal('/** [this/place] */ a;'); expectTranslate('/* {@link 1} {@link 2} */ a').to.equal('/* [1] [2] */ a;'); }); + it('removes @module doc tags', () => { + expectTranslate(`/** @module + * This is a module for doing X. + */`).to.equal(`/** + * This is a module for doing X. + */`); + }); + it('removes @description doc tags', () => { + expectTranslate(`/** @description + * This is a module for doing X. + */`).to.equal(`/** + * This is a module for doing X. + */`); + }); + it('removes @depracted doc tags', () => { + expectTranslate(`/** + * Use SomethingElse instead. + * @deprecated + */`).to.equal(`/** + * Use SomethingElse instead. + * + */`); + }); + it('removes @param doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @param doc Document. + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); + it('removes @return doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @return {String} + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); + it('removes @throws doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @throws ArgumentException If arguments are wrong + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); }); describe('errors', () => { From 0605f34d17bc73e0b348119d88b3f3742a646cc1 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 17 Feb 2016 11:28:19 -0800 Subject: [PATCH 029/108] Release v0.8.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41ce222..2e506eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.3", + "version": "0.8.4", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From cc27423bbd00a1556eecc41fd23d2e6ed4c3a92d Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 17 Feb 2016 00:33:57 -0800 Subject: [PATCH 030/108] Sanitize TypeScript doc strings to remove tags not recognized by dartdoc --- lib/main.ts | 14 ++++++++++++- test/main_test.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/main.ts b/lib/main.ts index bd1f69f..23c1a73 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -275,7 +275,19 @@ export class Transpiler { private normalizeSlashes(path: string) { return path.replace(/\\/g, '/'); } private translateComment(comment: string): string { - return comment.replace(/\{@link ([^\}]+)\}/g, '[$1]'); + comment = comment.replace(/\{@link ([^\}]+)\}/g, '[$1]'); + + // Remove the following tags and following comments till end of line. + comment = comment.replace(/@param.*$/gm, ''); + comment = comment.replace(/@throws.*$/gm, ''); + comment = comment.replace(/@return.*$/gm, ''); + + // Remove the following tags. + comment = comment.replace(/@module/g, ''); + comment = comment.replace(/@description/g, ''); + comment = comment.replace(/@deprecated/g, ''); + + return comment; } } diff --git a/test/main_test.ts b/test/main_test.ts index 9d24918..1a1b663 100644 --- a/test/main_test.ts +++ b/test/main_test.ts @@ -41,6 +41,56 @@ class A { expectTranslate('/** {@link this/place} */ a').to.equal('/** [this/place] */ a;'); expectTranslate('/* {@link 1} {@link 2} */ a').to.equal('/* [1] [2] */ a;'); }); + it('removes @module doc tags', () => { + expectTranslate(`/** @module + * This is a module for doing X. + */`).to.equal(`/** + * This is a module for doing X. + */`); + }); + it('removes @description doc tags', () => { + expectTranslate(`/** @description + * This is a module for doing X. + */`).to.equal(`/** + * This is a module for doing X. + */`); + }); + it('removes @depracted doc tags', () => { + expectTranslate(`/** + * Use SomethingElse instead. + * @deprecated + */`).to.equal(`/** + * Use SomethingElse instead. + * + */`); + }); + it('removes @param doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @param doc Document. + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); + it('removes @return doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @return {String} + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); + it('removes @throws doc tags', () => { + expectTranslate(`/** + * Method to do blah. + * @throws ArgumentException If arguments are wrong + */`).to.equal(`/** + * Method to do blah. + * + */`); + }); }); describe('errors', () => { From b0261d33181c21f9868341b50e07776e5a197867 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 17 Feb 2016 11:30:15 -0800 Subject: [PATCH 031/108] Release v0.7.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83c3b57..7db6a89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.25", + "version": "0.7.26", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 8c2e9a9c10af02481e02b2900e93c8f320bce875 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 18 Feb 2016 11:03:33 -0800 Subject: [PATCH 032/108] fix(): allow the caller (or CLI) to specify a root directory for typings. --- gulpfile.js | 1 + lib/facade_converter.ts | 48 +++++++++++++++++------------------ lib/main.ts | 7 ++++- test/facade_converter_test.ts | 7 ++--- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 951e699..5998e10 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -89,6 +89,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { // run node with a shell so we can wildcard all the .ts files var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + + '--typingsRoot=typings/ ' + '*.ts angular2/src/facade/lang.d.ts typings/es6-promise/es6-promise.d.ts'; // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 35ea1b5..a521bbf 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -27,12 +27,15 @@ export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; + private typingsRootRegex: RegExp; - constructor(transpiler: Transpiler) { + constructor(transpiler: Transpiler, typingsRoot: string = '') { super(transpiler); this.extractPropertyNames(this.callHandlers, this.candidateProperties); this.extractPropertyNames(this.propertyHandlers, this.candidateProperties); this.extractPropertyNames(this.TS_TO_DART_TYPENAMES, this.candidateTypes); + + this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); } private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) { @@ -204,10 +207,11 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - var fileName = decl.getSourceFile().fileName; - fileName = this.getRelativeFileName(fileName); - fileName = fileName.replace(/(\.d)?\.ts$/, ''); - fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); + const fileName = decl.getSourceFile().fileName; + const canonicalFileName = this.getRelativeFileName(fileName) + .replace(/(\.d)?\.ts$/, '') + .replace(FACADE_NODE_MODULES_PREFIX, '') + .replace(this.typingsRootRegex, ''); var qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, @@ -216,8 +220,8 @@ export class FacadeConverter extends base.TranspilerBase { symbol.flags & ts.SymbolFlags.Class) { qname = symbol.getName(); } - if (FACADE_DEBUG) console.log('fn:', fileName, 'qn:', qname); - return {fileName, qname}; + if (FACADE_DEBUG) console.log('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); + return {fileName: canonicalFileName, qname}; } private isNamedType(node: ts.Node, fileName: string, qname: string): boolean { @@ -285,11 +289,11 @@ export class FacadeConverter extends base.TranspilerBase { private TS_TO_DART_TYPENAMES: ts.Map> = { 'lib': this.stdlibTypeReplacements, 'lib.es6': this.stdlibTypeReplacements, - 'typings/es6-promise/es6-promise': {'Promise': 'Future'}, - 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, - 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, - 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, + + 'rxjs/Observable': {'Observable': 'Stream'}, + 'es6-promise/es6-promise': {'Promise': 'Future'}, + 'es6-shim/es6-shim': {'Promise': 'Future'}, }; private es6Promises: ts.Map = { @@ -546,19 +550,16 @@ export class FacadeConverter extends base.TranspilerBase { }; private callHandlerReplaceNew: ts.Map> = { - 'typings/es6-promise/es6-promise': {'Promise': true}, - 'angular2/typings/es6-promise/es6-promise': {'Promise': true}, + 'es6-promise/es6-promise': {'Promise': true}, + 'es6-shim/es6-shim': {'Promise': true}, }; private callHandlers: ts.Map> = { 'lib': this.stdlibHandlers, 'lib.es6': this.stdlibHandlers, - 'typings/es6-promise/es6-promise': this.es6Promises, - 'typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), - 'typings/es6-collections/es6-collections': this.es6Collections, - 'angular2/typings/es6-promise/es6-promise': this.es6Promises, - 'angular2/typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), - 'angular2/typings/es6-collections/es6-collections': this.es6Collections, + 'es6-promise/es6-promise': this.es6Promises, + 'es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), + 'es6-collections/es6-collections': this.es6Collections, 'angular2/manual_typings/globals': this.es6Collections, 'angular2/src/facade/collection': { 'Map': (c: ts.CallExpression, context: ts.Expression): boolean => { @@ -618,11 +619,8 @@ export class FacadeConverter extends base.TranspilerBase { }; private propertyHandlers: ts.Map> = { - 'typings/es6-shim/es6-shim': this.es6CollectionsProp, - 'angular2/typings/es6-shim/es6-shim': this.es6CollectionsProp, - 'typings/es6-collections/es6-collections': this.es6CollectionsProp, - 'angular2/typings/es6-collections/es6-collections': this.es6CollectionsProp, - 'typings/es6-promise/es6-promise': this.es6PromisesProp, - 'angular2/typings/es6-promise/es6-promise': this.es6PromisesProp, + 'es6-shim/es6-shim': this.es6CollectionsProp, + 'es6-collections/es6-collections': this.es6CollectionsProp, + 'es6-promise/es6-promise': this.es6PromisesProp, }; } diff --git a/lib/main.ts b/lib/main.ts index 5387ec6..c9b5365 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -40,6 +40,10 @@ export interface TranspilerOptions { * Enforce conventions of public/private keyword and underscore prefix */ enforceUnderscoreConventions?: boolean; + /** + * Sets a root path to look for typings used by the facade converter. + */ + typingsRoot?: string; } export const COMPILER_OPTIONS: ts.CompilerOptions = { @@ -62,7 +66,8 @@ export class Transpiler { private fc: FacadeConverter; constructor(private options: TranspilerOptions = {}) { - this.fc = new FacadeConverter(this); + // TODO: Remove the angular2 default when angular uses typingsRoot. + this.fc = new FacadeConverter(this, options.typingsRoot || 'angular2/typings/'); this.transpilers = [ new CallTranspiler(this, this.fc), // Has to come before StatementTranspiler! new DeclarationTranspiler(this, this.fc, options.enforceUnderscoreConventions), diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 19b304c..8ea361f 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -33,10 +33,10 @@ var es6RuntimeDeclarations = ` function getSources(str: string): {[k: string]: string} { var srcs: {[k: string]: string} = { - 'angular2/typings/es6-shim/es6-shim': es6RuntimeDeclarations, + 'some/path/to/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, - 'typings/es6-promise/es6-promise.d.ts': + 'some/path/to/typings/es6-promise/es6-promise.d.ts': fs.readFileSync('typings/es6-promise/es6-promise.d.ts', 'utf-8'), 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, @@ -62,7 +62,8 @@ function getSources(str: string): {[k: string]: string} { const COMPILE_OPTS = { translateBuiltins: true, - failFast: true + failFast: true, + typingsRoot: 'some/path/to/typings/' }; function expectWithTypes(str: string) { From 708de548bc870e505a7643c24c14a3c6bdb579f6 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Thu, 18 Feb 2016 11:03:33 -0800 Subject: [PATCH 033/108] fix(): allow the caller (or CLI) to specify a root directory for typings. --- gulpfile.js | 1 + lib/facade_converter.ts | 48 +++++++++++++++++------------------ lib/main.ts | 7 ++++- test/facade_converter_test.ts | 7 ++--- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 951e699..5998e10 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -89,6 +89,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { // run node with a shell so we can wildcard all the .ts files var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + + '--typingsRoot=typings/ ' + '*.ts angular2/src/facade/lang.d.ts typings/es6-promise/es6-promise.d.ts'; // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 35ea1b5..a521bbf 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -27,12 +27,15 @@ export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; + private typingsRootRegex: RegExp; - constructor(transpiler: Transpiler) { + constructor(transpiler: Transpiler, typingsRoot: string = '') { super(transpiler); this.extractPropertyNames(this.callHandlers, this.candidateProperties); this.extractPropertyNames(this.propertyHandlers, this.candidateProperties); this.extractPropertyNames(this.TS_TO_DART_TYPENAMES, this.candidateTypes); + + this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); } private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) { @@ -204,10 +207,11 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - var fileName = decl.getSourceFile().fileName; - fileName = this.getRelativeFileName(fileName); - fileName = fileName.replace(/(\.d)?\.ts$/, ''); - fileName = fileName.replace(FACADE_NODE_MODULES_PREFIX, ''); + const fileName = decl.getSourceFile().fileName; + const canonicalFileName = this.getRelativeFileName(fileName) + .replace(/(\.d)?\.ts$/, '') + .replace(FACADE_NODE_MODULES_PREFIX, '') + .replace(this.typingsRootRegex, ''); var qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, @@ -216,8 +220,8 @@ export class FacadeConverter extends base.TranspilerBase { symbol.flags & ts.SymbolFlags.Class) { qname = symbol.getName(); } - if (FACADE_DEBUG) console.log('fn:', fileName, 'qn:', qname); - return {fileName, qname}; + if (FACADE_DEBUG) console.log('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); + return {fileName: canonicalFileName, qname}; } private isNamedType(node: ts.Node, fileName: string, qname: string): boolean { @@ -285,11 +289,11 @@ export class FacadeConverter extends base.TranspilerBase { private TS_TO_DART_TYPENAMES: ts.Map> = { 'lib': this.stdlibTypeReplacements, 'lib.es6': this.stdlibTypeReplacements, - 'typings/es6-promise/es6-promise': {'Promise': 'Future'}, - 'angular2/typings/es6-promise/es6-promise': {'Promise': 'Future'}, - 'angular2/typings/es6-shim/es6-shim': {'Promise': 'Future'}, - 'rxjs/Observable': {'Observable': 'Stream'}, 'angular2/src/facade/lang': {'Date': 'DateTime'}, + + 'rxjs/Observable': {'Observable': 'Stream'}, + 'es6-promise/es6-promise': {'Promise': 'Future'}, + 'es6-shim/es6-shim': {'Promise': 'Future'}, }; private es6Promises: ts.Map = { @@ -546,19 +550,16 @@ export class FacadeConverter extends base.TranspilerBase { }; private callHandlerReplaceNew: ts.Map> = { - 'typings/es6-promise/es6-promise': {'Promise': true}, - 'angular2/typings/es6-promise/es6-promise': {'Promise': true}, + 'es6-promise/es6-promise': {'Promise': true}, + 'es6-shim/es6-shim': {'Promise': true}, }; private callHandlers: ts.Map> = { 'lib': this.stdlibHandlers, 'lib.es6': this.stdlibHandlers, - 'typings/es6-promise/es6-promise': this.es6Promises, - 'typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), - 'typings/es6-collections/es6-collections': this.es6Collections, - 'angular2/typings/es6-promise/es6-promise': this.es6Promises, - 'angular2/typings/es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), - 'angular2/typings/es6-collections/es6-collections': this.es6Collections, + 'es6-promise/es6-promise': this.es6Promises, + 'es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), + 'es6-collections/es6-collections': this.es6Collections, 'angular2/manual_typings/globals': this.es6Collections, 'angular2/src/facade/collection': { 'Map': (c: ts.CallExpression, context: ts.Expression): boolean => { @@ -618,11 +619,8 @@ export class FacadeConverter extends base.TranspilerBase { }; private propertyHandlers: ts.Map> = { - 'typings/es6-shim/es6-shim': this.es6CollectionsProp, - 'angular2/typings/es6-shim/es6-shim': this.es6CollectionsProp, - 'typings/es6-collections/es6-collections': this.es6CollectionsProp, - 'angular2/typings/es6-collections/es6-collections': this.es6CollectionsProp, - 'typings/es6-promise/es6-promise': this.es6PromisesProp, - 'angular2/typings/es6-promise/es6-promise': this.es6PromisesProp, + 'es6-shim/es6-shim': this.es6CollectionsProp, + 'es6-collections/es6-collections': this.es6CollectionsProp, + 'es6-promise/es6-promise': this.es6PromisesProp, }; } diff --git a/lib/main.ts b/lib/main.ts index 23c1a73..28e98cf 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -40,6 +40,10 @@ export interface TranspilerOptions { * Enforce conventions of public/private keyword and underscore prefix */ enforceUnderscoreConventions?: boolean; + /** + * Sets a root path to look for typings used by the facade converter. + */ + typingsRoot?: string; } export const COMPILER_OPTIONS: ts.CompilerOptions = { @@ -62,7 +66,8 @@ export class Transpiler { private fc: FacadeConverter; constructor(private options: TranspilerOptions = {}) { - this.fc = new FacadeConverter(this); + // TODO: Remove the angular2 default when angular uses typingsRoot. + this.fc = new FacadeConverter(this, options.typingsRoot || 'angular2/typings/'); this.transpilers = [ new CallTranspiler(this, this.fc), // Has to come before StatementTranspiler! new DeclarationTranspiler(this, this.fc, options.enforceUnderscoreConventions), diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 19b304c..8ea361f 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -33,10 +33,10 @@ var es6RuntimeDeclarations = ` function getSources(str: string): {[k: string]: string} { var srcs: {[k: string]: string} = { - 'angular2/typings/es6-shim/es6-shim': es6RuntimeDeclarations, + 'some/path/to/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, - 'typings/es6-promise/es6-promise.d.ts': + 'some/path/to/typings/es6-promise/es6-promise.d.ts': fs.readFileSync('typings/es6-promise/es6-promise.d.ts', 'utf-8'), 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, @@ -62,7 +62,8 @@ function getSources(str: string): {[k: string]: string} { const COMPILE_OPTS = { translateBuiltins: true, - failFast: true + failFast: true, + typingsRoot: 'some/path/to/typings/' }; function expectWithTypes(str: string) { From dafa4072b58f9dd8cf1fe263b63dc24c5c37f89b Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 24 Feb 2016 16:27:45 -0800 Subject: [PATCH 034/108] Release v0.7.27 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7db6a89..3acaa9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.26", + "version": "0.7.27", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From cbd75fe7533162839cd75a09db980909a77c65c8 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 24 Feb 2016 16:39:20 -0800 Subject: [PATCH 035/108] Release v0.8.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2e506eb..cc58733 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.4", + "version": "0.8.5", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From e1b1502d732d1c2e97dd467b171db4bc4c50c366 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 1 Mar 2016 07:41:57 -0800 Subject: [PATCH 036/108] feat(): support DDC style generic methods. Fixes #348. --- lib/declaration.ts | 55 +++++++++++++++++++++-------------- lib/facade_converter.ts | 43 +++++++++++++++++++++++++++ test/facade_converter_test.ts | 3 ++ test/function_test.ts | 28 +++++++++++++++--- test/type_test.ts | 5 ++++ 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 8024222..59d53cd 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -126,7 +126,6 @@ export default class DeclarationTranspiler extends base.TranspilerBase { case ts.SyntaxKind.FunctionDeclaration: var funcDecl = node; this.visitDecorators(funcDecl.decorators); - if (funcDecl.typeParameters) this.reportError(node, 'generic functions are unsupported'); this.visitFunctionLike(funcDecl); break; case ts.SyntaxKind.ArrowFunction: @@ -252,30 +251,42 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } private visitFunctionLike(fn: ts.FunctionLikeDeclaration, accessor?: string) { - if (fn.type) { - if (fn.kind === ts.SyntaxKind.ArrowFunction) { - // Type is silently dropped for arrow functions, not supported in Dart. - this.emit('/*'); - this.visit(fn.type); - this.emit('*/'); + this.fc.pushTypeParameterNames(fn); + try { + if (fn.type) { + if (fn.kind === ts.SyntaxKind.ArrowFunction) { + // Type is silently dropped for arrow functions, not supported in Dart. + this.emit('/*'); + this.visit(fn.type); + this.emit('*/'); + } else { + this.visit(fn.type); + } + } + if (accessor) this.emit(accessor); + if (fn.name) this.visit(fn.name); + if (fn.typeParameters) { + this.emit('/*<'); + // Emit the names literally instead of visiting, otherwise they will be replaced with the + // comment hack themselves. + this.emit(fn.typeParameters.map(p => base.ident(p.name)).join(', ')); + this.emit('>*/'); + } + // Dart does not even allow the parens of an empty param list on getter + if (accessor !== 'get') { + this.visitParameters(fn.parameters); } else { - this.visit(fn.type); + if (fn.parameters && fn.parameters.length > 0) { + this.reportError(fn, 'getter should not accept parameters'); + } } - } - if (accessor) this.emit(accessor); - if (fn.name) this.visit(fn.name); - // Dart does not even allow the parens of an empty param list on getter - if (accessor !== 'get') { - this.visitParameters(fn.parameters); - } else { - if (fn.parameters && fn.parameters.length > 0) { - this.reportError(fn, 'getter should not accept parameters'); + if (fn.body) { + this.visit(fn.body); + } else { + this.emit(';'); } - } - if (fn.body) { - this.visit(fn.body); - } else { - this.emit(';'); + } finally { + this.fc.popTypeParameterNames(fn); } } diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index a521bbf..5a8216d 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -28,6 +28,7 @@ export class FacadeConverter extends base.TranspilerBase { private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; private typingsRootRegex: RegExp; + private genericMethodDeclDepth = 0; constructor(transpiler: Transpiler, typingsRoot: string = '') { super(transpiler); @@ -106,6 +107,39 @@ export class FacadeConverter extends base.TranspilerBase { .forEach((n: ts.Node) => this.emitImports(n, libraries, emitted, sourceFile)); } + pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + this.genericMethodDeclDepth++; + } + + popTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + this.genericMethodDeclDepth--; + } + + + /** + * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate + * generic methods in Dart. ts2dart has to hack around this and keep track of which type names + * in the current scope are actually DDC type parameters and need to be emitted in comments. + * + * TODO(martinprobst): Remove this once the DDC hack has made it into Dart proper. + */ + private isGenericMethodTypeParameterName(name: ts.EntityName): boolean { + // Avoid checking this unless needed. + if (this.genericMethodDeclDepth === 0 || !this.tc) return false; + // Check if the type of the name is a TypeParameter. + let t = this.tc.getTypeAtLocation(name); + if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false; + + // Check if the symbol we're looking at is the type parameter. + let symbol = this.tc.getSymbolAtLocation(name); + if (symbol != t.symbol) return false; + + // Check that the Type Parameter has been declared by a function declaration. + return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration); + } + visitTypeName(typeName: ts.EntityName) { if (typeName.kind !== ts.SyntaxKind.Identifier) { this.visit(typeName); @@ -113,6 +147,15 @@ export class FacadeConverter extends base.TranspilerBase { } var identifier = typeName; var ident = base.ident(typeName); + if (this.isGenericMethodTypeParameterName(typeName)) { + // DDC generic methods hack - all names that are type parameters to generic methods have to be + // emitted in comments. + this.emit('dynamic/*='); + this.emit(ident); + this.emit('*/'); + return; + } + if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { var symbol = this.tc.getSymbolAtLocation(typeName); if (!symbol) { diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 8ea361f..c566ab7 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -108,6 +108,9 @@ ByteBuffer buff;`); var y = x is Promise;`); }); + + it('does not substitute all identifiers', + () => { expectWithTypes('let Promise = 1;').to.equal(`var Promise = 1;`); }); }); describe('collection façade', () => { diff --git a/test/function_test.ts b/test/function_test.ts index 7208bab..d05c7e0 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -41,10 +41,6 @@ describe('functions', () => { expectErroneousCode('function x(...a: number) { return 42; }') .to.throw('rest parameters are unsupported'); }); - it('does not support generic functions', () => { - expectErroneousCode('function x() { return 42; }') - .to.throw('generic functions are unsupported'); - }); it('translates function expressions', () => { expectTranslate('var a = function() {}').to.equal('var a = () {};'); }); it('translates fat arrow operator', () => { @@ -55,3 +51,27 @@ describe('functions', () => { .to.equal('var a = ([p = null]) => isBlank(p);'); }); }); + +describe('generic functions', () => { + it('supports generic types', () => { + expectTranslate('function sort(xs: T[]): T[] { return xs; }', { + translateBuiltins: true + }).to.equal(`List sort/*< T, U >*/(List xs) { + return xs; +}`); + }); + it('replaces type usage sites, but not idents', () => { + expectTranslate( + `function wobble(u: U): T { + let t: T = u; + for (let T of [1, 2]) {} + return t; + }`, + {translateBuiltins: true}) + .to.equal(`dynamic/*= T */ wobble/*< T, U >*/(dynamic/*= U */ u) { + dynamic/*= T */ t = (u as dynamic/*= T */); + for (var T in [1, 2]) {} + return t; +}`); + }); +}); diff --git a/test/type_test.ts b/test/type_test.ts index 849da32..616919c 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -20,6 +20,11 @@ describe('types', () => { it('should support union types', () => { expectTranslate('var x: number|List = 11;') .to.equal('dynamic /* num | List < String > */ x = 11;'); + expectTranslate('function x(): number|List<{[k: string]: any}> { return 11; }') + .to.equal( + 'dynamic /* num | List < Map < String , dynamic > > */ x() {\n' + + ' return 11;\n' + + '}'); }); it('should support array types', () => { expectTranslate('var x: string[] = [];').to.equal('List x = [];'); }); From a7df0b717ee3b5093d2e6ae9b6d335757bbadd41 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 1 Mar 2016 07:41:57 -0800 Subject: [PATCH 037/108] feat(): support DDC style generic methods. Fixes #348. --- lib/declaration.ts | 55 +++++++++++++++++++++-------------- lib/facade_converter.ts | 43 +++++++++++++++++++++++++++ test/facade_converter_test.ts | 3 ++ test/function_test.ts | 28 +++++++++++++++--- test/type_test.ts | 5 ++++ 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 16c9840..480a526 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -126,7 +126,6 @@ export default class DeclarationTranspiler extends base.TranspilerBase { case ts.SyntaxKind.FunctionDeclaration: var funcDecl = node; this.visitDecorators(funcDecl.decorators); - if (funcDecl.typeParameters) this.reportError(node, 'generic functions are unsupported'); this.visitFunctionLike(funcDecl); break; case ts.SyntaxKind.ArrowFunction: @@ -252,30 +251,42 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } private visitFunctionLike(fn: ts.FunctionLikeDeclaration, accessor?: string) { - if (fn.type) { - if (fn.kind === ts.SyntaxKind.ArrowFunction) { - // Type is silently dropped for arrow functions, not supported in Dart. - this.emit('/*'); - this.visit(fn.type); - this.emit('*/'); + this.fc.pushTypeParameterNames(fn); + try { + if (fn.type) { + if (fn.kind === ts.SyntaxKind.ArrowFunction) { + // Type is silently dropped for arrow functions, not supported in Dart. + this.emit('/*'); + this.visit(fn.type); + this.emit('*/'); + } else { + this.visit(fn.type); + } + } + if (accessor) this.emit(accessor); + if (fn.name) this.visit(fn.name); + if (fn.typeParameters) { + this.emit('/*<'); + // Emit the names literally instead of visiting, otherwise they will be replaced with the + // comment hack themselves. + this.emit(fn.typeParameters.map(p => base.ident(p.name)).join(', ')); + this.emit('>*/'); + } + // Dart does not even allow the parens of an empty param list on getter + if (accessor !== 'get') { + this.visitParameters(fn.parameters); } else { - this.visit(fn.type); + if (fn.parameters && fn.parameters.length > 0) { + this.reportError(fn, 'getter should not accept parameters'); + } } - } - if (accessor) this.emit(accessor); - if (fn.name) this.visit(fn.name); - // Dart does not even allow the parens of an empty param list on getter - if (accessor !== 'get') { - this.visitParameters(fn.parameters); - } else { - if (fn.parameters && fn.parameters.length > 0) { - this.reportError(fn, 'getter should not accept parameters'); + if (fn.body) { + this.visit(fn.body); + } else { + this.emit(';'); } - } - if (fn.body) { - this.visit(fn.body); - } else { - this.emit(';'); + } finally { + this.fc.popTypeParameterNames(fn); } } diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index a521bbf..5a8216d 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -28,6 +28,7 @@ export class FacadeConverter extends base.TranspilerBase { private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; private typingsRootRegex: RegExp; + private genericMethodDeclDepth = 0; constructor(transpiler: Transpiler, typingsRoot: string = '') { super(transpiler); @@ -106,6 +107,39 @@ export class FacadeConverter extends base.TranspilerBase { .forEach((n: ts.Node) => this.emitImports(n, libraries, emitted, sourceFile)); } + pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + this.genericMethodDeclDepth++; + } + + popTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + this.genericMethodDeclDepth--; + } + + + /** + * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate + * generic methods in Dart. ts2dart has to hack around this and keep track of which type names + * in the current scope are actually DDC type parameters and need to be emitted in comments. + * + * TODO(martinprobst): Remove this once the DDC hack has made it into Dart proper. + */ + private isGenericMethodTypeParameterName(name: ts.EntityName): boolean { + // Avoid checking this unless needed. + if (this.genericMethodDeclDepth === 0 || !this.tc) return false; + // Check if the type of the name is a TypeParameter. + let t = this.tc.getTypeAtLocation(name); + if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false; + + // Check if the symbol we're looking at is the type parameter. + let symbol = this.tc.getSymbolAtLocation(name); + if (symbol != t.symbol) return false; + + // Check that the Type Parameter has been declared by a function declaration. + return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration); + } + visitTypeName(typeName: ts.EntityName) { if (typeName.kind !== ts.SyntaxKind.Identifier) { this.visit(typeName); @@ -113,6 +147,15 @@ export class FacadeConverter extends base.TranspilerBase { } var identifier = typeName; var ident = base.ident(typeName); + if (this.isGenericMethodTypeParameterName(typeName)) { + // DDC generic methods hack - all names that are type parameters to generic methods have to be + // emitted in comments. + this.emit('dynamic/*='); + this.emit(ident); + this.emit('*/'); + return; + } + if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { var symbol = this.tc.getSymbolAtLocation(typeName); if (!symbol) { diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 8ea361f..c566ab7 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -108,6 +108,9 @@ ByteBuffer buff;`); var y = x is Promise;`); }); + + it('does not substitute all identifiers', + () => { expectWithTypes('let Promise = 1;').to.equal(`var Promise = 1;`); }); }); describe('collection façade', () => { diff --git a/test/function_test.ts b/test/function_test.ts index 7208bab..d05c7e0 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -41,10 +41,6 @@ describe('functions', () => { expectErroneousCode('function x(...a: number) { return 42; }') .to.throw('rest parameters are unsupported'); }); - it('does not support generic functions', () => { - expectErroneousCode('function x() { return 42; }') - .to.throw('generic functions are unsupported'); - }); it('translates function expressions', () => { expectTranslate('var a = function() {}').to.equal('var a = () {};'); }); it('translates fat arrow operator', () => { @@ -55,3 +51,27 @@ describe('functions', () => { .to.equal('var a = ([p = null]) => isBlank(p);'); }); }); + +describe('generic functions', () => { + it('supports generic types', () => { + expectTranslate('function sort(xs: T[]): T[] { return xs; }', { + translateBuiltins: true + }).to.equal(`List sort/*< T, U >*/(List xs) { + return xs; +}`); + }); + it('replaces type usage sites, but not idents', () => { + expectTranslate( + `function wobble(u: U): T { + let t: T = u; + for (let T of [1, 2]) {} + return t; + }`, + {translateBuiltins: true}) + .to.equal(`dynamic/*= T */ wobble/*< T, U >*/(dynamic/*= U */ u) { + dynamic/*= T */ t = (u as dynamic/*= T */); + for (var T in [1, 2]) {} + return t; +}`); + }); +}); diff --git a/test/type_test.ts b/test/type_test.ts index 849da32..616919c 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -20,6 +20,11 @@ describe('types', () => { it('should support union types', () => { expectTranslate('var x: number|List = 11;') .to.equal('dynamic /* num | List < String > */ x = 11;'); + expectTranslate('function x(): number|List<{[k: string]: any}> { return 11; }') + .to.equal( + 'dynamic /* num | List < Map < String , dynamic > > */ x() {\n' + + ' return 11;\n' + + '}'); }); it('should support array types', () => { expectTranslate('var x: string[] = [];').to.equal('List x = [];'); }); From 4342332420d01b5a16229ddd78c8770dc7c234a5 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 2 Mar 2016 18:04:21 -0800 Subject: [PATCH 038/108] rel: 0.7.28. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3acaa9b..ae42f6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.27", + "version": "0.7.28", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 32e80036764de55f5c9fc1db4dea5fe7511894af Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Wed, 2 Mar 2016 18:12:44 -0800 Subject: [PATCH 039/108] Release v0.8.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc58733..d201c6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.5", + "version": "0.8.6", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From a0ec02b8e794abd311628427f34a51ae28c849bf Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 3 Mar 2016 16:46:48 -0800 Subject: [PATCH 040/108] feat(): support generic method calls. A leftover forgotten for #348. --- lib/call.ts | 10 +++++----- test/call_test.ts | 5 +++-- test/function_test.ts | 11 +++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/call.ts b/lib/call.ts index f854a95..cb1f834 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -52,12 +52,12 @@ export default class CallTranspiler extends base.TranspilerBase { } else { this.visit(c.expression); } - // Type arguments on methods are ignored. Dart doesn't support - // generic methods, and while we don't allow them to be declared - // in ts2dart, it's possible the method being called is not - // transpiled by ts2dart. - if (c.typeArguments && c.kind === ts.SyntaxKind.NewExpression) { + if (c.typeArguments) { + // For DDC, emit generic method arguments in /* block comments */ + // TODO(martinprobst): Remove once Dart natively supports generic methods. + if (c.kind !== ts.SyntaxKind.NewExpression) this.emit('/*'); this.maybeVisitTypeArguments(c); + if (c.kind !== ts.SyntaxKind.NewExpression) this.emit('*/'); } this.emit('('); if (c.arguments && !this.handleNamedParamsCall(c)) { diff --git a/test/call_test.ts b/test/call_test.ts index a8521af..5bc75dc 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -31,8 +31,9 @@ describe('calls', () => { expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); }); - it('throws away generic type parameters', - () => { expectTranslate('var s = foo();').to.equal('var s = foo();'); }); + it('supports generic type parameters', () => { + expectTranslate('var s = foo();').to.equal('var s = foo /* < String > */ ();'); + }); it('translates "super()" constructor calls', () => { expectTranslate('class X { constructor() { super(1); } }').to.equal(`class X { X() : super(1) { diff --git a/test/function_test.ts b/test/function_test.ts index d05c7e0..2c98e93 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -74,4 +74,15 @@ describe('generic functions', () => { return t; }`); }); + it('translates generic calls', () => { + expectTranslate( + `function wobble(foo: T): T { return foo; } + let f = foo('hello');`, + {translateBuiltins: true}) + .to.equal(`dynamic/*= T */ wobble/*< T >*/(dynamic/*= T */ foo) { + return foo; +} + +var f = foo /* < String > */ ("hello");`); + }); }); From 841e884db4f179890d84cb438e34c6141d6859f1 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 3 Mar 2016 16:47:56 -0800 Subject: [PATCH 041/108] rel: 0.7.29. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae42f6d..989a909 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.28", + "version": "0.7.29", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 22b27169e2fb9e01d6d2eaea7a63693960b7c215 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 3 Mar 2016 21:27:13 -0800 Subject: [PATCH 042/108] fix(): handle significant whitespace in DDC generic functions. Surprisingly, in DDC the whitespace in generic function type parameters is significant. I.e. `x/**/()` works, whereas `x/* */()` fails. Kind of hopefully fingers crossed fixes #348. --- lib/base.ts | 2 +- lib/call.ts | 3 ++- test/call_test.ts | 2 +- test/function_test.ts | 2 +- test/type_test.ts | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/base.ts b/lib/base.ts index 5c2c79a..c3826d3 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -94,7 +94,7 @@ export class TranspilerBase { if (n.typeArguments.length == 1 && n.typeArguments[0].kind == ts.SyntaxKind.VoidKeyword) { return; } - this.emit('<'); + this.emitNoSpace('<'); this.visitList(n.typeArguments); this.emit('>'); } diff --git a/lib/call.ts b/lib/call.ts index cb1f834..1e38f52 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -54,10 +54,11 @@ export default class CallTranspiler extends base.TranspilerBase { } if (c.typeArguments) { // For DDC, emit generic method arguments in /* block comments */ + // NB: Surprisingly, whitespace within the comment is significant here :-( // TODO(martinprobst): Remove once Dart natively supports generic methods. if (c.kind !== ts.SyntaxKind.NewExpression) this.emit('/*'); this.maybeVisitTypeArguments(c); - if (c.kind !== ts.SyntaxKind.NewExpression) this.emit('*/'); + if (c.kind !== ts.SyntaxKind.NewExpression) this.emitNoSpace('*/'); } this.emit('('); if (c.arguments && !this.handleNamedParamsCall(c)) { diff --git a/test/call_test.ts b/test/call_test.ts index 5bc75dc..6b16a47 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -32,7 +32,7 @@ describe('calls', () => { expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); }); it('supports generic type parameters', () => { - expectTranslate('var s = foo();').to.equal('var s = foo /* < String > */ ();'); + expectTranslate('var s = foo();').to.equal('var s = foo/*< String >*/();'); }); it('translates "super()" constructor calls', () => { expectTranslate('class X { constructor() { super(1); } }').to.equal(`class X { diff --git a/test/function_test.ts b/test/function_test.ts index 2c98e93..200e132 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -83,6 +83,6 @@ describe('generic functions', () => { return foo; } -var f = foo /* < String > */ ("hello");`); +var f = foo/*< String >*/("hello");`); }); }); diff --git a/test/type_test.ts b/test/type_test.ts index 616919c..3509318 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -19,10 +19,10 @@ describe('types', () => { }); it('should support union types', () => { expectTranslate('var x: number|List = 11;') - .to.equal('dynamic /* num | List < String > */ x = 11;'); + .to.equal('dynamic /* num | List< String > */ x = 11;'); expectTranslate('function x(): number|List<{[k: string]: any}> { return 11; }') .to.equal( - 'dynamic /* num | List < Map < String , dynamic > > */ x() {\n' + + 'dynamic /* num | List< Map < String , dynamic > > */ x() {\n' + ' return 11;\n' + '}'); }); From a594d026ae4576e8b6fe07d5608a8a341e2b250f Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 3 Mar 2016 21:29:04 -0800 Subject: [PATCH 043/108] rel: 0.7.30. --- package.json | 2 +- test/call_test.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 989a909..49cfc88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.29", + "version": "0.7.30", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", diff --git a/test/call_test.ts b/test/call_test.ts index 6b16a47..ab66514 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -31,9 +31,8 @@ describe('calls', () => { expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); expectTranslate('new Foo(1, 2);').to.equal('new Foo(1, 2);'); }); - it('supports generic type parameters', () => { - expectTranslate('var s = foo();').to.equal('var s = foo/*< String >*/();'); - }); + it('supports generic type parameters', + () => { expectTranslate('var s = foo();').to.equal('var s = foo/*< String >*/();'); }); it('translates "super()" constructor calls', () => { expectTranslate('class X { constructor() { super(1); } }').to.equal(`class X { X() : super(1) { From 935d4533b6b956b9cbab79705194d8a764ea79a4 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 3 Mar 2016 21:34:24 -0800 Subject: [PATCH 044/108] rel: 0.7.31. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 49cfc88..1939be2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.7.30", + "version": "0.7.31", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 4f5a67ed5b48e80a306fa5c4667431aa31ab2e95 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Tue, 8 Mar 2016 17:52:35 -0800 Subject: [PATCH 045/108] Release v0.8.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d201c6c..64d08b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.6", + "version": "0.8.7", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From c313fbb8384c4774fc2aa8a66d880437768ed101 Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Wed, 2 Mar 2016 08:55:48 -0800 Subject: [PATCH 046/108] Pull in version of dart-style that does not pollute global with a stub for document. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64d08b0..3fa0f77 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test": "test" }, "dependencies": { - "dart-style": "^0.2.6", + "dart-style": "^0.2.7", "minimist": "^1.1.1", "source-map": "^0.4.2", "source-map-support": "^0.3.1", From ac5ac86eccb0fe7a6ad61a5cdbc7746d43cdd514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Wed, 9 Mar 2016 14:05:27 -0800 Subject: [PATCH 047/108] fix: ensure that numbers are temporarily casted to ints for bitwise operations --- lib/expression.ts | 78 +++++++++++++++++++++++++++++++---------- test/expression_test.ts | 22 ++++++------ 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/lib/expression.ts b/lib/expression.ts index 9d974ea..ea72758 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -11,31 +11,67 @@ export default class ExpressionTranspiler extends base.TranspilerBase { case ts.SyntaxKind.BinaryExpression: var binExpr = node; var operatorKind = binExpr.operatorToken.kind; - if (operatorKind === ts.SyntaxKind.EqualsEqualsEqualsToken || - operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) { - if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) this.emit('!'); - this.emit('identical ('); - this.visit(binExpr.left); - this.emit(','); - this.visit(binExpr.right); - this.emit(')'); - } else { - this.visit(binExpr.left); - if (operatorKind === ts.SyntaxKind.InstanceOfKeyword) { + var tokenStr = ts.tokenToString(operatorKind); + switch (operatorKind) { + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) this.emit('!'); + this.emit('identical ('); + this.visit(binExpr.left); + this.emit(','); + this.visit(binExpr.right); + this.emit(')'); + break; + case ts.SyntaxKind.CaretToken: + case ts.SyntaxKind.BarToken: + case ts.SyntaxKind.AmpersandToken: + case ts.SyntaxKind.GreaterThanGreaterThanToken: + case ts.SyntaxKind.LessThanLessThanToken: + case ts.SyntaxKind.CaretEqualsToken: + case ts.SyntaxKind.BarEqualsToken: + case ts.SyntaxKind.AmpersandEqualsToken: + case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: + case ts.SyntaxKind.LessThanLessThanEqualsToken: + // In Dart, the bitwise operators are only available on int, so the number types ts2dart + // deals with have to be converted to int explicitly to match JS's semantics in Dart. + if (tokenStr[tokenStr.length - 1] == "=") { + // For assignments, strip the trailing `=` sign to emit just the operator itself. + this.visit(binExpr.left); + this.emit('='); + visitAndWrapAsInt(this, binExpr.left); + this.emit(tokenStr.slice(0, -1)); + } else { + // normal case (LHS [op]) + visitAndWrapAsInt(this, binExpr.left); + this.emit(tokenStr); + } + visitAndWrapAsInt(this, binExpr.right); + break; + case ts.SyntaxKind.InKeyword: + this.reportError(node, 'in operator is unsupported'); + break; + case ts.SyntaxKind.InstanceOfKeyword: + this.visit(binExpr.left); this.emit('is'); this.fc.visitTypeName(binExpr.right); - } else if (operatorKind == ts.SyntaxKind.InKeyword) { - this.reportError(node, 'in operator is unsupported'); - } else { - this.emit(ts.tokenToString(binExpr.operatorToken.kind)); + break; + default: + this.visit(binExpr.left); + this.emit(tokenStr); this.visit(binExpr.right); - } + break; } break; case ts.SyntaxKind.PrefixUnaryExpression: var prefixUnary = node; - this.emit(ts.tokenToString(prefixUnary.operator)); - this.visit(prefixUnary.operand); + var operator = ts.tokenToString(prefixUnary.operator); + this.emit(operator); + + if (prefixUnary.operator === ts.SyntaxKind.TildeToken) { + visitAndWrapAsInt(this, prefixUnary.operand); + } else { + this.visit(prefixUnary.operand); + } break; case ts.SyntaxKind.PostfixUnaryExpression: var postfixUnary = node; @@ -96,3 +132,9 @@ export default class ExpressionTranspiler extends base.TranspilerBase { return true; } } + +function visitAndWrapAsInt(visitor: ExpressionTranspiler, ident: ts.Node) { + visitor.emit('('); + visitor.visit(ident); + visitor.emit('as int)'); +} diff --git a/test/expression_test.ts b/test/expression_test.ts index ed1da8f..2a0057d 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -31,12 +31,12 @@ describe('expressions', () => { 'x *= 1': 'x *= 1;', 'x /= 1': 'x /= 1;', 'x %= 1': 'x %= 1;', - 'x <<= 1': 'x <<= 1;', - 'x >>= 1': 'x >>= 1;', + 'x <<= 1': 'x = (x as int) << (1 as int);', + 'x >>= 1': 'x = (x as int) >> (1 as int);', // 'x >>>= 1': 'x >>>= 1;', // This doesn't appear to be a valid operator in Dart. - 'x &= 1': 'x &= 1;', - 'x ^= 1': 'x ^= 1;', - 'x |= 1': 'x |= 1;', + 'x &= 1': 'x = (x as int) & (1 as int);', + 'x ^= 1': 'x = (x as int) ^ (1 as int);', + 'x |= 1': 'x = (x as int) | (1 as int);', }); }); it('compares', () => { @@ -55,12 +55,12 @@ describe('expressions', () => { }); it('bit fiddles', () => { expectTranslates({ - '1 & 2': '1 & 2;', - '1 | 2': '1 | 2;', - '1 ^ 2': '1 ^ 2;', - '~1': '~1;', - '1 << 2': '1 << 2;', - '1 >> 2': '1 >> 2;', + '1 & 2': '(1 as int) & (2 as int);', + '1 | 2': '(1 as int) | (2 as int);', + '1 ^ 2': '(1 as int) ^ (2 as int);', + '~1': '~(1 as int);', + '1 << 2': '(1 as int) << (2 as int);', + '1 >> 2': '(1 as int) >> (2 as int);', // '1 >>> 2': '1 >>> 2;', // This doesn't appear to be a valid operator in Dart. }); }); From 87d5419fb8645f395029413d7e4d0e172ba90aa9 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 9 Mar 2016 17:12:07 -0800 Subject: [PATCH 048/108] rel: 0.8.8. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3fa0f77..20d6908 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.7", + "version": "0.8.8", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 0a8aed9d7daa1492a9c6b80d89afa93594696f8c Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 14 Mar 2016 18:21:28 -0700 Subject: [PATCH 049/108] chore: make a slightly cleaner bitwise comparison. Reviewers: rkirov Reviewed By: rkirov Differential Revision: http://reviews.angular.io/D2 --- lib/facade_converter.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 5a8216d..7a7d228 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -259,8 +259,7 @@ export class FacadeConverter extends base.TranspilerBase { var qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, // for the time being just special case. - if (symbol.flags & ts.SymbolFlags.Function || symbol.flags & ts.SymbolFlags.Variable || - symbol.flags & ts.SymbolFlags.Class) { + if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) { qname = symbol.getName(); } if (FACADE_DEBUG) console.log('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); From f35694269ec92a5c102fa074041471a8405d7891 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 14 Mar 2016 18:02:42 -0700 Subject: [PATCH 050/108] feat: log errors to stderr. Summary: Fixes #349. Reviewers: rkirov Reviewed By: rkirov Differential Revision: https://reviews.angular.io/D3 --- lib/facade_converter.ts | 6 +++--- lib/main.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 7a7d228..73708ae 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -202,7 +202,7 @@ export class FacadeConverter extends base.TranspilerBase { ident = base.ident(expr); if (!this.candidateProperties.hasOwnProperty(ident)) return {}; symbol = this.tc.getSymbolAtLocation(expr); - if (FACADE_DEBUG) console.log('s:', symbol); + if (FACADE_DEBUG) console.error('s:', symbol); if (!symbol) { this.reportMissingType(c, ident); @@ -217,7 +217,7 @@ export class FacadeConverter extends base.TranspilerBase { if (!this.candidateProperties.hasOwnProperty(ident)) return {}; symbol = this.tc.getSymbolAtLocation(pa); - if (FACADE_DEBUG) console.log('s:', symbol); + if (FACADE_DEBUG) console.error('s:', symbol); // Error will be reported by PropertyAccess handling below. if (!symbol) return {}; @@ -262,7 +262,7 @@ export class FacadeConverter extends base.TranspilerBase { if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) { qname = symbol.getName(); } - if (FACADE_DEBUG) console.log('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); + if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); return {fileName: canonicalFileName, qname}; } diff --git a/lib/main.ts b/lib/main.ts index c9b5365..e8fcc74 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -381,11 +381,11 @@ if (require.main === module) { var args = require('minimist')(process.argv.slice(2), {base: 'string'}); try { let transpiler = new Transpiler(args); - console.log('Transpiling', args._, 'to', args.destination); + console.error('Transpiling', args._, 'to', args.destination); transpiler.transpile(args._, args.destination); } catch (e) { if (e.name !== 'TS2DartError') throw e; - console.log(e.message); + console.error(e.message); process.exit(1); } } From 1abcc3c5beef8365ec55fa7d89c430b49ad8c144 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 23 Mar 2016 17:50:00 +0100 Subject: [PATCH 051/108] feat: support container literals with reified types. Summary: feat: support container literals with reified types. Dart containers (lists and maps) store reified types. Special case TypeScript type assertions so that `ContainerLiteral` translates to Dart's reified type syntax. Fixes #356. Reviewers: alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D19 --- lib/type.ts | 73 ++++++++++++++++++++++++++++++++++++----------- test/type_test.ts | 4 +++ 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/type.ts b/lib/type.ts index 5d95362..237c907 100644 --- a/lib/type.ts +++ b/lib/type.ts @@ -9,34 +9,34 @@ export default class TypeTranspiler extends base.TranspilerBase { visitNode(node: ts.Node): boolean { switch (node.kind) { case ts.SyntaxKind.TypeLiteral: - let members = (node).members; - if (members.length == 1 && members[0].kind == ts.SyntaxKind.IndexSignature) { - let indexSig = (members[0]); - if (indexSig.parameters.length > 1) { - this.reportError(indexSig, "Expected an index signature to have a single parameter"); - } + let indexType = this.maybeDestructureIndexType(node); + if (indexType) { + // This is effectively a Map. this.emit('Map <'); - this.visit(indexSig.parameters[0].type); + this.visit(indexType[0]); this.emit(','); - this.visit(indexSig.type); + this.visit(indexType[1]); this.emit('>'); - break; + } else { + // Dart doesn't support other type literals. + this.emit('dynamic'); } - // Dart doesn't support other type literals. - this.emit('dynamic'); break; case ts.SyntaxKind.UnionType: this.emit('dynamic /*'); - this.visitList((node).types, "|"); + this.visitList((node).types, '|'); this.emit('*/'); break; case ts.SyntaxKind.TypeReference: - var typeRef = node; + let typeRef = node; this.fc.visitTypeName(typeRef.typeName); this.maybeVisitTypeArguments(typeRef); break; case ts.SyntaxKind.TypeAssertionExpression: - var typeAssertExpr = node; + let typeAssertExpr = node; + if (this.maybeHandleReifiedTypeLiteral(typeAssertExpr)) { + break; + } this.emit('('); this.visit(typeAssertExpr.expression); this.emit('as'); @@ -44,7 +44,7 @@ export default class TypeTranspiler extends base.TranspilerBase { this.emit(')'); break; case ts.SyntaxKind.TypeParameter: - var typeParam = node; + let typeParam = node; this.visit(typeParam.name); if (typeParam.constraint) { this.emit('extends'); @@ -63,13 +63,13 @@ export default class TypeTranspiler extends base.TranspilerBase { this.emit('*/'); break; case ts.SyntaxKind.QualifiedName: - var first = node; + let first = node; this.visit(first.left); this.emit('.'); this.visit(first.right); break; case ts.SyntaxKind.Identifier: - var ident = node; + let ident = node; this.fc.visitTypeName(ident); break; case ts.SyntaxKind.NumberKeyword: @@ -92,4 +92,43 @@ export default class TypeTranspiler extends base.TranspilerBase { } return true; } + + maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] { + let members = node.members; + if (members.length != 1 || members[0].kind != ts.SyntaxKind.IndexSignature) { + return null; + } + let indexSig = (members[0]); + if (indexSig.parameters.length > 1) { + this.reportError(indexSig, 'Expected an index signature to have a single parameter'); + } + return [indexSig.parameters[0].type, indexSig.type]; + } + + maybeHandleReifiedTypeLiteral(node: ts.TypeAssertion): boolean { + if (node.expression.kind === ts.SyntaxKind.ArrayLiteralExpression && + node.type.kind === ts.SyntaxKind.ArrayType) { + this.emit('<'); + this.visit((node.type).elementType); + this.emit('>'); + this.visit(node.expression); + return true; + } else if ( + node.expression.kind === ts.SyntaxKind.ObjectLiteralExpression && + node.type.kind === ts.SyntaxKind.TypeLiteral) { + let it = this.maybeDestructureIndexType(node.type); + if (!it) { + this.reportError(node, 'expected {[k]: v} type on object literal'); + return false; + } + this.emit('<'); + this.visit(it[0]); + this.emit(','); + this.visit(it[1]); + this.emit('>'); + this.visit(node.expression); + return true; + } + return false; + } } diff --git a/test/type_test.ts b/test/type_test.ts index 3509318..7874c7d 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -13,6 +13,10 @@ describe('types', () => { it('drops type literals with index signatures and other properties', () => { expectTranslate('var x: {a: number, [k: string]: number};').to.equal('dynamic x;'); }); it('allows typecasts', () => { expectTranslate('ref').to.equal('(ref as MyType);'); }); + it('translates typecasts to reified types on literals', () => { + expectTranslate('let x = [];').to.equal('var x = [];'); + expectTranslate('let x = <{[k:string]: number}>{};').to.equal('var x = {};'); + }); it('does not mangle prototype names', () => { expectTranslate('import toString = require("./somewhere");') .to.equal('import "somewhere.dart" as toString;'); From 8d94b243bb78c0618d794b34f8f9bfc53325fa6c Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 23 Mar 2016 17:53:39 +0100 Subject: [PATCH 052/108] rel: 0.8.9. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 20d6908..9f3a715 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.8", + "version": "0.8.9", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 36dca3a4d99f6b5a85c606e9cd7ca94fc45c82ff Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 4 Apr 2016 16:31:18 +0200 Subject: [PATCH 053/108] feat: support types on named parameters. Summary: TypeScript object binding patterns split parameters names, types, and initializers into three groups. This merges the three groups when emitting Dart named parameters. Fixes #357. Reviewers: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D39 --- lib/declaration.ts | 66 +++++++++++++++++++++++++++---------------- test/call_test.ts | 4 +-- test/function_test.ts | 9 +++--- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 59d53cd..aa94659 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -183,20 +183,6 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visit(paramDecl.initializer); } break; - case ts.SyntaxKind.ObjectBindingPattern: - var bindingPattern = node; - this.emit('{'); - this.visitList(bindingPattern.elements); - this.emit('}'); - break; - case ts.SyntaxKind.BindingElement: - var bindingElement = node; - this.visit(bindingElement.name); - if (bindingElement.initializer) { - this.emit(':'); - this.visit(bindingElement.initializer); - } - break; case ts.SyntaxKind.StaticKeyword: this.emit('static'); @@ -382,9 +368,9 @@ export default class DeclarationTranspiler extends base.TranspilerBase { if (this.isConst(decl) && !(>decl.members) .some((m) => m.kind == ts.SyntaxKind.Constructor)) { - this.emit("const"); + this.emit('const'); this.fc.visitTypeName(decl.name); - this.emit("();") + this.emit('();') } this.emit('}'); } @@ -435,18 +421,50 @@ export default class DeclarationTranspiler extends base.TranspilerBase { private visitNamedParameter(paramDecl: ts.ParameterDeclaration) { this.visitDecorators(paramDecl.decorators); - if (paramDecl.type) { - // TODO(martinprobst): These are currently silently ignored. - // this.reportError(paramDecl.type, 'types on named parameters are unsupported'); + let bp = paramDecl.name; + let typeMap: ts.Map = {}; + if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.TypeLiteral) { + for (let tn of(paramDecl.type).members) { + if (tn.kind !== ts.SyntaxKind.PropertySignature) { + this.reportError(tn, 'unsupported named parameter kind ' + tn.kind); + continue; + } + let pd = tn; + typeMap[base.ident(pd.name)] = pd.type; + } } - this.visit(paramDecl.name); + let initMap: ts.Map = {}; if (paramDecl.initializer) { - if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression || - (paramDecl.initializer).properties.length > 0) { - this.reportError( - paramDecl, 'initializers for named parameters must be empty object literals'); + if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) { + this.reportError(paramDecl, 'initializers for named parameters must be object literals'); + return; + } + for (let i of(paramDecl.initializer).properties) { + if (i.kind !== ts.SyntaxKind.PropertyAssignment) { + this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind); + continue; + } + let ole = i; + initMap[base.ident(ole.name)] = ole.initializer; + } + } + this.emit('{'); + for (let i = 0; i < bp.elements.length; i++) { + let elem = bp.elements[i]; + let type = typeMap[base.ident(elem.name)]; + if (type) this.visit(type); + this.visit(elem.name); + if (elem.initializer && initMap[base.ident(elem.name)]) { + this.reportError(elem, 'cannot have both an inner and outer initializer'); } + let init = elem.initializer || initMap[base.ident(elem.name)]; + if (init) { + this.emit(':'); + this.visit(init); + } + if (i + 1 < bp.elements.length) this.emit(','); } + this.emit('}'); } /** diff --git a/test/call_test.ts b/test/call_test.ts index ab66514..91b1518 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -6,9 +6,9 @@ describe('calls', () => { expectTranslate('function x({p = null, d = false} = {}) {}') .to.equal('x({p: null, d: false}) {}'); expectErroneousCode('function x({a=false}={a:true})') - .to.throw('initializers for named parameters must be empty object literals'); + .to.throw('cannot have both an inner and outer initializer'); expectErroneousCode('function x({a=false}=true)') - .to.throw('initializers for named parameters must be empty object literals'); + .to.throw('initializers for named parameters must be object literals'); expectTranslate('class X { constructor() { super({p: 1}); } }').to.equal(`class X { X() : super(p: 1) { /* super call moved to initializer */; diff --git a/test/function_test.ts b/test/function_test.ts index 200e132..a8a6c85 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -32,10 +32,11 @@ describe('functions', () => { return a + b; }`); }); - // TODO(martinprobst): Support types on named parameters. - it.skip('fails for types on named parameters', () => { - expectErroneousCode('function x({a}: number) { return a + b; }') - .to.throw('types on named parameters are unsupported'); + it('supports types on named parameters', () => { + expectTranslate('function x({a = 1, b = 2}: {a: number, b: number} = {}) { return a + b; }') + .to.equal(`x({num a: 1, num b: 2}) { + return a + b; +}`); }); it('does not support var args', () => { expectErroneousCode('function x(...a: number) { return 42; }') From 09b7fde43b4ccc6bcd6f8bd2a470fb71fbb2a52c Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 4 Apr 2016 15:08:42 +0200 Subject: [PATCH 054/108] feat: handle const reified generics. Summary: `const` is emitted by the literal expression handler, so the type assertion must be handled there, too - otherwise the const part gets mixed in with the reified type. Fixes #359. Reviewers: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D38 --- lib/base.ts | 13 +++++++++++++ lib/call.ts | 12 +----------- lib/facade_converter.ts | 2 +- lib/literal.ts | 35 +++++++++++++++++++++++++++++++++-- lib/type.ts | 34 ++++------------------------------ test/facade_converter_test.ts | 13 +++++++++++++ 6 files changed, 65 insertions(+), 44 deletions(-) diff --git a/lib/base.ts b/lib/base.ts index c3826d3..b570447 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -82,6 +82,19 @@ export class TranspilerBase { }); } + maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] { + let members = node.members; + if (members.length != 1 || members[0].kind != ts.SyntaxKind.IndexSignature) { + return null; + } + let indexSig = (members[0]); + if (indexSig.parameters.length > 1) { + this.reportError(indexSig, 'Expected an index signature to have a single parameter'); + } + return [indexSig.parameters[0].type, indexSig.type]; + } + + getRelativeFileName(fileName: string): string { return this.transpiler.getRelativeFileName(fileName); } diff --git a/lib/call.ts b/lib/call.ts index 1e38f52..cd08bd7 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -20,7 +20,7 @@ export default class CallTranspiler extends base.TranspilerBase { if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) { // Constructor calls in annotations must be const constructor calls. this.emit('const'); - } else if (this.isInsideConstExpr(node)) { + } else if (this.fc.isInsideConstExpr(node)) { this.emit('const'); } else { // Some implementations can replace the `new` keyword. @@ -67,16 +67,6 @@ export default class CallTranspiler extends base.TranspilerBase { this.emit(')'); } - private isInsideConstExpr(node: ts.Node): boolean { - return this.isConstCall( - this.getAncestor(node, ts.SyntaxKind.CallExpression)); - } - - private isConstCall(node: ts.CallExpression): boolean { - // TODO: Align with facade_converter.ts - return node && base.ident(node.expression) === 'CONST_EXPR'; - } - private handleNamedParamsCall(c: ts.CallExpression): boolean { // Preamble: This is all committed in the name of backwards compat with the traceur transpiler. diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 73708ae..6cee5d3 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -289,7 +289,7 @@ export class FacadeConverter extends base.TranspilerBase { this.getAncestor(node, ts.SyntaxKind.CallExpression)); } - private isConstCall(node: ts.CallExpression): boolean { + isConstCall(node: ts.CallExpression): boolean { return node && base.ident(node.expression) === 'CONST_EXPR'; } diff --git a/lib/literal.ts b/lib/literal.ts index 745c8fd..3b10efc 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -50,14 +50,18 @@ export default class LiteralTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.ArrayLiteralExpression: if (this.shouldBeConst(node)) this.emit('const'); + let ale = node; + this.handleReifiedArray(ale); this.emit('['); - this.visitList((node).elements); + this.visitList(ale.elements); this.emit(']'); break; case ts.SyntaxKind.ObjectLiteralExpression: if (this.shouldBeConst(node)) this.emit('const'); + let ole = node; + this.handleReifiedMap(ole); this.emit('{'); - this.visitList((node).properties); + this.visitList(ole.properties); this.emit('}'); break; case ts.SyntaxKind.PropertyAssignment: @@ -130,4 +134,31 @@ export default class LiteralTranspiler extends base.TranspilerBase { private escapeTextForTemplateString(n: ts.Node): string { return (n).text.replace(/\\/g, '\\\\').replace(/([$'])/g, '\\$1'); } + + private handleReifiedArray(node: ts.ArrayLiteralExpression) { + if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return; + let ta = node.parent; + if (ta.type.kind !== ts.SyntaxKind.ArrayType) return; + this.emit('<'); + this.visit((ta.type).elementType); + this.emit('>'); + return true; + } + + + private handleReifiedMap(node: ts.ObjectLiteralExpression) { + if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return; + let ta = node.parent; + if (ta.type.kind !== ts.SyntaxKind.TypeLiteral) return; + let it = this.maybeDestructureIndexType(ta.type); + if (!it) { + this.reportError(node, 'expected {[k]: v} type on object literal'); + return; + } + this.emit('<'); + this.visit(it[0]); + this.emit(','); + this.visit(it[1]); + this.emit('>'); + } } diff --git a/lib/type.ts b/lib/type.ts index 237c907..fa15a61 100644 --- a/lib/type.ts +++ b/lib/type.ts @@ -34,8 +34,9 @@ export default class TypeTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.TypeAssertionExpression: let typeAssertExpr = node; - if (this.maybeHandleReifiedTypeLiteral(typeAssertExpr)) { - break; + if (this.isReifiedTypeLiteral(typeAssertExpr)) { + this.visit(typeAssertExpr.expression); + break; // type is handled by the container literal itself. } this.emit('('); this.visit(typeAssertExpr.expression); @@ -93,40 +94,13 @@ export default class TypeTranspiler extends base.TranspilerBase { return true; } - maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] { - let members = node.members; - if (members.length != 1 || members[0].kind != ts.SyntaxKind.IndexSignature) { - return null; - } - let indexSig = (members[0]); - if (indexSig.parameters.length > 1) { - this.reportError(indexSig, 'Expected an index signature to have a single parameter'); - } - return [indexSig.parameters[0].type, indexSig.type]; - } - - maybeHandleReifiedTypeLiteral(node: ts.TypeAssertion): boolean { + isReifiedTypeLiteral(node: ts.TypeAssertion): boolean { if (node.expression.kind === ts.SyntaxKind.ArrayLiteralExpression && node.type.kind === ts.SyntaxKind.ArrayType) { - this.emit('<'); - this.visit((node.type).elementType); - this.emit('>'); - this.visit(node.expression); return true; } else if ( node.expression.kind === ts.SyntaxKind.ObjectLiteralExpression && node.type.kind === ts.SyntaxKind.TypeLiteral) { - let it = this.maybeDestructureIndexType(node.type); - if (!it) { - this.reportError(node, 'expected {[k]: v} type on object literal'); - return false; - } - this.emit('<'); - this.visit(it[0]); - this.emit(','); - this.visit(it[1]); - this.emit('>'); - this.visit(node.expression); return true; } return false; diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index c566ab7..960e82b 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -362,6 +362,19 @@ const x = const {};`); .to.equal(`import "package:angular2/src/facade/collection.dart" show Map; const x = const {};`); + + expectWithTypes(` + import {CONST_EXPR} from "angular2/src/facade/lang"; + const _EMPTY_LIST = CONST_EXPR([]);`) + .to.equal(`const _EMPTY_LIST = const [];`); + expectWithTypes(` + import {CONST_EXPR} from "angular2/src/facade/lang"; + const _EMPTY_LIST = CONST_EXPR([]);`) + .to.equal(`const _EMPTY_LIST = const [];`); + expectWithTypes(` + import {CONST_EXPR} from "angular2/src/facade/lang"; + const MY_MAP = CONST_EXPR(<{[k: string]: number}>{});`) + .to.equal(`const MY_MAP = const {};`); }); it('translates forwardRef(() => T) to T', From c035ef370d8c100f5637dfb398b2dca6da174868 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 4 Apr 2016 14:34:02 +0200 Subject: [PATCH 055/108] feat: support function types in parameters. Summary: Dart does not support general function types, but has special-cased support for function types in parameters. Fixes #358. Reviewers: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D37 --- lib/declaration.ts | 13 +++++++++++-- test/e2e/helloworld.ts | 4 ++++ test/function_test.ts | 11 +++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index aa94659..354c090 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -176,8 +176,17 @@ export default class DeclarationTranspiler extends base.TranspilerBase { break; } this.visitDecorators(paramDecl.decorators); - if (paramDecl.type) this.visit(paramDecl.type); - this.visit(paramDecl.name); + + if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType) { + // Dart uses "returnType paramName ( parameters )" syntax. + let fnType = paramDecl.type; + this.visit(fnType.type); + this.visit(paramDecl.name); + this.visitParameters(fnType.parameters); + } else { + if (paramDecl.type) this.visit(paramDecl.type); + this.visit(paramDecl.name); + } if (paramDecl.initializer) { this.emit('='); this.visit(paramDecl.initializer); diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index 6136c20..d05e258 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -3,6 +3,9 @@ import t = require("test/test"); import {MyClass, MySubclass, SomeArray} from './lib'; +function callOne(a: (t: T) => U, t: T): U { + return a(t); +} function main(): void { t.test("handles classes", function() { @@ -27,6 +30,7 @@ function main(): void { t.expect(/o/g.exec("fo.o").length, t.equals(2)); }); t.test("const expr", function() { t.expect(SomeArray[0], t.equals(1)); }); + t.test('generic types fn', function() { t.expect(callOne((a) => a, 1), t.equals(1)); }); t.test("promises", function() { let p: Promise = new Promise((resolve) => { resolve(1); }); diff --git a/test/function_test.ts b/test/function_test.ts index a8a6c85..c869836 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -51,6 +51,17 @@ describe('functions', () => { expectTranslate('var a = (p = null) => isBlank(p)') .to.equal('var a = ([p = null]) => isBlank(p);'); }); + it('supports function parameters', () => { + expectTranslate('function f(fn: (a: A, b: B) => C) {}').to.equal('f(C fn(A a, B b)) {}'); + }); + it('supports recursive function parameters', () => { + expectTranslate('function f(fn: (a: (b: B) => C) => D) {}').to.equal('f(D fn(C a(B b))) {}'); + }); + it('supports generic-typed function parameters', () => { + expectTranslate('function f(fn: (a: T, b: U) => T) {}', { + translateBuiltins: true + }).to.equal('f/*< T, U >*/(dynamic/*= T */ fn(dynamic/*= T */ a, dynamic/*= U */ b)) {}'); + }); }); describe('generic functions', () => { From 39236456660c98c8e342bd390cf05e814ff4975f Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 4 Apr 2016 18:27:18 +0200 Subject: [PATCH 056/108] rel: 0.8.10. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f3a715..592506b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.9", + "version": "0.8.10", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From b0aba1e0d4ee9892947492365366f0dcd2118ee3 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 7 Apr 2016 11:47:01 +0200 Subject: [PATCH 057/108] chore: upgrade clang-format to 1.0.37. Summary: chore: adjust formatting for clang-format 1.0.37. feat: install tslint.json. Eating our own dog food, we should make sure tslint works well for us. The given configuration is a straw man, but overall seems to match what we've been doing so far. chore: fix lint. Reviewers: alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D43 --- gulpfile.js | 12 +++- lib/base.ts | 22 +++---- lib/call.ts | 56 ++++++++-------- lib/declaration.ts | 81 ++++++++++++------------ lib/expression.ts | 22 +++---- lib/facade_converter.ts | 116 +++++++++++++++++----------------- lib/literal.ts | 26 ++++---- lib/main.ts | 78 +++++++++++------------ lib/mkdirp.ts | 4 +- lib/module.ts | 42 ++++++------ lib/statement.ts | 36 +++++------ package.json | 4 +- test/declaration_test.ts | 2 +- test/e2e/helloworld.ts | 44 +++++++------ test/e2e/lib.ts | 22 +++---- test/e2e/test.d.ts | 6 +- test/expression_test.ts | 2 +- test/facade_converter_test.ts | 14 ++-- test/literal_test.ts | 20 +++--- test/main_test.ts | 12 ++-- test/module_test.ts | 6 +- test/statement_test.ts | 10 +-- test/test_support.ts | 31 +++++---- tsconfig.json | 2 +- tslint.json | 29 +++++++++ 25 files changed, 361 insertions(+), 338 deletions(-) create mode 100644 tslint.json diff --git a/gulpfile.js b/gulpfile.js index 5998e10..3a21f46 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,7 @@ var ts = require('gulp-typescript'); var typescript = require('typescript'); var style = require('dart-style'); var which = require('which'); +var tslint = require('gulp-tslint'); gulp.task('test.check-format', function() { return gulp.src(['*.js', 'lib/**/*.ts', 'test/**/*.ts']) @@ -21,6 +22,13 @@ gulp.task('test.check-format', function() { .on('warning', onError); }); +gulp.task('test.check-lint', function() { + return gulp.src(['lib/**/*.ts', 'test/**/*.ts']) + .pipe(tslint()) + .pipe(tslint.report('verbose')) + .on('warning', onError); +}); + var hasError; var failOnError = true; @@ -94,7 +102,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { // Paths must be relative to our source root, so run with cwd == dir. spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { if (code > 0) { - onError(new Error("Failed to transpile " + testfile + '.ts')); + onError(new Error('Failed to transpile ' + testfile + '.ts')); } else { try { var opts = {stdio: 'inherit', cwd: dir}; @@ -112,7 +120,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { }); }); -gulp.task('test', ['test.unit', 'test.check-format', 'test.e2e']); +gulp.task('test', ['test.check-format', 'test.check-lint', 'test.unit', 'test.e2e']); gulp.task('watch', ['test.unit'], function() { failOnError = false; diff --git a/lib/base.ts b/lib/base.ts index b570447..709b28a 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -6,15 +6,15 @@ export type ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration; export function ident(n: ts.Node): string { if (n.kind === ts.SyntaxKind.Identifier) return (n).text; if (n.kind === ts.SyntaxKind.QualifiedName) { - var qname = (n); - var leftName = ident(qname.left); + let qname = (n); + let leftName = ident(qname.left); if (leftName) return leftName + '.' + ident(qname.right); } return null; } export class TranspilerBase { - private id_: number = 0; + private idCounter: number = 0; constructor(private transpiler: Transpiler) {} visit(n: ts.Node) { this.transpiler.visit(n); } @@ -30,15 +30,15 @@ export class TranspilerBase { if (nodes) this.visitEach(nodes); } - visitList(nodes: ts.Node[], separator: string = ',') { - for (var i = 0; i < nodes.length; i++) { + visitList(nodes: ts.Node[], separator = ',') { + for (let i = 0; i < nodes.length; i++) { this.visit(nodes[i]); if (i < nodes.length - 1) this.emit(separator); } } uniqueId(name: string): string { - const id = this.id_++; + const id = this.idCounter++; return `_${name}\$\$ts2dart\$${id}`; } @@ -50,7 +50,7 @@ export class TranspilerBase { } getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node { - for (var parent = n; parent; parent = parent.parent) { + for (let parent = n; parent; parent = parent.parent) { if (parent.kind === kind) return parent; } return null; @@ -61,10 +61,10 @@ export class TranspilerBase { hasAnnotation(decorators: ts.NodeArray, name: string): boolean { if (!decorators) return false; return decorators.some((d) => { - var decName = ident(d.expression); + let decName = ident(d.expression); if (decName === name) return true; if (d.expression.kind !== ts.SyntaxKind.CallExpression) return false; - var callExpr = (d.expression); + let callExpr = (d.expression); decName = ident(callExpr.expression); return decName === name; }); @@ -84,7 +84,7 @@ export class TranspilerBase { maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] { let members = node.members; - if (members.length != 1 || members[0].kind != ts.SyntaxKind.IndexSignature) { + if (members.length !== 1 || members[0].kind !== ts.SyntaxKind.IndexSignature) { return null; } let indexSig = (members[0]); @@ -104,7 +104,7 @@ export class TranspilerBase { // If it's a single type argument ``, ignore it and emit nothing. // This is particularly useful for `Promise`, see // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639 - if (n.typeArguments.length == 1 && n.typeArguments[0].kind == ts.SyntaxKind.VoidKeyword) { + if (n.typeArguments.length === 1 && n.typeArguments[0].kind === ts.SyntaxKind.VoidKeyword) { return; } this.emitNoSpace('<'); diff --git a/lib/call.ts b/lib/call.ts index cd08bd7..86aa01b 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -1,7 +1,7 @@ import ts = require('typescript'); import base = require('./base'); import ts2dart = require('./main'); -import {FacadeConverter} from "./facade_converter"; +import {FacadeConverter} from './facade_converter'; export default class CallTranspiler extends base.TranspilerBase { constructor(tr: ts2dart.Transpiler, private fc: FacadeConverter) { super(tr); } @@ -16,7 +16,7 @@ export default class CallTranspiler extends base.TranspilerBase { } return false; case ts.SyntaxKind.NewExpression: - var newExpr = node; + let newExpr = node; if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) { // Constructor calls in annotations must be const constructor calls. this.emit('const'); @@ -32,7 +32,7 @@ export default class CallTranspiler extends base.TranspilerBase { this.visitCall(newExpr); break; case ts.SyntaxKind.CallExpression: - var callExpr = node; + let callExpr = node; if (this.fc.maybeHandleCall(callExpr)) break; if (this.maybeHandleSuperCall(callExpr)) break; this.visitCall(callExpr); @@ -47,7 +47,7 @@ export default class CallTranspiler extends base.TranspilerBase { } private visitCall(c: ts.CallExpression) { - if (c.expression.kind == ts.SyntaxKind.Identifier) { + if (c.expression.kind === ts.SyntaxKind.Identifier) { this.fc.visitTypeName(c.expression); } else { this.visit(c.expression); @@ -75,23 +75,23 @@ export default class CallTranspiler extends base.TranspilerBase { // declaration to take a plain object literal and destructure in the method, but then client // code written against Dart wouldn't get nice named parameters. if (c.arguments.length === 0) return false; - var last = c.arguments[c.arguments.length - 1]; + let last = c.arguments[c.arguments.length - 1]; if (last.kind !== ts.SyntaxKind.ObjectLiteralExpression) return false; - var objLit = last; + let objLit = last; if (objLit.properties.length === 0) return false; // Even worse: foo(a, b, {'c': d}) is considered to *not* be a named parameters call. - var hasNonPropAssignments = objLit.properties.some( + let hasNonPropAssignments = objLit.properties.some( (p) => - (p.kind != ts.SyntaxKind.PropertyAssignment || + (p.kind !== ts.SyntaxKind.PropertyAssignment || (p).name.kind !== ts.SyntaxKind.Identifier)); if (hasNonPropAssignments) return false; - var len = c.arguments.length - 1; + let len = c.arguments.length - 1; this.visitList(c.arguments.slice(0, len)); if (len) this.emit(','); - var props = objLit.properties; - for (var i = 0; i < props.length; i++) { - var prop = props[i]; + let props = objLit.properties; + for (let i = 0; i < props.length; i++) { + let prop = props[i]; this.emit(base.ident(prop.name)); this.emit(':'); this.visit(prop.initializer); @@ -112,27 +112,27 @@ export default class CallTranspiler extends base.TranspilerBase { * below. */ private visitConstructorBody(ctor: ts.ConstructorDeclaration): boolean { - var body = ctor.body; + let body = ctor.body; if (!body) return false; - var errorAssignmentsSuper = 'const constructors can only contain assignments and super calls'; - var errorThisAssignment = 'assignments in const constructors must assign into this.'; + let errorAssignmentsSuper = 'const constructors can only contain assignments and super calls'; + let errorThisAssignment = 'assignments in const constructors must assign into this.'; - var parent = ctor.parent; - var parentIsConst = this.isConst(parent); - var superCall: ts.CallExpression; - var expressions: ts.Expression[] = []; + let parent = ctor.parent; + let parentIsConst = this.isConst(parent); + let superCall: ts.CallExpression; + let expressions: ts.Expression[] = []; // Find super() calls and (if in a const ctor) collect assignment expressions (not statements!) body.statements.forEach((stmt) => { if (stmt.kind !== ts.SyntaxKind.ExpressionStatement) { if (parentIsConst) this.reportError(stmt, errorAssignmentsSuper); return; } - var nestedExpr = (stmt).expression; + let nestedExpr = (stmt).expression; // super() call? if (nestedExpr.kind === ts.SyntaxKind.CallExpression) { - var callExpr = nestedExpr; + let callExpr = nestedExpr; if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) { if (parentIsConst) this.reportError(stmt, errorAssignmentsSuper); return; @@ -148,7 +148,7 @@ export default class CallTranspiler extends base.TranspilerBase { this.reportError(nestedExpr, errorAssignmentsSuper); return; } - var binExpr = nestedExpr; + let binExpr = nestedExpr; if (binExpr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) { this.reportError(binExpr, errorAssignmentsSuper); return; @@ -158,18 +158,18 @@ export default class CallTranspiler extends base.TranspilerBase { this.reportError(binExpr, errorThisAssignment); return; } - var lhs = binExpr.left; + let lhs = binExpr.left; if (lhs.expression.kind !== ts.SyntaxKind.ThisKeyword) { this.reportError(binExpr, errorThisAssignment); return; } - var ident = lhs.name; + let ident = lhs.name; binExpr.left = ident; expressions.push(nestedExpr); } }); - var hasInitializerExpr = expressions.length > 0; + let hasInitializerExpr = expressions.length > 0; if (hasInitializerExpr) { // Write out the assignments. this.emit(':'); @@ -199,9 +199,9 @@ export default class CallTranspiler extends base.TranspilerBase { private maybeHandleSuperCall(callExpr: ts.CallExpression): boolean { if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) return false; // Sanity check that there was indeed a ctor directly above this call. - var exprStmt = callExpr.parent; - var ctorBody = exprStmt.parent; - var ctor = ctorBody.parent; + let exprStmt = callExpr.parent; + let ctorBody = exprStmt.parent; + let ctor = ctorBody.parent; if (ctor.kind !== ts.SyntaxKind.Constructor) { this.reportError(callExpr, 'super calls must be immediate children of their constructors'); return false; diff --git a/lib/declaration.ts b/lib/declaration.ts index 354c090..e91c5cd 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -13,11 +13,11 @@ export default class DeclarationTranspiler extends base.TranspilerBase { switch (node.kind) { case ts.SyntaxKind.VariableDeclarationList: // Note: VariableDeclarationList can only occur as part of a for loop. - var varDeclList = node; + let varDeclList = node; this.visitList(varDeclList.declarations); break; case ts.SyntaxKind.VariableDeclaration: - var varDecl = node; + let varDecl = node; this.visitVariableDeclarationType(varDecl); this.visit(varDecl.name); if (varDecl.initializer) { @@ -27,7 +27,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.ClassDeclaration: - var classDecl = node; + let classDecl = node; if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abstract)) { this.visitClassLike('abstract class', classDecl); } else { @@ -35,7 +35,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.InterfaceDeclaration: - var ifDecl = node; + let ifDecl = node; // Function type interface in an interface with a single declaration // of a call signature (http://goo.gl/ROC5jN). if (ifDecl.members.length === 1 && ifDecl.members[0].kind === ts.SyntaxKind.CallSignature) { @@ -46,9 +46,9 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.HeritageClause: - var heritageClause = node; + let heritageClause = node; if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword && - heritageClause.parent.kind != ts.SyntaxKind.InterfaceDeclaration) { + heritageClause.parent.kind !== ts.SyntaxKind.InterfaceDeclaration) { this.emit('extends'); } else { this.emit('implements'); @@ -57,14 +57,14 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visitList(heritageClause.types); break; case ts.SyntaxKind.ExpressionWithTypeArguments: - var exprWithTypeArgs = node; + let exprWithTypeArgs = node; this.visit(exprWithTypeArgs.expression); this.maybeVisitTypeArguments(exprWithTypeArgs); break; case ts.SyntaxKind.EnumDeclaration: - var decl = node; + let decl = node; // The only legal modifier for an enum decl is const. - var isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Const); + let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Const); if (isConst) { this.reportError(node, 'const enums are not supported'); } @@ -80,18 +80,18 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.emit('}'); break; case ts.SyntaxKind.EnumMember: - var member = node; + let member = node; this.visit(member.name); if (member.initializer) { this.reportError(node, 'enum initializers are not supported'); } break; case ts.SyntaxKind.Constructor: - var ctorDecl = node; + let ctorDecl = node; // Find containing class name. - var className: ts.Identifier; - for (var parent = ctorDecl.parent; parent; parent = parent.parent) { - if (parent.kind == ts.SyntaxKind.ClassDeclaration) { + let className: ts.Identifier; + for (let parent = ctorDecl.parent; parent; parent = parent.parent) { + if (parent.kind === ts.SyntaxKind.ClassDeclaration) { className = (parent).name; break; } @@ -124,16 +124,16 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visitFunctionLike(node, 'set'); break; case ts.SyntaxKind.FunctionDeclaration: - var funcDecl = node; + let funcDecl = node; this.visitDecorators(funcDecl.decorators); this.visitFunctionLike(funcDecl); break; case ts.SyntaxKind.ArrowFunction: - var arrowFunc = node; + let arrowFunc = node; // Dart only allows expressions following the fat arrow operator. // If the body is a block, we have to drop the fat arrow and emit an // anonymous function instead. - if (arrowFunc.body.kind == ts.SyntaxKind.Block) { + if (arrowFunc.body.kind === ts.SyntaxKind.Block) { this.visitFunctionLike(arrowFunc); } else { this.visitParameters(arrowFunc.parameters); @@ -142,20 +142,20 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.FunctionExpression: - var funcExpr = node; + let funcExpr = node; this.visitFunctionLike(funcExpr); break; case ts.SyntaxKind.PropertySignature: - var propSig = node; + let propSig = node; this.visitProperty(propSig); break; case ts.SyntaxKind.MethodSignature: - var methodSignatureDecl = node; + let methodSignatureDecl = node; this.visitEachIfPresent(methodSignatureDecl.modifiers); this.visitFunctionLike(methodSignatureDecl); break; case ts.SyntaxKind.Parameter: - var paramDecl = node; + let paramDecl = node; // Property parameters will have an explicit property declaration, so we just // need the dart assignment shorthand to reference the property. if (this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Public) || @@ -228,9 +228,9 @@ export default class DeclarationTranspiler extends base.TranspilerBase { * - A variable declaration list with a single variable can be explicitly typed. * - When more than one variable is in the list, all must be implicitly typed. */ - var firstDecl = varDecl.parent.declarations[0]; - var msg = 'Variables in a declaration list of more than one variable cannot by typed'; - var isConst = this.hasFlag(varDecl.parent, ts.NodeFlags.Const); + let firstDecl = varDecl.parent.declarations[0]; + let msg = 'Variables in a declaration list of more than one variable cannot by typed'; + let isConst = this.hasFlag(varDecl.parent, ts.NodeFlags.Const); if (firstDecl === varDecl) { if (isConst) this.emit('const'); if (!varDecl.type) { @@ -298,13 +298,13 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } if (firstInitParamIdx !== 0) { - var requiredParams = parameters.slice(0, firstInitParamIdx); + let requiredParams = parameters.slice(0, firstInitParamIdx); this.visitList(requiredParams); } if (firstInitParamIdx !== parameters.length) { if (firstInitParamIdx !== 0) this.emit(','); - var positionalOptional = parameters.slice(firstInitParamIdx, parameters.length); + let positionalOptional = parameters.slice(firstInitParamIdx, parameters.length); this.emit('['); this.visitList(positionalOptional); this.emit(']'); @@ -318,16 +318,15 @@ export default class DeclarationTranspiler extends base.TranspilerBase { * In the special case of property parameters in a constructor, we also allow a parameter to be * emitted as a property. */ - private visitProperty( - decl: ts.PropertyDeclaration | ts.ParameterDeclaration, isParameter: boolean = false) { + private visitProperty(decl: ts.PropertyDeclaration|ts.ParameterDeclaration, isParameter = false) { if (!isParameter) this.visitDeclarationMetadata(decl); - var containingClass = (isParameter ? decl.parent.parent : decl.parent); - var isConstField = this.hasAnnotation(decl.decorators, 'CONST'); + let containingClass = (isParameter ? decl.parent.parent : decl.parent); + let isConstField = this.hasAnnotation(decl.decorators, 'CONST'); + let hasConstCtor = this.isConst(containingClass); if (isConstField) { // const implies final this.emit('const'); } else { - var hasConstCtor = this.isConst(containingClass); if (hasConstCtor) { this.emit('final'); } @@ -367,7 +366,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } }; (>decl.members) - .filter((m) => m.kind == ts.SyntaxKind.Constructor) + .filter((m) => m.kind === ts.SyntaxKind.Constructor) .forEach( (ctor) => (ctor).parameters.forEach(synthesizePropertyParam)); @@ -376,10 +375,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { // Generate a constructor to host the const modifier, if needed if (this.isConst(decl) && !(>decl.members) - .some((m) => m.kind == ts.SyntaxKind.Constructor)) { + .some((m) => m.kind === ts.SyntaxKind.Constructor)) { this.emit('const'); this.fc.visitTypeName(decl.name); - this.emit('();') + this.emit('();'); } this.emit('}'); } @@ -389,10 +388,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { decorators.forEach((d) => { // Special case @CONST - var name = base.ident(d.expression); + let name = base.ident(d.expression); if (!name && d.expression.kind === ts.SyntaxKind.CallExpression) { // Unwrap @CONST() - var callExpr = (d.expression); + let callExpr = (d.expression); name = base.ident(callExpr.expression); } // Make sure these match IGNORED_ANNOTATIONS below. @@ -416,10 +415,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { if (!this.enforceUnderscoreConventions) return; // Early return in case this is a decl with no name, such as a constructor if (!decl.name) return; - var name = base.ident(decl.name); + let name = base.ident(decl.name); if (!name) return; - var isPrivate = this.hasFlag(decl.modifiers, ts.NodeFlags.Private); - var matchesPrivate = !!name.match(/^_/); + let isPrivate = this.hasFlag(decl.modifiers, ts.NodeFlags.Private); + let matchesPrivate = !!name.match(/^_/); if (isPrivate && !matchesPrivate) { this.reportError(decl, 'private members must be prefixed with "_"'); } @@ -433,7 +432,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { let bp = paramDecl.name; let typeMap: ts.Map = {}; if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.TypeLiteral) { - for (let tn of(paramDecl.type).members) { + for (let tn of (paramDecl.type).members) { if (tn.kind !== ts.SyntaxKind.PropertySignature) { this.reportError(tn, 'unsupported named parameter kind ' + tn.kind); continue; @@ -448,7 +447,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.reportError(paramDecl, 'initializers for named parameters must be object literals'); return; } - for (let i of(paramDecl.initializer).properties) { + for (let i of (paramDecl.initializer).properties) { if (i.kind !== ts.SyntaxKind.PropertyAssignment) { this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind); continue; diff --git a/lib/expression.ts b/lib/expression.ts index ea72758..c537abd 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -9,9 +9,9 @@ export default class ExpressionTranspiler extends base.TranspilerBase { visitNode(node: ts.Node): boolean { switch (node.kind) { case ts.SyntaxKind.BinaryExpression: - var binExpr = node; - var operatorKind = binExpr.operatorToken.kind; - var tokenStr = ts.tokenToString(operatorKind); + let binExpr = node; + let operatorKind = binExpr.operatorToken.kind; + let tokenStr = ts.tokenToString(operatorKind); switch (operatorKind) { case ts.SyntaxKind.EqualsEqualsEqualsToken: case ts.SyntaxKind.ExclamationEqualsEqualsToken: @@ -34,7 +34,7 @@ export default class ExpressionTranspiler extends base.TranspilerBase { case ts.SyntaxKind.LessThanLessThanEqualsToken: // In Dart, the bitwise operators are only available on int, so the number types ts2dart // deals with have to be converted to int explicitly to match JS's semantics in Dart. - if (tokenStr[tokenStr.length - 1] == "=") { + if (tokenStr[tokenStr.length - 1] === '=') { // For assignments, strip the trailing `=` sign to emit just the operator itself. this.visit(binExpr.left); this.emit('='); @@ -63,8 +63,8 @@ export default class ExpressionTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.PrefixUnaryExpression: - var prefixUnary = node; - var operator = ts.tokenToString(prefixUnary.operator); + let prefixUnary = node; + let operator = ts.tokenToString(prefixUnary.operator); this.emit(operator); if (prefixUnary.operator === ts.SyntaxKind.TildeToken) { @@ -74,12 +74,12 @@ export default class ExpressionTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.PostfixUnaryExpression: - var postfixUnary = node; + let postfixUnary = node; this.visit(postfixUnary.operand); this.emit(ts.tokenToString(postfixUnary.operator)); break; case ts.SyntaxKind.ConditionalExpression: - var conditional = node; + let conditional = node; this.visit(conditional.condition); this.emit('?'); this.visit(conditional.whenTrue); @@ -97,14 +97,14 @@ export default class ExpressionTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.ParenthesizedExpression: - var parenExpr = node; + let parenExpr = node; this.emit('('); this.visit(parenExpr.expression); this.emit(')'); break; case ts.SyntaxKind.PropertyAccessExpression: - var propAccess = node; + let propAccess = node; if (propAccess.name.text === 'stack' && this.hasAncestor(propAccess, ts.SyntaxKind.CatchClause)) { // Handle `e.stack` accesses in catch clauses by mangling to `e_stack`. @@ -119,7 +119,7 @@ export default class ExpressionTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.ElementAccessExpression: - var elemAccess = node; + let elemAccess = node; this.visit(elemAccess.expression); this.emit('['); this.visit(elemAccess.argumentExpression); diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 6cee5d3..9c5923e 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -30,7 +30,7 @@ export class FacadeConverter extends base.TranspilerBase { private typingsRootRegex: RegExp; private genericMethodDeclDepth = 0; - constructor(transpiler: Transpiler, typingsRoot: string = '') { + constructor(transpiler: Transpiler, typingsRoot = '') { super(transpiler); this.extractPropertyNames(this.callHandlers, this.candidateProperties); this.extractPropertyNames(this.propertyHandlers, this.candidateProperties); @@ -40,9 +40,9 @@ export class FacadeConverter extends base.TranspilerBase { } private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) { - for (var fileName in m) { - Object.keys(m[fileName]) - .filter((k) => m[fileName].hasOwnProperty(k)) + for (let fileName of Object.keys(m)) { + const file = m[fileName]; + Object.keys(file) .map((propName) => propName.substring(propName.lastIndexOf('.') + 1)) .forEach((propName) => candidates[propName] = true); } @@ -57,21 +57,21 @@ export class FacadeConverter extends base.TranspilerBase { // getCallInformation returns a symbol if we understand this call. return false; } - var handler = this.getHandler(c, symbol, this.callHandlers); + let handler = this.getHandler(c, symbol, this.callHandlers); return handler && !handler(c, context); } handlePropertyAccess(pa: ts.PropertyAccessExpression): boolean { if (!this.tc) return; - var ident = pa.name.text; + let ident = pa.name.text; if (!this.candidateProperties.hasOwnProperty(ident)) return false; - var symbol = this.tc.getSymbolAtLocation(pa.name); + let symbol = this.tc.getSymbolAtLocation(pa.name); if (!symbol) { this.reportMissingType(pa, ident); return false; } - var handler = this.getHandler(pa, symbol, this.propertyHandlers); + let handler = this.getHandler(pa, symbol, this.propertyHandlers); return handler && !handler(pa); } @@ -79,23 +79,23 @@ export class FacadeConverter extends base.TranspilerBase { * Searches for type references that require extra imports and emits the imports as necessary. */ emitExtraImports(sourceFile: ts.SourceFile) { - var libraries = >{ - "XMLHttpRequest": "dart:html", - "KeyboardEvent": "dart:html", - "Uint8Array": "dart:typed_arrays", - "ArrayBuffer": "dart:typed_arrays", - "Promise": "dart:async" + let libraries = >{ + 'XMLHttpRequest': 'dart:html', + 'KeyboardEvent': 'dart:html', + 'Uint8Array': 'dart:typed_arrays', + 'ArrayBuffer': 'dart:typed_arrays', + 'Promise': 'dart:async', }; - var emitted: Set = {}; + let emitted: Set = {}; this.emitImports(sourceFile, libraries, emitted, sourceFile); } private emitImports( n: ts.Node, libraries: ts.Map, emitted: Set, sourceFile: ts.SourceFile): void { if (n.kind === ts.SyntaxKind.TypeReference) { - var type = base.ident((n).typeName); + let type = base.ident((n).typeName); if (libraries.hasOwnProperty(type)) { - var toEmit = libraries[type]; + let toEmit = libraries[type]; if (!emitted[toEmit]) { this.emit(`import "${toEmit}";`); emitted[toEmit] = true; @@ -104,7 +104,7 @@ export class FacadeConverter extends base.TranspilerBase { } n.getChildren(sourceFile) - .forEach((n: ts.Node) => this.emitImports(n, libraries, emitted, sourceFile)); + .forEach((child: ts.Node) => this.emitImports(child, libraries, emitted, sourceFile)); } pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { @@ -134,7 +134,7 @@ export class FacadeConverter extends base.TranspilerBase { // Check if the symbol we're looking at is the type parameter. let symbol = this.tc.getSymbolAtLocation(name); - if (symbol != t.symbol) return false; + if (symbol !== t.symbol) return false; // Check that the Type Parameter has been declared by a function declaration. return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration); @@ -145,8 +145,7 @@ export class FacadeConverter extends base.TranspilerBase { this.visit(typeName); return; } - var identifier = typeName; - var ident = base.ident(typeName); + let ident = base.ident(typeName); if (this.isGenericMethodTypeParameterName(typeName)) { // DDC generic methods hack - all names that are type parameters to generic methods have to be // emitted in comments. @@ -157,14 +156,14 @@ export class FacadeConverter extends base.TranspilerBase { } if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { - var symbol = this.tc.getSymbolAtLocation(typeName); + let symbol = this.tc.getSymbolAtLocation(typeName); if (!symbol) { this.reportMissingType(typeName, ident); return; } let fileAndName = this.getFileAndName(typeName, symbol); if (fileAndName) { - var fileSubs = this.TS_TO_DART_TYPENAMES[fileAndName.fileName]; + let fileSubs = this.TS_TO_DART_TYPENAMES[fileAndName.fileName]; if (fileSubs && fileSubs.hasOwnProperty(fileAndName.qname)) { this.emit(fileSubs[fileAndName.qname]); return; @@ -177,25 +176,24 @@ export class FacadeConverter extends base.TranspilerBase { shouldEmitNew(c: ts.CallExpression): boolean { if (!this.tc) return true; - let {context, symbol} = this.getCallInformation(c); - if (!symbol) { - // getCallInformation returns a symbol if we understand this call. - return true; - } + let ci = this.getCallInformation(c); + let symbol = ci.symbol; + // getCallInformation returns a symbol if we understand this call. + if (!symbol) return true; - var loc = this.getFileAndName(c, symbol); + let loc = this.getFileAndName(c, symbol); if (!loc) return true; - var {fileName, qname} = loc; - var fileSubs = this.callHandlerReplaceNew[fileName]; + let {fileName, qname} = loc; + let fileSubs = this.callHandlerReplaceNew[fileName]; if (!fileSubs) return true; return !fileSubs[qname]; } private getCallInformation(c: ts.CallExpression): {context?: ts.Expression, symbol?: ts.Symbol} { - var symbol: ts.Symbol; - var context: ts.Expression; - var ident: string; - var expr = c.expression; + let symbol: ts.Symbol; + let context: ts.Expression; + let ident: string; + let expr = c.expression; if (expr.kind === ts.SyntaxKind.Identifier) { // Function call. @@ -212,7 +210,7 @@ export class FacadeConverter extends base.TranspilerBase { context = null; } else if (expr.kind === ts.SyntaxKind.PropertyAccessExpression) { // Method call. - var pa = expr; + let pa = expr; ident = base.ident(pa.name); if (!this.candidateProperties.hasOwnProperty(ident)) return {}; @@ -228,10 +226,10 @@ export class FacadeConverter extends base.TranspilerBase { } private getHandler(n: ts.Node, symbol: ts.Symbol, m: ts.Map>): T { - var loc = this.getFileAndName(n, symbol); + let loc = this.getFileAndName(n, symbol); if (!loc) return null; - var {fileName, qname} = loc; - var fileSubs = m[fileName]; + let {fileName, qname} = loc; + let fileSubs = m[fileName]; if (!fileSubs) return null; return fileSubs[qname]; } @@ -256,7 +254,7 @@ export class FacadeConverter extends base.TranspilerBase { .replace(FACADE_NODE_MODULES_PREFIX, '') .replace(this.typingsRootRegex, ''); - var qname = this.tc.getFullyQualifiedName(symbol); + let qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, // for the time being just special case. if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) { @@ -267,9 +265,9 @@ export class FacadeConverter extends base.TranspilerBase { } private isNamedType(node: ts.Node, fileName: string, qname: string): boolean { - var symbol = this.tc.getTypeAtLocation(node).getSymbol(); + let symbol = this.tc.getTypeAtLocation(node).getSymbol(); if (!symbol) return false; - var actual = this.getFileAndName(node, symbol); + let actual = this.getFileAndName(node, symbol); if (fileName === 'lib' && !(actual.fileName === 'lib' || actual.fileName === 'lib.es6')) { return false; } else { @@ -358,16 +356,16 @@ export class FacadeConverter extends base.TranspilerBase { } }, 'Promise': (c: ts.CallExpression, context: ts.Expression) => { - if (c.kind != ts.SyntaxKind.NewExpression) return true; - this.assert(c, c.arguments.length == 1, 'Promise construction must take 2 arguments.'); + if (c.kind !== ts.SyntaxKind.NewExpression) return true; + this.assert(c, c.arguments.length === 1, 'Promise construction must take 2 arguments.'); this.assert( - c, c.arguments[0].kind == ts.SyntaxKind.ArrowFunction || - c.arguments[0].kind == ts.SyntaxKind.FunctionExpression, + c, c.arguments[0].kind === ts.SyntaxKind.ArrowFunction || + c.arguments[0].kind === ts.SyntaxKind.FunctionExpression, 'Promise argument must be a function expression (or arrow function).'); let callback: ts.FunctionLikeDeclaration; - if (c.arguments[0].kind == ts.SyntaxKind.ArrowFunction) { + if (c.arguments[0].kind === ts.SyntaxKind.ArrowFunction) { callback = (c.arguments[0]); - } else if (c.arguments[0].kind == ts.SyntaxKind.FunctionExpression) { + } else if (c.arguments[0].kind === ts.SyntaxKind.FunctionExpression) { callback = (c.arguments[0]); } this.assert( @@ -376,7 +374,7 @@ export class FacadeConverter extends base.TranspilerBase { const completerVarName = this.uniqueId('completer'); this.assert( - c, callback.parameters[0].name.kind == ts.SyntaxKind.Identifier, + c, callback.parameters[0].name.kind === ts.SyntaxKind.Identifier, 'First argument of the Promise executor is not a straight parameter.'); let resolveParameterIdent = (callback.parameters[0].name); @@ -386,14 +384,14 @@ export class FacadeConverter extends base.TranspilerBase { this.emit(resolveParameterIdent.text); this.emit(`= ${completerVarName}.complete;`); - if (callback.parameters.length == 2) { + if (callback.parameters.length === 2) { this.assert( - c, callback.parameters[1].name.kind == ts.SyntaxKind.Identifier, + c, callback.parameters[1].name.kind === ts.SyntaxKind.Identifier, 'First argument of the Promise executor is not a straight parameter.'); let rejectParameterIdent = (callback.parameters[1].name); this.emit('var'); this.emit(rejectParameterIdent.text); - this.emit(`= ${completerVarName}.completeError;`) + this.emit(`= ${completerVarName}.completeError;`); } this.emit('(()'); this.visit(callback.body); @@ -419,7 +417,7 @@ export class FacadeConverter extends base.TranspilerBase { 'Array.unshift': (c: ts.CallExpression, context: ts.Expression) => { this.emit('('); this.visit(context); - if (c.arguments.length == 1) { + if (c.arguments.length === 1) { this.emit('.. insert ( 0,'); this.visit(c.arguments[0]); this.emit(') ) . length'); @@ -522,8 +520,8 @@ export class FacadeConverter extends base.TranspilerBase { 'Map.delete': (c: ts.CallExpression, context: ts.Expression) => { // JS Map.delete(k) returns whether k was present in the map, // convert to: - // (Map.containsKey(k) && (Map.remove(k) != null || true)) - // (Map.remove(k) != null || true) is required to always returns true + // (Map.containsKey(k) && (Map.remove(k) !== null || true)) + // (Map.remove(k) !== null || true) is required to always returns true // when Map.containsKey(k) this.emit('('); this.visit(context); @@ -541,7 +539,7 @@ export class FacadeConverter extends base.TranspilerBase { case ts.SyntaxKind.FunctionExpression: cb = (c.arguments[0]); params = cb.parameters; - if (params.length != 2) { + if (params.length !== 2) { this.reportError(c, 'Map.forEach callback requires exactly two arguments'); return; } @@ -558,7 +556,7 @@ export class FacadeConverter extends base.TranspilerBase { case ts.SyntaxKind.ArrowFunction: cb = (c.arguments[0]); params = cb.parameters; - if (params.length != 2) { + if (params.length !== 2) { this.reportError(c, 'Map.forEach callback requires exactly two arguments'); return; } @@ -568,7 +566,7 @@ export class FacadeConverter extends base.TranspilerBase { this.emit(','); this.visit(params[0]); this.emit(')'); - if (cb.body.kind != ts.SyntaxKind.Block) { + if (cb.body.kind !== ts.SyntaxKind.Block) { this.emit('=>'); } this.visit(cb.body); @@ -638,7 +636,7 @@ export class FacadeConverter extends base.TranspilerBase { 'normalizeBlank': (c: ts.CallExpression, context: ts.Expression) => { // normalizeBlank is a noop in Dart, so erase it. this.visitList(c.arguments); - } + }, }, }; diff --git a/lib/literal.ts b/lib/literal.ts index 3b10efc..efe1b0b 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -1,7 +1,7 @@ import * as ts from 'typescript'; import * as base from './base'; import {Transpiler} from './main'; -import {FacadeConverter} from "./facade_converter"; +import {FacadeConverter} from './facade_converter'; export default class LiteralTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } @@ -10,14 +10,14 @@ export default class LiteralTranspiler extends base.TranspilerBase { switch (node.kind) { // Literals. case ts.SyntaxKind.NumericLiteral: - var sLit = node; - this.emit(sLit.getText()); + let nLit = node; + this.emit(nLit.getText()); break; case ts.SyntaxKind.StringLiteral: - var sLit = node; - var text = JSON.stringify(sLit.text); + let sLit = node; + let text = JSON.stringify(sLit.text); // Escape dollar sign since dart will interpolate in double quoted literal - var text = text.replace(/\$/, '\\$'); + text = text.replace(/\$/, '\\$'); this.emit(text); break; case ts.SyntaxKind.NoSubstitutionTemplateLiteral: @@ -27,7 +27,7 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.emitNoSpace(this.escapeTextForTemplateString(node)); break; case ts.SyntaxKind.TemplateExpression: - var tmpl = node; + let tmpl = node; if (tmpl.head) this.visit(tmpl.head); if (tmpl.templateSpans) this.visitEach(tmpl.templateSpans); break; @@ -39,7 +39,7 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.emitNoSpace(`'''`); break; case ts.SyntaxKind.TemplateSpan: - var span = node; + let span = node; if (span.expression) { // Do not emit extra whitespace inside the string template this.emitNoSpace('${'); @@ -65,7 +65,7 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.emit('}'); break; case ts.SyntaxKind.PropertyAssignment: - var propAssign = node; + let propAssign = node; if (propAssign.name.kind === ts.SyntaxKind.Identifier) { // Dart identifiers in Map literals need quoting. this.emitNoSpace(' "'); @@ -78,7 +78,7 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.visit(propAssign.initializer); break; case ts.SyntaxKind.ShorthandPropertyAssignment: - var shorthand = node; + let shorthand = node; this.emitNoSpace(' "'); this.emitNoSpace(shorthand.name.text); this.emitNoSpace('"'); @@ -98,9 +98,9 @@ export default class LiteralTranspiler extends base.TranspilerBase { case ts.SyntaxKind.RegularExpressionLiteral: this.emit('new RegExp ('); this.emit('r\''); - var regExp = (node).text; - var slashIdx = regExp.lastIndexOf('/'); - var flags = regExp.substring(slashIdx + 1); + let regExp = (node).text; + let slashIdx = regExp.lastIndexOf('/'); + let flags = regExp.substring(slashIdx + 1); regExp = regExp.substring(1, slashIdx); // cut off /.../ chars. regExp = regExp.replace(/'/g, '\' + "\'" + r\''); // handle nested quotes by concatenation. this.emitNoSpace(regExp); diff --git a/lib/main.ts b/lib/main.ts index e8fcc74..639e9ce 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -89,19 +89,19 @@ export class Transpiler { this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath)); } fileNames = fileNames.map((f) => this.normalizeSlashes(f)); - var host = this.createCompilerHost(); + let host = this.createCompilerHost(); if (this.options.basePath && destination === undefined) { throw new Error( 'Must have a destination path when a basePath is specified ' + this.options.basePath); } - var destinationRoot = destination || this.options.basePath || ''; - var program = ts.createProgram(fileNames, this.getCompilerOptions(), host); + let destinationRoot = destination || this.options.basePath || ''; + let program = ts.createProgram(fileNames, this.getCompilerOptions(), host); if (this.options.translateBuiltins) { this.fc.setTypeChecker(program.getTypeChecker()); } // Only write files that were explicitly passed in. - var fileSet: {[s: string]: boolean} = {}; + let fileSet: {[s: string]: boolean} = {}; fileNames.forEach((f) => fileSet[f] = true); this.errors = []; @@ -110,8 +110,8 @@ export class Transpiler { // Do not generate output for .d.ts files. .filter((sourceFile: ts.SourceFile) => !sourceFile.fileName.match(/\.d\.ts$/)) .forEach((f: ts.SourceFile) => { - var dartCode = this.translate(f); - var outputFile = this.getOutputPath(path.resolve(f.fileName), destinationRoot); + let dartCode = this.translate(f); + let outputFile = this.getOutputPath(path.resolve(f.fileName), destinationRoot); mkdirP(path.dirname(outputFile)); fs.writeFileSync(outputFile, dartCode); }); @@ -122,7 +122,7 @@ export class Transpiler { if (this.options.translateBuiltins) { this.fc.setTypeChecker(program.getTypeChecker()); } - var paths: {[path: string]: string} = {}; + let paths: {[path: string]: string} = {}; this.errors = []; program.getSourceFiles() .filter( @@ -134,18 +134,18 @@ export class Transpiler { } private getCompilerOptions() { - var opts: ts.CompilerOptions = {}; - for (var k in COMPILER_OPTIONS) opts[k] = COMPILER_OPTIONS[k]; + let opts: ts.CompilerOptions = {}; + for (let k of Object.keys(COMPILER_OPTIONS)) opts[k] = COMPILER_OPTIONS[k]; opts.rootDir = this.options.basePath; return opts; } private createCompilerHost(): ts.CompilerHost { - var defaultLibFileName = ts.getDefaultLibFileName(COMPILER_OPTIONS); + let defaultLibFileName = ts.getDefaultLibFileName(COMPILER_OPTIONS); defaultLibFileName = this.normalizeSlashes(defaultLibFileName); - var compilerHost: ts.CompilerHost = { + let compilerHost: ts.CompilerHost = { getSourceFile: (sourceName, languageVersion) => { - var sourcePath = sourceName; + let sourcePath = sourceName; if (sourceName === defaultLibFileName) { sourcePath = ts.getDefaultLibFilePath(COMPILER_OPTIONS); } @@ -168,8 +168,8 @@ export class Transpiler { // Visible for testing. getOutputPath(filePath: string, destinationRoot: string): string { - var relative = this.getRelativeFileName(filePath); - var dartFile = relative.replace(/.(js|es6|ts)$/, '.dart'); + let relative = this.getRelativeFileName(filePath); + let dartFile = relative.replace(/.(js|es6|ts)$/, '.dart'); return this.normalizeSlashes(path.join(destinationRoot, dartFile)); } @@ -179,12 +179,12 @@ export class Transpiler { new Output(sourceFile, this.getRelativeFileName(), this.options.generateSourceMap); this.lastCommentIdx = -1; this.visit(sourceFile); - var result = this.output.getResult(); + let result = this.output.getResult(); return this.formatCode(result, sourceFile); } private formatCode(code: string, context: ts.Node) { - var result = dartStyle.formatCode(code); + let result = dartStyle.formatCode(code); if (result.error) { this.reportError(context, result.error); } @@ -192,9 +192,9 @@ export class Transpiler { } private checkForErrors(program: ts.Program) { - var errors = this.errors; + let errors = this.errors; - var diagnostics = program.getGlobalDiagnostics().concat(program.getSyntacticDiagnostics()); + let diagnostics = program.getGlobalDiagnostics().concat(program.getSyntacticDiagnostics()); if ((errors.length || diagnostics.length) && this.options.translateBuiltins) { // Only report semantic diagnostics if ts2dart failed; this code is not a generic compiler, so @@ -203,8 +203,8 @@ export class Transpiler { diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); } - var diagnosticErrs = diagnostics.map((d) => { - var msg = ''; + let diagnosticErrs = diagnostics.map((d) => { + let msg = ''; if (d.file) { let pos = d.file.getLineAndCharacterOfPosition(d.start); let fn = this.getRelativeFileName(d.file.fileName); @@ -217,7 +217,7 @@ export class Transpiler { if (diagnosticErrs.length) errors = errors.concat(diagnosticErrs); if (errors.length) { - var e = new Error(errors.join('\n')); + let e = new Error(errors.join('\n')); e.name = 'TS2DartError'; throw e; } @@ -233,7 +233,7 @@ export class Transpiler { if (this.normalizeSlashes(path.resolve('/x/', filePath)) !== filePath) { return filePath; // already relative. } - var base = this.options.basePath || ''; + let base = this.options.basePath || ''; if (filePath.indexOf(base) !== 0 && !filePath.match(/\.d\.ts$/)) { throw new Error(`Files must be located under base, got ${filePath} vs ${base}`); } @@ -244,31 +244,31 @@ export class Transpiler { emitNoSpace(s: string) { this.output.emitNoSpace(s); } reportError(n: ts.Node, message: string) { - var file = n.getSourceFile() || this.currentFile; - var fileName = this.getRelativeFileName(file.fileName); - var start = n.getStart(file); - var pos = file.getLineAndCharacterOfPosition(start); + let file = n.getSourceFile() || this.currentFile; + let fileName = this.getRelativeFileName(file.fileName); + let start = n.getStart(file); + let pos = file.getLineAndCharacterOfPosition(start); // Line and character are 0-based. - var fullMessage = `${fileName}:${pos.line + 1}:${pos.character + 1}: ${message}`; + let fullMessage = `${fileName}:${pos.line + 1}:${pos.character + 1}: ${message}`; if (this.options.failFast) throw new Error(fullMessage); this.errors.push(fullMessage); } visit(node: ts.Node) { this.output.addSourceMapping(node); - var comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart()); + let comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart()); if (comments) { comments.forEach((c) => { if (c.pos <= this.lastCommentIdx) return; this.lastCommentIdx = c.pos; - var text = this.currentFile.text.substring(c.pos, c.end); + let text = this.currentFile.text.substring(c.pos, c.end); this.emitNoSpace('\n'); this.emit(this.translateComment(text)); if (c.hasTrailingNewLine) this.emitNoSpace('\n'); }); } - for (var i = 0; i < this.transpilers.length; i++) { + for (let i = 0; i < this.transpilers.length; i++) { if (this.transpilers[i].visitNode(node)) return; } @@ -342,7 +342,7 @@ class Output { emitNoSpace(str: string) { this.result += str; - for (var i = 0; i < str.length; i++) { + for (let i = 0; i < str.length; i++) { if (str[i] === '\n') { this.line++; this.column = 0; @@ -352,15 +352,15 @@ class Output { } } - getResult(): string { return this.result; } + getResult(): string { return this.result + this.generateSourceMapComment(); } addSourceMapping(n: ts.Node) { - if (!this.sourceMap) return; // source maps disabled. - var file = n.getSourceFile() || this.currentFile; - var start = n.getStart(file); - var pos = file.getLineAndCharacterOfPosition(start); + if (!this.generateSourceMap) return; // source maps disabled. + let file = n.getSourceFile() || this.currentFile; + let start = n.getStart(file); + let pos = file.getLineAndCharacterOfPosition(start); - var mapping: SourceMap.Mapping = { + let mapping: SourceMap.Mapping = { original: {line: pos.line + 1, column: pos.character}, generated: {line: this.line, column: this.column}, source: this.relativeFileName, @@ -371,14 +371,14 @@ class Output { private generateSourceMapComment() { if (!this.sourceMap) return ''; - var base64map = new Buffer(JSON.stringify(this.sourceMap)).toString('base64'); + let base64map = new Buffer(JSON.stringify(this.sourceMap)).toString('base64'); return '\n\n//# sourceMappingURL=data:application/json;base64,' + base64map; } } // CLI entry point if (require.main === module) { - var args = require('minimist')(process.argv.slice(2), {base: 'string'}); + let args = require('minimist')(process.argv.slice(2), {base: 'string'}); try { let transpiler = new Transpiler(args); console.error('Transpiling', args._, 'to', args.destination); diff --git a/lib/mkdirp.ts b/lib/mkdirp.ts index 8aa41d4..01e5089 100644 --- a/lib/mkdirp.ts +++ b/lib/mkdirp.ts @@ -7,11 +7,11 @@ export default function mkdirP(p: string) { p = path.resolve(p); p = path.relative('', p); - var pathToCreate = ''; + let pathToCreate = ''; p.split(path.sep).forEach(dirName => { pathToCreate = path.join(pathToCreate, dirName); if (!fs.existsSync(pathToCreate)) { fs.mkdirSync(pathToCreate); } - }) + }); } diff --git a/lib/module.ts b/lib/module.ts index d8bea02..8b8d12c 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -23,7 +23,7 @@ export default class ModuleTranspiler extends base.TranspilerBase { ts.forEachChild(node, this.visit.bind(this)); break; case ts.SyntaxKind.ImportDeclaration: - var importDecl = node; + let importDecl = node; if (importDecl.importClause) { if (this.isEmptyImport(importDecl)) return true; this.emit('import'); @@ -35,41 +35,41 @@ export default class ModuleTranspiler extends base.TranspilerBase { this.emit(';'); break; case ts.SyntaxKind.ImportClause: - var importClause = node; + let importClause = node; if (importClause.name) this.fc.visitTypeName(importClause.name); if (importClause.namedBindings) { this.visit(importClause.namedBindings); } break; case ts.SyntaxKind.NamespaceImport: - var nsImport = node; + let nsImport = node; this.emit('as'); this.fc.visitTypeName(nsImport.name); break; case ts.SyntaxKind.NamedImports: this.emit('show'); - var used = this.filterImports((node).elements); + let used = this.filterImports((node).elements); if (used.length === 0) { this.reportError(node, 'internal error, used imports must not be empty'); } this.visitList(used); break; case ts.SyntaxKind.NamedExports: - var exportElements = (node).elements; + let exportElements = (node).elements; this.emit('show'); if (exportElements.length === 0) this.reportError(node, 'empty export list'); this.visitList((node).elements); break; case ts.SyntaxKind.ImportSpecifier: case ts.SyntaxKind.ExportSpecifier: - var spec = node; + let spec = node; if (spec.propertyName) { this.reportError(spec.propertyName, 'import/export renames are unsupported in Dart'); } this.fc.visitTypeName(spec.name); break; case ts.SyntaxKind.ExportDeclaration: - var exportDecl = node; + let exportDecl = node; this.emit('export'); if (exportDecl.moduleSpecifier) { this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); @@ -80,7 +80,7 @@ export default class ModuleTranspiler extends base.TranspilerBase { this.emit(';'); break; case ts.SyntaxKind.ImportEqualsDeclaration: - var importEqDecl = node; + let importEqDecl = node; this.emit('import'); this.visit(importEqDecl.moduleReference); this.emit('as'); @@ -99,7 +99,7 @@ export default class ModuleTranspiler extends base.TranspilerBase { private static isIgnoredImport(e: ts.ImportSpecifier) { // TODO: unify with facade_converter.ts - var name = base.ident(e.name); + let name = base.ident(e.name); switch (name) { case 'CONST': case 'CONST_EXPR': @@ -115,8 +115,8 @@ export default class ModuleTranspiler extends base.TranspilerBase { private visitExternalModuleReferenceExpr(expr: ts.Expression) { // TODO: what if this isn't a string literal? - var moduleName = expr; - var text = moduleName.text; + let moduleName = expr; + let text = moduleName.text; if (text.match(/^\.\//)) { // Strip './' to be more Dart-idiomatic. text = text.substring(2); @@ -128,9 +128,9 @@ export default class ModuleTranspiler extends base.TranspilerBase { } private isEmptyImport(n: ts.ImportDeclaration): boolean { - var bindings = n.importClause.namedBindings; - if (bindings.kind != ts.SyntaxKind.NamedImports) return false; - var elements = (bindings).elements; + let bindings = n.importClause.namedBindings; + if (bindings.kind !== ts.SyntaxKind.NamedImports) return false; + let elements = (bindings).elements; // An import list being empty *after* filtering is ok, but if it's empty in the code itself, // it's nonsensical code, so probably a programming error. if (elements.length === 0) this.reportError(n, 'empty import list'); @@ -145,23 +145,17 @@ export default class ModuleTranspiler extends base.TranspilerBase { // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords private static DART_RESERVED_WORDS = ('assert break case catch class const continue default do else enum extends false final ' + - 'finally for if in is new null rethrow return super switch this throw true try var void ' + + 'finally for if in is new null rethrow return super switch this throw true try let void ' + 'while with') .split(/ /); - // These are the built-in and limited keywords. - private static DART_OTHER_KEYWORDS = - ('abstract as async await deferred dynamic export external factory get implements import ' + - 'library operator part set static sync typedef yield') - .split(/ /); - getLibraryName(nameForTest?: string) { - var fileName = this.getRelativeFileName(nameForTest); - var parts = fileName.split('/'); + let fileName = this.getRelativeFileName(nameForTest); + let parts = fileName.split('/'); return parts.filter((p) => p.length > 0) .map((p) => p.replace(/[^\w.]/g, '_')) .map((p) => p.replace(/\.[jt]s$/g, '')) - .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) != -1 ? '_' + p : p) + .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p) .join('.'); } } diff --git a/lib/statement.ts b/lib/statement.ts index 7cf9ca1..7de10da 100644 --- a/lib/statement.ts +++ b/lib/statement.ts @@ -13,30 +13,30 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit(';'); break; case ts.SyntaxKind.ReturnStatement: - var retStmt = node; + let retStmt = node; this.emit('return'); if (retStmt.expression) this.visit(retStmt.expression); this.emit(';'); break; case ts.SyntaxKind.BreakStatement: case ts.SyntaxKind.ContinueStatement: - var breakContinue = node; - this.emit(breakContinue.kind == ts.SyntaxKind.BreakStatement ? 'break' : 'continue'); + let breakContinue = node; + this.emit(breakContinue.kind === ts.SyntaxKind.BreakStatement ? 'break' : 'continue'); if (breakContinue.label) this.visit(breakContinue.label); this.emit(';'); break; case ts.SyntaxKind.VariableStatement: - var variableStmt = node; + let variableStmt = node; this.visit(variableStmt.declarationList); this.emit(';'); break; case ts.SyntaxKind.ExpressionStatement: - var expr = node; + let expr = node; this.visit(expr.expression); this.emit(';'); break; case ts.SyntaxKind.SwitchStatement: - var switchStmt = node; + let switchStmt = node; this.emit('switch ('); this.visit(switchStmt.expression); this.emit(')'); @@ -48,7 +48,7 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit('}'); break; case ts.SyntaxKind.CaseClause: - var caseClause = node; + let caseClause = node; this.emit('case'); this.visit(caseClause.expression); this.emit(':'); @@ -59,7 +59,7 @@ export default class StatementTranspiler extends base.TranspilerBase { this.visitEach((node).statements); break; case ts.SyntaxKind.IfStatement: - var ifStmt = node; + let ifStmt = node; this.emit('if ('); this.visit(ifStmt.expression); this.emit(')'); @@ -70,7 +70,7 @@ export default class StatementTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.ForStatement: - var forStmt = node; + let forStmt = node; this.emit('for ('); if (forStmt.initializer) this.visit(forStmt.initializer); this.emit(';'); @@ -83,7 +83,7 @@ export default class StatementTranspiler extends base.TranspilerBase { case ts.SyntaxKind.ForInStatement: // TODO(martinprobst): Dart's for-in loops actually have different semantics, they are more // like for-of loops, iterating over collections. - var forInStmt = node; + let forInStmt = node; this.emit('for ('); if (forInStmt.initializer) this.visit(forInStmt.initializer); this.emit('in'); @@ -92,7 +92,7 @@ export default class StatementTranspiler extends base.TranspilerBase { this.visit(forInStmt.statement); break; case ts.SyntaxKind.ForOfStatement: - var forOfStmt = node; + let forOfStmt = node; this.emit('for ('); if (forOfStmt.initializer) this.visit(forOfStmt.initializer); this.emit('in'); @@ -101,14 +101,14 @@ export default class StatementTranspiler extends base.TranspilerBase { this.visit(forOfStmt.statement); break; case ts.SyntaxKind.WhileStatement: - var whileStmt = node; + let whileStmt = node; this.emit('while ('); this.visit(whileStmt.expression); this.emit(')'); this.visit(whileStmt.statement); break; case ts.SyntaxKind.DoStatement: - var doStmt = node; + let doStmt = node; this.emit('do'); this.visit(doStmt.statement); this.emit('while ('); @@ -117,10 +117,10 @@ export default class StatementTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.ThrowStatement: - var throwStmt = node; - var surroundingCatchClause = this.getAncestor(throwStmt, ts.SyntaxKind.CatchClause); + let throwStmt = node; + let surroundingCatchClause = this.getAncestor(throwStmt, ts.SyntaxKind.CatchClause); if (surroundingCatchClause) { - var ref = (surroundingCatchClause).variableDeclaration; + let ref = (surroundingCatchClause).variableDeclaration; if (ref.getText() === throwStmt.expression.getText()) { this.emit('rethrow'); this.emit(';'); @@ -133,7 +133,7 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit(';'); break; case ts.SyntaxKind.TryStatement: - var tryStmt = node; + let tryStmt = node; this.emit('try'); this.visit(tryStmt.tryBlock); if (tryStmt.catchClause) { @@ -145,7 +145,7 @@ export default class StatementTranspiler extends base.TranspilerBase { } break; case ts.SyntaxKind.CatchClause: - var ctch = node; + let ctch = node; if (ctch.variableDeclaration.type) { this.emit('on'); this.visit(ctch.variableDeclaration.type); diff --git a/package.json b/package.json index 592506b..937509d 100644 --- a/package.json +++ b/package.json @@ -16,18 +16,20 @@ }, "devDependencies": { "chai": "^2.1.1", - "clang-format": "^1.0.34", + "clang-format": "^1.0.37", "fs-extra": "^0.18.0", "gulp": "^3.8.11", "gulp-clang-format": "^1.0.21", "gulp-mocha": "^2.0.0", "gulp-sourcemaps": "^1.5.0", + "gulp-tslint": "^4.3.4", "gulp-typescript": "^2.7.6", "gulp-util": "^3.0.4", "merge2": "^0.3.1", "npm-release": "^1.0.0", "temp": "^0.8.1", "tsd": "^0.6.0", + "tslint": "^3.7.1", "which": "^1.0.9" }, "scripts": { diff --git a/test/declaration_test.ts b/test/declaration_test.ts index bcbfab3..c228cfd 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -19,7 +19,7 @@ describe('variables', () => { expectTranslate('var a = 1, b = 0;').to.equal('var a = 1, b = 0;'); }); it('does not support vardecls containing more than one type (implicit or explicit)', () => { - var msg = 'Variables in a declaration list of more than one variable cannot by typed'; + let msg = 'Variables in a declaration list of more than one variable cannot by typed'; expectErroneousCode('var a: A, untyped;').to.throw(msg); expectErroneousCode('var untyped, b: B;').to.throw(msg); expectErroneousCode('var n: number, s: string;').to.throw(msg); diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index d05e258..de726b6 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,38 +1,40 @@ /// /// -import t = require("test/test"); -import {MyClass, MySubclass, SomeArray} from './lib'; +import t = require('test/test'); +import {MyClass, MySubclass, SOME_ARRAY} from './lib'; function callOne(a: (t: T) => U, t: T): U { return a(t); } +/* tslint:disable: no-unused-variable */ function main(): void { - t.test("handles classes", function() { - var mc = new MyClass("hello"); - t.expect(mc.field.toUpperCase(), t.equals("HELLO WORLD")); - t.expect(mc.namedParam({x: '!'}), t.equals("hello!")); - t.expect(mc.namedParam(), t.equals("hello?")); + /* tslint:enable: no-unused-variable */ + t.test('handles classes', function() { + let mc = new MyClass('hello'); + t.expect(mc.field.toUpperCase(), t.equals('HELLO WORLD')); + t.expect(mc.namedParam({x: '!'}), t.equals('hello!')); + t.expect(mc.namedParam(), t.equals('hello?')); }); - t.test("allows subclassing and casts", function() { - var mc: MyClass; - mc = new MySubclass("hello"); - t.expect((mc).subclassField, t.equals("hello world")); + t.test('allows subclassing and casts', function() { + let mc: MyClass; + mc = new MySubclass('hello'); + t.expect((mc).subclassField, t.equals('hello world')); }); - t.test("string templates", function() { - t.expect("$mc", t.equals("$mc")); - var a = "hello"; - var b = "world"; - t.expect(`${a} ${b}`, t.equals("hello world")); + t.test('string templates', function() { + t.expect('$mc', t.equals('$mc')); + let a = 'hello'; + let b = 'world'; + t.expect(`${a} ${b}`, t.equals('hello world')); }); - t.test("regexp", function() { - t.expect(/o\./g.test("fo.o"), t.equals(true)); - t.expect(/o/g.exec("fo.o").length, t.equals(2)); + t.test('regexp', function() { + t.expect(/o\./g.test('fo.o'), t.equals(true)); + t.expect(/o/g.exec('fo.o').length, t.equals(2)); }); - t.test("const expr", function() { t.expect(SomeArray[0], t.equals(1)); }); + t.test('const expr', function() { t.expect(SOME_ARRAY[0], t.equals(1)); }); t.test('generic types fn', function() { t.expect(callOne((a) => a, 1), t.equals(1)); }); - t.test("promises", function() { + t.test('promises', function() { let p: Promise = new Promise((resolve) => { resolve(1); }); p.then((n) => { t.expect(n, t.equals(1)); }); }); diff --git a/test/e2e/lib.ts b/test/e2e/lib.ts index 234ff05..6a30f63 100644 --- a/test/e2e/lib.ts +++ b/test/e2e/lib.ts @@ -1,22 +1,22 @@ -import {CONST, CONST_EXPR, forwardRef} from "angular2/src/facade/lang"; +import {CONST, CONST_EXPR, forwardRef} from 'angular2/src/facade/lang'; @CONST export class MyClass { - private _error: string = "error"; - constructor(private _field: string) {} + private error: string = 'error'; + constructor(private ctorField: string) {} get field(): string { // TODO: TypeScript doesn't parse the RHS as StringKeyword so we lose // the translation of string -> String. // We use capital S String here, even though it wouldn't run in TS. - if ((" world") instanceof String) { - return this._field + " world"; + if ((' world') instanceof String) { + return this.ctorField + ' world'; } else { - return this._error; + return this.error; } } - namedParam({x = "?"}: any = {}) { return 'hello' + x; } + namedParam({x = '?'}: any = {}) { return 'hello' + x; } } interface Observer { @@ -24,10 +24,10 @@ interface Observer { } export class MySubclass extends MyClass implements Observer { - constructor(_field: string) { super(_field); } + constructor(ctorField: string) { super(ctorField); } get subclassField(): string { return this.field; } - update(o: Object, arg: Object) {} + update(o: Object, arg: Object) { this.field = arg.toString(); } } -export const SomeArray = CONST_EXPR([1, 2, 3]); -const someArray = forwardRef(() => SomeArray); +export const SOME_ARRAY = CONST_EXPR([1, 2, 3]); +export const someArray = forwardRef(() => SOME_ARRAY); diff --git a/test/e2e/test.d.ts b/test/e2e/test.d.ts index 1e9dd66..330c220 100644 --- a/test/e2e/test.d.ts +++ b/test/e2e/test.d.ts @@ -1,5 +1,5 @@ declare module 'test/test' { - function test(msg: string, fn: () => void); - function expect(a: any, b: any); - function equals(a: any): any; + export function test(msg: string, fn: () => void); + export function expect(a: any, b: any); + export function equals(a: any): any; } diff --git a/test/expression_test.ts b/test/expression_test.ts index 2a0057d..4025cad 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -2,7 +2,7 @@ import {expectTranslate, expectErroneousCode} from './test_support'; function expectTranslates(cases: any) { - for (var tsCode in cases) { + for (let tsCode of Object.keys(cases)) { expectTranslate(tsCode).to.equal(cases[tsCode]); } } diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 960e82b..7325119 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,15 +1,9 @@ /// import * as fs from 'fs'; -import { - parseFiles, - expectTranslate, - FAKE_MAIN, - expectErroneousCode, - translateSource -} from './test_support'; +import {expectTranslate, FAKE_MAIN, translateSource} from './test_support'; import chai = require('chai'); -var es6RuntimeDeclarations = ` +let es6RuntimeDeclarations = ` interface Iterable {} interface Symbol {} interface Map { @@ -32,7 +26,7 @@ var es6RuntimeDeclarations = ` function getSources(str: string): {[k: string]: string} { - var srcs: {[k: string]: string} = { + let srcs: {[k: string]: string} = { 'some/path/to/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, @@ -63,7 +57,7 @@ function getSources(str: string): {[k: string]: string} { const COMPILE_OPTS = { translateBuiltins: true, failFast: true, - typingsRoot: 'some/path/to/typings/' + typingsRoot: 'some/path/to/typings/', }; function expectWithTypes(str: string) { diff --git a/test/literal_test.ts b/test/literal_test.ts index 9e0565c..fe17250 100644 --- a/test/literal_test.ts +++ b/test/literal_test.ts @@ -8,22 +8,22 @@ describe('literals', () => { }); it('translates string templates', () => { - expectTranslate("`hello \nworld`").to.equal("'''hello \nworld''';"); - expectTranslate("`hello ${world}`").to.equal("'''hello ${ world}''';"); - expectTranslate("`${a}$b${$c}`").to.equal("'''${ a}\\$b${ $c}''';"); - expectTranslate("`'${a}'`").to.equal("'''\\'${ a}\\'''';"); - expectTranslate("`'a'`").to.equal("'''\\'a\\'''';"); + expectTranslate('`hello \nworld`').to.equal(`'''hello \nworld''';`); + expectTranslate('`hello ${world}`').to.equal(`'''hello \${ world}''';`); + expectTranslate('`${a}$b${$c}`').to.equal(`'''\${ a}\\$b\${ $c}''';`); + expectTranslate('`\'${a}\'`').to.equal(`'''\\\'\${ a}\\\'''';`); + expectTranslate('`\'a\'`').to.equal(`'''\\\'a\\\'''';`); // https://github.com/angular/angular/issues/509 expectTranslate('"${a}"').to.equal('"\\${a}";'); expectTranslate('"\\${a}"').to.equal('"\\${a}";'); - expectTranslate("'\\${a}'").to.equal('"\\${a}";'); - expectTranslate("'$a'").to.equal('"\\$a";'); - expectTranslate("`$a`").to.equal("'''\\$a''';"); - expectTranslate("`\\$a`").to.equal("'''\\$a''';"); + expectTranslate('\'\\${a}\'').to.equal('"\\${a}";'); + expectTranslate('\'$a\'').to.equal(`"\\$a";`); + expectTranslate('`$a`').to.equal(`'''\\$a''';`); + expectTranslate('`\\$a`').to.equal(`'''\\$a''';`); }); it('escapes escape sequences', - () => { expectTranslate("`\\\\u1234`").to.equal("'''\\\\u1234''';"); }); + () => { expectTranslate('`\\\\u1234`').to.equal(`'''\\\\u1234''';`); }); it('translates boolean literals', () => { expectTranslate('true').to.equal('true;'); diff --git a/test/main_test.ts b/test/main_test.ts index 1a1b663..9714592 100644 --- a/test/main_test.ts +++ b/test/main_test.ts @@ -1,12 +1,10 @@ /// /// /// -import SourceMap = require('source-map'); import chai = require('chai'); import main = require('../lib/main'); -import ts = require('typescript'); -import {expectTranslate, expectErroneousCode, translateSources} from './test_support'; +import {expectTranslate, expectErroneousCode} from './test_support'; describe('main transpiler functionality', () => { describe('comments', () => { @@ -96,7 +94,7 @@ class A { describe('errors', () => { it('reports multiple errors', () => { // Reports both the private field not having an underbar and protected being unsupported. - var errorLines = new RegExp( + let errorLines = new RegExp( 'delete operator is unsupported\n' + '.*void operator is unsupported'); expectErroneousCode('delete x["y"]; void z;').to.throw(errorLines); @@ -114,7 +112,7 @@ class A { describe('output paths', () => { it('writes within the path', () => { - var transpiler = new main.Transpiler({basePath: '/a'}); + let transpiler = new main.Transpiler({basePath: '/a'}); chai.expect(transpiler.getOutputPath('/a/b/c.js', '/x')).to.equal('/x/b/c.dart'); chai.expect(transpiler.getOutputPath('b/c.js', '/x')).to.equal('/x/b/c.dart'); chai.expect(transpiler.getOutputPath('b/c.js', 'x')).to.equal('x/b/c.dart'); @@ -122,12 +120,12 @@ class A { .to.throw(/must be located under base/); }); it('defaults to writing to the same location', () => { - var transpiler = new main.Transpiler({basePath: undefined}); + let transpiler = new main.Transpiler({basePath: undefined}); chai.expect(transpiler.getOutputPath('/a/b/c.js', '/e')).to.equal('/a/b/c.dart'); chai.expect(transpiler.getOutputPath('b/c.js', '')).to.equal('b/c.dart'); }); it('translates .es6, .ts, and .js', () => { - var transpiler = new main.Transpiler({basePath: undefined}); + let transpiler = new main.Transpiler({basePath: undefined}); ['a.js', 'a.ts', 'a.es6'].forEach( (n) => { chai.expect(transpiler.getOutputPath(n, '')).to.equal('a.dart'); }); }); diff --git a/test/module_test.ts b/test/module_test.ts index dec9f4f..2d59cfa 100644 --- a/test/module_test.ts +++ b/test/module_test.ts @@ -58,14 +58,14 @@ describe('exports', () => { }); describe('library name', () => { - var transpiler: main.Transpiler; - var modTranspiler: ModuleTranspiler; + let transpiler: main.Transpiler; + let modTranspiler: ModuleTranspiler; beforeEach(() => { transpiler = new main.Transpiler({failFast: true, generateLibraryName: true, basePath: '/a'}); modTranspiler = new ModuleTranspiler(transpiler, new FacadeConverter(transpiler), true); }); it('adds a library name', () => { - var results = translateSources( + let results = translateSources( {'/a/b/c.ts': 'var x;'}, {failFast: true, generateLibraryName: true, basePath: '/a'}); chai.expect(results['/a/b/c.ts']).to.equal(`library b.c; diff --git a/test/statement_test.ts b/test/statement_test.ts index c277c84..6618c25 100644 --- a/test/statement_test.ts +++ b/test/statement_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectTranslate} from './test_support'; describe('statements', () => { it('translates switch', () => { @@ -97,9 +97,9 @@ else console.log(e, e_stack); }`); }); - it('rewrites rethrow to preserve stack trace', - () => { - expectTranslate('try {} catch (ex) { throw ex; }').to.equal(`try {} catch (ex, ex_stack) { + it('rewrites rethrow to preserve stack trace', () => { + expectTranslate('try {} catch (ex) { throw ex; }').to.equal(`try {} catch (ex, ex_stack) { rethrow; -}`)}); +}`); + }); }); diff --git a/test/test_support.ts b/test/test_support.ts index 53507c5..0028161 100644 --- a/test/test_support.ts +++ b/test/test_support.ts @@ -4,7 +4,6 @@ import chai = require('chai'); import fs = require('fs'); import main = require('../lib/main'); -import path = require('path'); import ts = require('typescript'); export type StringMap = { @@ -13,10 +12,10 @@ export type StringMap = { export type Input = string | StringMap; export function expectTranslate(tsCode: Input, options: main.TranspilerOptions = {}) { - var result = translateSource(tsCode, options); + let result = translateSource(tsCode, options); // The Dart formatter is aggressive at terminating statements with \n // which clutters the expectation output without providing value. - if (result[result.length - 1] == '\n') { + if (result[result.length - 1] === '\n') { result = result.slice(0, -1); } return chai.expect(result); @@ -27,14 +26,14 @@ export function expectErroneousCode(tsCode: Input, options: main.TranspilerOptio return chai.expect(() => translateSource(tsCode, options)); } -var compilerOptions = main.COMPILER_OPTIONS; -var defaultLibName = ts.getDefaultLibFileName(compilerOptions); -var libSource = fs.readFileSync(ts.getDefaultLibFilePath(compilerOptions), 'utf-8'); -var libSourceFile: ts.SourceFile; +let compilerOptions = main.COMPILER_OPTIONS; +let defaultLibName = ts.getDefaultLibFileName(compilerOptions); +let libSource = fs.readFileSync(ts.getDefaultLibFilePath(compilerOptions), 'utf-8'); +let libSourceFile: ts.SourceFile; export function parseFiles(nameToContent: StringMap): ts.Program { - var result: string; - var compilerHost: ts.CompilerHost = { + let result: string; + let compilerHost: ts.CompilerHost = { getSourceFile: function(sourceName, languageVersion) { if (nameToContent.hasOwnProperty(sourceName)) { return ts.createSourceFile( @@ -60,11 +59,11 @@ export function parseFiles(nameToContent: StringMap): ts.Program { }; compilerHost.resolveModuleNames = main.getModuleResolver(compilerHost); // Create a program from inputs - var entryPoints = Object.keys(nameToContent); - var program: ts.Program = ts.createProgram(entryPoints, compilerOptions, compilerHost); + let entryPoints = Object.keys(nameToContent); + let program: ts.Program = ts.createProgram(entryPoints, compilerOptions, compilerHost); if (program.getSyntacticDiagnostics().length > 0) { // Throw first error. - var first = program.getSyntacticDiagnostics()[0]; + let first = program.getSyntacticDiagnostics()[0]; throw new Error(`${first.start}: ${first.messageText} in ${nameToContent[entryPoints[0]]}`); } return program; @@ -75,7 +74,7 @@ export const FAKE_MAIN = 'angular2/some/main.ts'; export function translateSources(contents: Input, options: main.TranspilerOptions = {}): StringMap { // Default to quick stack traces. if (!options.hasOwnProperty('failFast')) options.failFast = true; - var namesToContent: StringMap; + let namesToContent: StringMap; if (typeof contents === 'string') { namesToContent = {}; namesToContent[FAKE_MAIN] = contents; @@ -83,14 +82,14 @@ export function translateSources(contents: Input, options: main.TranspilerOption namesToContent = contents; } options.enforceUnderscoreConventions = true; - var transpiler = new main.Transpiler(options); - var program = parseFiles(namesToContent); + let transpiler = new main.Transpiler(options); + let program = parseFiles(namesToContent); return transpiler.translateProgram(program); } export function translateSource(contents: Input, options: main.TranspilerOptions = {}): string { - var results = translateSources(contents, options); + let results = translateSources(contents, options); // Return the main outcome, from 'main.ts'. return results[FAKE_MAIN]; } diff --git a/tsconfig.json b/tsconfig.json index 760bcc0..20b82bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "noEmit": true, "noEmitOnError": true, "noImplicitAny": true, - "noImplicitAny": true + "allowUnreachableCode": false }, "exclude": [ "node_modules", diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..2c5fb10 --- /dev/null +++ b/tslint.json @@ -0,0 +1,29 @@ +{ + "rules": { + "class-name": true, + "forin": true, + "jsdoc-format": true, + "label-position": true, + "label-undefined": true, + "no-arg": true, + "no-conditional-assignment": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-key": true, + "no-empty": true, + "no-inferrable-types": true, + "no-internal-module": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "radix": true, + "semicolon": [true, "always"], + "switch-default": true, + "triple-equals": [true, "allow-null-check"], + "variable-name": [true, "check-format", "ban-keywords"] + } +} From ab74a71429037c635558691e7e767b39e1bc6001 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 8 Apr 2016 13:00:20 +0200 Subject: [PATCH 058/108] chore: base arc diffs on v0.7 on this branch. Reviewers: alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D55 --- .arcconfig | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .arcconfig diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000..cb80acf --- /dev/null +++ b/.arcconfig @@ -0,0 +1,3 @@ +{ + "base": "git:origin/v0.7" +} From 0e814241bef26e014b2a53aa763bf8bdb951f796 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 9 Apr 2016 11:02:12 +0200 Subject: [PATCH 059/108] Automatically run unit tests on "arc diff". Summary: This is not quite Travis, but should make operations a bit safer. Reviewers: alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D52 --- .arc/npm-test/__phutil_library_init__.php | 3 +++ .arc/npm-test/__phutil_library_map__.php | 18 ++++++++++++++++++ .arc/npm-test/src/NpmUnitTestEngine.php | 20 ++++++++++++++++++++ .arcconfig | 7 ++++++- .gitignore | 1 + README.md | 17 ++++++++++++++--- 6 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 .arc/npm-test/__phutil_library_init__.php create mode 100644 .arc/npm-test/__phutil_library_map__.php create mode 100644 .arc/npm-test/src/NpmUnitTestEngine.php diff --git a/.arc/npm-test/__phutil_library_init__.php b/.arc/npm-test/__phutil_library_init__.php new file mode 100644 index 0000000..8efba37 --- /dev/null +++ b/.arc/npm-test/__phutil_library_init__.php @@ -0,0 +1,3 @@ + 2, + 'class' => array( + 'NpmUnitTestEngine' => 'src/NpmUnitTestEngine.php', + ), + 'function' => array(), + 'xmap' => array( + 'NpmUnitTestEngine' => 'ArcanistUnitTestEngine', + ), +)); diff --git a/.arc/npm-test/src/NpmUnitTestEngine.php b/.arc/npm-test/src/NpmUnitTestEngine.php new file mode 100644 index 0000000..d18326f --- /dev/null +++ b/.arc/npm-test/src/NpmUnitTestEngine.php @@ -0,0 +1,20 @@ +setName('npm test'); + if ($retval == 0) { + $result->setResult(ArcanistUnitTestResult::RESULT_PASS); + } else { + $result->setResult(ArcanistUnitTestResult::RESULT_FAIL); + } + return array($result); + } + + public function shouldEchoTestResults() { + return false; + } +} +?> diff --git a/.arcconfig b/.arcconfig index cb80acf..77f4c60 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,3 +1,8 @@ { - "base": "git:origin/v0.7" + "base": "git:origin/v0.7", + "phabricator.uri" : "https://reviews.angular.io/", + "load": [ + ".arc/npm-test" + ], + "unit.engine": "NpmUnitTestEngine" } diff --git a/.gitignore b/.gitignore index 59da8ce..0810fe6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ logs pids *.pid *.seed +.phutil_module_cache # Type definitions installed with tsd typings diff --git a/README.md b/README.md index c89c2f2..a134fb5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # TypeScript to Dart transpiler [![Build Status](https://travis-ci.org/angular/ts2dart.svg?branch=master)](https://travis-ci.org/angular/ts2dart) - -ts2dart is a TypeScript to Dart transpiler. It's in its very early days and under heavy development, -not ready for production use. +ts2dart is a TypeScript to Dart transpiler. It's mainly used to translate Angular 2 from TypeScript +to Dart for its Dart user base. ## Installation @@ -15,3 +14,15 @@ not ready for production use. - `gulp test.e2e` executes the e2e tests, - `gulp test.check-format` checks the source code formatting using `clang-format`, - `gulp test` runs unit tests, e2e tests and checks the source code formatting. + +## Phabricator Reviews + +You can send pull requests via Github, or by creating a Phabricator diff on +https://reviews.angular.io. Both are fine, though Phabricator has a nicer code review UI. + +To create a Phabricator diff: + +- create an account on https://reviews.angular.io +- install [Arcanist](https://secure.phabricator.com/book/phabricator/article/arcanist/) +- run `arc diff` to upload a diff (= pull request). This will also run all tests. +- get it reviewed by entering a "Reviewer", e.g. "mprobst", "alexeagle", "viks", ... From ae3c9a8be1c8673e87792be92b863114917ef5d9 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 8 Apr 2016 14:58:46 +0200 Subject: [PATCH 060/108] feat: test case for function typed fields. Summary: From #361. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D56 --- test/declaration_test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/declaration_test.ts b/test/declaration_test.ts index c228cfd..d1d3b53 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -56,6 +56,16 @@ describe('classes', () => { }`); expectTranslate('class X { x; }').to.equal(`class X { var x; +}`); + }); + it('supports function typed fields', () => { + expectTranslate( + 'interface FnDef {(y: number): string;}\n' + + 'class X { x: FnDef; }') + .to.equal(`typedef String FnDef(num y); + +class X { + FnDef x; }`); }); it('supports field initializers', () => { From 2cbaf79d2244830b87db7122ae7f01e1e46a2826 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 8 Apr 2016 12:30:45 +0200 Subject: [PATCH 061/108] feat: translate function parameters taking rest parameters to `Function`. Summary: Fixes #360. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D53 --- lib/declaration.ts | 14 ++++++++++---- test/function_test.ts | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index e91c5cd..4c7a683 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -180,9 +180,16 @@ export default class DeclarationTranspiler extends base.TranspilerBase { if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType) { // Dart uses "returnType paramName ( parameters )" syntax. let fnType = paramDecl.type; - this.visit(fnType.type); - this.visit(paramDecl.name); - this.visitParameters(fnType.parameters); + let hasRestParameter = fnType.parameters.some(p => !!p.dotDotDotToken); + if (hasRestParameter) { + // Dart does not support rest parameters/varargs, degenerate to just "Function". + this.emit('Function'); + this.visit(paramDecl.name); + } else { + this.visit(fnType.type); + this.visit(paramDecl.name); + this.visitParameters(fnType.parameters); + } } else { if (paramDecl.type) this.visit(paramDecl.type); this.visit(paramDecl.name); @@ -192,7 +199,6 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visit(paramDecl.initializer); } break; - case ts.SyntaxKind.StaticKeyword: this.emit('static'); break; diff --git a/test/function_test.ts b/test/function_test.ts index c869836..8ed6d66 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -62,6 +62,9 @@ describe('functions', () => { translateBuiltins: true }).to.equal('f/*< T, U >*/(dynamic/*= T */ fn(dynamic/*= T */ a, dynamic/*= U */ b)) {}'); }); + it('translates functions taking rest parameters to untyped Function', () => { + expectTranslate('function f(fn: (...a: string[]) => number) {}').to.equal('f(Function fn) {}'); + }); }); describe('generic functions', () => { From 2d6f8bb141a4641dcf186caea3996e17574faca7 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 8 Apr 2016 12:53:16 +0200 Subject: [PATCH 062/108] feat: do not cast numeric literals to ints for bit fiddling. Summary: Numeric literals are `int`s in Dart, casting them to `int` explicitly causes a warning. Reviewers: mhevery Reviewed By: mhevery Subscribers: evmar, typescript-eng Differential Revision: https://reviews.angular.io/D54 --- lib/expression.ts | 23 ++++++++++++++--------- test/expression_test.ts | 24 +++++++++++++----------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/lib/expression.ts b/lib/expression.ts index c537abd..5c42d68 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -38,14 +38,14 @@ export default class ExpressionTranspiler extends base.TranspilerBase { // For assignments, strip the trailing `=` sign to emit just the operator itself. this.visit(binExpr.left); this.emit('='); - visitAndWrapAsInt(this, binExpr.left); + this.visitAndWrapAsInt(binExpr.left); this.emit(tokenStr.slice(0, -1)); } else { // normal case (LHS [op]) - visitAndWrapAsInt(this, binExpr.left); + this.visitAndWrapAsInt(binExpr.left); this.emit(tokenStr); } - visitAndWrapAsInt(this, binExpr.right); + this.visitAndWrapAsInt(binExpr.right); break; case ts.SyntaxKind.InKeyword: this.reportError(node, 'in operator is unsupported'); @@ -68,7 +68,7 @@ export default class ExpressionTranspiler extends base.TranspilerBase { this.emit(operator); if (prefixUnary.operator === ts.SyntaxKind.TildeToken) { - visitAndWrapAsInt(this, prefixUnary.operand); + this.visitAndWrapAsInt(prefixUnary.operand); } else { this.visit(prefixUnary.operand); } @@ -131,10 +131,15 @@ export default class ExpressionTranspiler extends base.TranspilerBase { } return true; } -} -function visitAndWrapAsInt(visitor: ExpressionTranspiler, ident: ts.Node) { - visitor.emit('('); - visitor.visit(ident); - visitor.emit('as int)'); + visitAndWrapAsInt(n: ts.Expression) { + let lhsIsHexLit = n.kind === ts.SyntaxKind.NumericLiteral; + if (lhsIsHexLit) { + this.visit(n); + return; + } + this.emit('('); + this.visit(n); + this.emit('as int)'); + } } diff --git a/test/expression_test.ts b/test/expression_test.ts index 4025cad..85eec7b 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -31,12 +31,12 @@ describe('expressions', () => { 'x *= 1': 'x *= 1;', 'x /= 1': 'x /= 1;', 'x %= 1': 'x %= 1;', - 'x <<= 1': 'x = (x as int) << (1 as int);', - 'x >>= 1': 'x = (x as int) >> (1 as int);', + 'x <<= 1': 'x = (x as int) << 1;', + 'x >>= 1': 'x = (x as int) >> 1;', // 'x >>>= 1': 'x >>>= 1;', // This doesn't appear to be a valid operator in Dart. - 'x &= 1': 'x = (x as int) & (1 as int);', - 'x ^= 1': 'x = (x as int) ^ (1 as int);', - 'x |= 1': 'x = (x as int) | (1 as int);', + 'x &= 1': 'x = (x as int) & 1;', + 'x ^= 1': 'x = (x as int) ^ 1;', + 'x |= 1': 'x = (x as int) | 1;', }); }); it('compares', () => { @@ -55,12 +55,14 @@ describe('expressions', () => { }); it('bit fiddles', () => { expectTranslates({ - '1 & 2': '(1 as int) & (2 as int);', - '1 | 2': '(1 as int) | (2 as int);', - '1 ^ 2': '(1 as int) ^ (2 as int);', - '~1': '~(1 as int);', - '1 << 2': '(1 as int) << (2 as int);', - '1 >> 2': '(1 as int) >> (2 as int);', + 'x & 2': '(x as int) & 2;', + '1 & 2': '1 & 2;', + '1 | 2': '1 | 2;', + '1 ^ 2': '1 ^ 2;', + '~1': '~1;', + '1 << 2': '1 << 2;', + '1 >> 2': '1 >> 2;', + '0x1 & 0x2': '0x1 & 0x2;', // '1 >>> 2': '1 >>> 2;', // This doesn't appear to be a valid operator in Dart. }); }); From 34f0ed9b33a176d48609985ed0bad6d305967840 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Fri, 8 Apr 2016 16:05:52 +0200 Subject: [PATCH 063/108] refactor: extract initialiser extraction. Summary: feat: use the resolved types of named parameters. Instead of an immediate object type literal, users might reference another type. This change resolves the destructured parameter names in the referenced type, finding their actual declaration. Reviewers: mhevery Reviewed By: mhevery Subscribers: evmar, typescript-eng Differential Revision: https://reviews.angular.io/D57 --- lib/declaration.ts | 50 ++++++++++++++++++----------------------- lib/facade_converter.ts | 18 +++++++++++++++ test/function_test.ts | 50 ++++++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 39 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 4c7a683..7df4691 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -436,37 +436,13 @@ export default class DeclarationTranspiler extends base.TranspilerBase { private visitNamedParameter(paramDecl: ts.ParameterDeclaration) { this.visitDecorators(paramDecl.decorators); let bp = paramDecl.name; - let typeMap: ts.Map = {}; - if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.TypeLiteral) { - for (let tn of (paramDecl.type).members) { - if (tn.kind !== ts.SyntaxKind.PropertySignature) { - this.reportError(tn, 'unsupported named parameter kind ' + tn.kind); - continue; - } - let pd = tn; - typeMap[base.ident(pd.name)] = pd.type; - } - } - let initMap: ts.Map = {}; - if (paramDecl.initializer) { - if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) { - this.reportError(paramDecl, 'initializers for named parameters must be object literals'); - return; - } - for (let i of (paramDecl.initializer).properties) { - if (i.kind !== ts.SyntaxKind.PropertyAssignment) { - this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind); - continue; - } - let ole = i; - initMap[base.ident(ole.name)] = ole.initializer; - } - } + let propertyTypes = this.fc.resolvePropertyTypes(paramDecl.type); + let initMap = this.getInitializers(paramDecl); this.emit('{'); for (let i = 0; i < bp.elements.length; i++) { let elem = bp.elements[i]; - let type = typeMap[base.ident(elem.name)]; - if (type) this.visit(type); + let propDecl = propertyTypes[base.ident(elem.name)]; + if (propDecl) this.visit(propDecl.type); this.visit(elem.name); if (elem.initializer && initMap[base.ident(elem.name)]) { this.reportError(elem, 'cannot have both an inner and outer initializer'); @@ -481,6 +457,24 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.emit('}'); } + private getInitializers(paramDecl: ts.ParameterDeclaration) { + let res: ts.Map = {}; + if (!paramDecl.initializer) return res; + if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) { + this.reportError(paramDecl, 'initializers for named parameters must be object literals'); + return res; + } + for (let i of (paramDecl.initializer).properties) { + if (i.kind !== ts.SyntaxKind.PropertyAssignment) { + this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind); + continue; + } + let ole = i; + res[base.ident(ole.name)] = ole.initializer; + } + return res; + } + /** * Handles a function typedef-like interface, i.e. an interface that only declares a single * call signature, by translating to a Dart `typedef`. diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 9c5923e..04bd3cc 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -117,6 +117,24 @@ export class FacadeConverter extends base.TranspilerBase { this.genericMethodDeclDepth--; } + resolvePropertyTypes(tn: ts.TypeNode): ts.Map { + let res: ts.Map = {}; + if (!tn || !this.tc) return res; + + let t = this.tc.getTypeAtLocation(tn); + for (let sym of this.tc.getPropertiesOfType(t)) { + let decl = sym.valueDeclaration || (sym.declarations && sym.declarations[0]); + if (decl.kind !== ts.SyntaxKind.PropertyDeclaration && + decl.kind !== ts.SyntaxKind.PropertySignature) { + let msg = this.tc.getFullyQualifiedName(sym) + + ' used for named parameter definition must be a property'; + this.reportError(decl, msg); + continue; + } + res[sym.name] = decl; + } + return res; + } /** * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate diff --git a/test/function_test.ts b/test/function_test.ts index 8ed6d66..b41d15f 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -27,17 +27,7 @@ describe('functions', () => { return; }`); }); - it('supports named parameters', () => { - expectTranslate('function x({a = "x", b}) { return a + b; }').to.equal(`x({a: "x", b}) { - return a + b; -}`); - }); - it('supports types on named parameters', () => { - expectTranslate('function x({a = 1, b = 2}: {a: number, b: number} = {}) { return a + b; }') - .to.equal(`x({num a: 1, num b: 2}) { - return a + b; -}`); - }); + it('does not support var args', () => { expectErroneousCode('function x(...a: number) { return 42; }') .to.throw('rest parameters are unsupported'); @@ -67,6 +57,44 @@ describe('functions', () => { }); }); +describe('named parameters', () => { + it('supports named parameters', () => { + expectTranslate('function x({a = "x", b}) { return a + b; }', { + translateBuiltins: true + }).to.equal(`x({a: "x", b}) { + return a + b; +}`); + }); + it('supports types on named parameters', () => { + expectTranslate('function x({a = 1, b = 2}: {a: number, b: number} = {}) { return a + b; }', { + translateBuiltins: true + }).to.equal(`x({num a: 1, num b: 2}) { + return a + b; +}`); + }); + it('supports reference types on named parameters', () => { + expectTranslate( + 'interface Args { a: string; b: number }\n' + + 'function x({a, b}: Args) { return a + b; }', + {translateBuiltins: true}) + .to.equal(`abstract class Args { + String a; + num b; +} + +x({String a, num b}) { + return a + b; +}`); + }); + it('fails for non-property types on named parameters', () => { + expectErroneousCode( + 'interface X { a(a: number); }\n' + + 'function x({a}: X) { return a + b; }', + {translateBuiltins: true}) + .to.throw('X.a used for named parameter definition must be a property'); + }); +}); + describe('generic functions', () => { it('supports generic types', () => { expectTranslate('function sort(xs: T[]): T[] { return xs; }', { From 0de9712201092f4f3ef620fe96531caa9d25b901 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sun, 10 Apr 2016 16:41:06 +0200 Subject: [PATCH 064/108] rel: 0.8.11. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 937509d..e68e95e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.10", + "version": "0.8.11", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From e23f45a4074cb0cb84c55017e4ef05b1befd0757 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 20 Apr 2016 07:29:22 -0700 Subject: [PATCH 065/108] feat: ignore return types on function expressions. Same as for arrow functions, Dart does not have a syntax for return types. Fixes #355. --- lib/declaration.ts | 6 ++++-- test/function_test.ts | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 7df4691..ac71b66 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -255,8 +255,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.fc.pushTypeParameterNames(fn); try { if (fn.type) { - if (fn.kind === ts.SyntaxKind.ArrowFunction) { - // Type is silently dropped for arrow functions, not supported in Dart. + if (fn.kind === ts.SyntaxKind.ArrowFunction || + fn.kind === ts.SyntaxKind.FunctionExpression) { + // The return type is silently dropped for function expressions (including arrow + // functions), it is not supported in Dart. this.emit('/*'); this.visit(fn.type); this.emit('*/'); diff --git a/test/function_test.ts b/test/function_test.ts index b41d15f..75d960b 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -41,6 +41,12 @@ describe('functions', () => { expectTranslate('var a = (p = null) => isBlank(p)') .to.equal('var a = ([p = null]) => isBlank(p);'); }); + it('translates types on function expressions', () => { + expectTranslate('let a = function(p: string): string { return p; };') + .to.equal(`var a = /* String */ (String p) { + return p; +};`); + }); it('supports function parameters', () => { expectTranslate('function f(fn: (a: A, b: B) => C) {}').to.equal('f(C fn(A a, B b)) {}'); }); From d2a01df0e729493e4288d93e191abf2ad3890491 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 21 Apr 2016 15:12:04 -0700 Subject: [PATCH 066/108] feat: prohibit use of `substr`. Summary: `substr` has different semantics from `substring` and `slice` in that it takes a length, not an end index. That is surprising and error prone, so ts2dart should just disallow it. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D73 --- lib/facade_converter.ts | 6 ++++++ test/facade_converter_test.ts | 3 +++ 2 files changed, 9 insertions(+) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 04bd3cc..5e4c7df 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -514,6 +514,12 @@ export class FacadeConverter extends base.TranspilerBase { this.emitMethodCall('allMatches', c.arguments); this.emitMethodCall('toList'); }, + 'String.substr': (c: ts.CallExpression, context: ts.Expression) => { + this.reportError( + c, 'substr is unsupported, use substring (but beware of the different semantics!)'); + this.visit(context); + this.emitMethodCall('substr', c.arguments); + }, }); private es6Collections: ts.Map = { diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 7325119..daeeb18 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -166,6 +166,9 @@ num y = x.fold(0, (a, b) => a + b);`); num y = x.fold(null, (a, b) => a + b);`); }); + it('translates string methoids', + () => { expectErroneousWithType(`var x = 'asd'.substr(0, 1);`).to.throw(/use substring/); }); + it('translates map operations to dartisms', () => { expectWithTypes('function f() { var x = new Map(); x.set("k", "v"); }') .to.equal(`f() { From 3fe41fbe979f39f60fc0ef4720c46374ddb7b2c7 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 21 Apr 2016 15:10:36 -0700 Subject: [PATCH 067/108] feat: support reference constness. Summary: ES6 `const` most closely maps to Dart's `final`, i.e. a constant reference that cannot be changed. ts2dart used to always translate TS `const` to Dart `const`, requiring the expression to be a deep const value. This change allows writing `const`, translating it to `final` in Dart, and only special casing declarations where the right hand side is in a `CONST_EXPR(...)` wrapper. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D74 --- lib/declaration.ts | 17 ++++++++++++++--- lib/facade_converter.ts | 5 +++-- test/declaration_test.ts | 5 +++-- test/facade_converter_test.ts | 4 ++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index ac71b66..0895aa0 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -236,11 +236,22 @@ export default class DeclarationTranspiler extends base.TranspilerBase { */ let firstDecl = varDecl.parent.declarations[0]; let msg = 'Variables in a declaration list of more than one variable cannot by typed'; - let isConst = this.hasFlag(varDecl.parent, ts.NodeFlags.Const); + let isFinal = this.hasFlag(varDecl.parent, ts.NodeFlags.Const); + let isConst = false; + if (isFinal && varDecl.initializer) { + // "const" in TypeScript/ES6 corresponds to "final" in Dart, i.e. reference constness. + // If a "const" variable is immediately initialized to a CONST_EXPR(), special case it to be + // a deeply const constant, and generate "const ...". + isConst = this.fc.isConstCall(varDecl.initializer); + } if (firstDecl === varDecl) { - if (isConst) this.emit('const'); + if (isConst) { + this.emit('const'); + } else if (isFinal) { + this.emit('final'); + } if (!varDecl.type) { - if (!isConst) this.emit('var'); + if (!isFinal) this.emit('var'); } else if (varDecl.parent.declarations.length > 1) { this.reportError(varDecl, msg); } else { diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 5e4c7df..f802895 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -305,8 +305,9 @@ export class FacadeConverter extends base.TranspilerBase { this.getAncestor(node, ts.SyntaxKind.CallExpression)); } - isConstCall(node: ts.CallExpression): boolean { - return node && base.ident(node.expression) === 'CONST_EXPR'; + isConstCall(node: ts.Expression): boolean { + return node && node.kind === ts.SyntaxKind.CallExpression && + base.ident((node).expression) === 'CONST_EXPR'; } private emitMethodCall(name: string, args?: ts.Expression[]) { diff --git a/test/declaration_test.ts b/test/declaration_test.ts index d1d3b53..bcb412b 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -27,8 +27,9 @@ describe('variables', () => { }); it('supports const', () => { - expectTranslate('const A = 1, B = 2;').to.equal('const A = 1, B = 2;'); - expectTranslate('const A: number = 1;').to.equal('const num A = 1;'); + // NB: const X = CONST_EXPR(1); is translated as deep-const, see tests in facade_converter_test. + expectTranslate('const A = 1, B = 2;').to.equal('final A = 1, B = 2;'); + expectTranslate('const A: number = 1;').to.equal('final num A = 1;'); }); }); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index daeeb18..a6ba7f4 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -330,6 +330,10 @@ main() { describe( 'builtin functions', () => { it('translates CONST_EXPR(...) to const (...)', () => { + expectWithTypes( + 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + + 'const x = CONST_EXPR(1);') + .to.equal('const x = 1;'); expectWithTypes( 'import {CONST_EXPR} from "angular2/src/facade/lang";\n' + 'const x = CONST_EXPR([]);') From 93ccbb0a475ea5cfc9293a1d7920d9847afd03f7 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 21 Apr 2016 16:24:07 -0700 Subject: [PATCH 068/108] rel: 0.8.12. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e68e95e..1df6d0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.11", + "version": "0.8.12", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From f4cdc398ca05f724f0845cf0868f87fcbf71fb78 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Sat, 23 Apr 2016 01:42:59 +0100 Subject: [PATCH 069/108] feat: transpile console.log to print (#352) (#364) Note: as suggested in the issue, we could transpile to window.console.log if it had a varargs signature. However, that would introduce a dependency to dart:html, which seems overkill. --- lib/facade_converter.ts | 11 +++++++++++ test/facade_converter_test.ts | 17 +++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index f802895..a6e4106 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -506,6 +506,17 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('is List'); this.emit(')'); }, + 'Console.log': (c: ts.CallExpression, context: ts.Expression) => { + this.emit('print('); + if (c.arguments.length === 1) { + this.visit(c.arguments[0]); + } else { + this.emit('['); + this.visitList(c.arguments); + this.emit('].join(" ")'); + } + this.emit(')'); + }, 'RegExp.test': (c: ts.CallExpression, context: ts.Expression) => { this.visit(context); this.emitMethodCall('hasMatch', c.arguments); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index a6ba7f4..949e471 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -166,6 +166,11 @@ num y = x.fold(0, (a, b) => a + b);`); num y = x.fold(null, (a, b) => a + b);`); }); + it('translates console.log', () => { + expectWithTypes(`console.log(1);`).to.equal('print(1);'); + expectWithTypes(`console.log(1, 2);`).to.equal('print([1, 2].join(" "));'); + }); + it('translates string methoids', () => { expectErroneousWithType(`var x = 'asd'.substr(0, 1);`).to.throw(/use substring/); }); @@ -293,9 +298,9 @@ Future x = (() { })(); void fn() { x.then((v) { - console.log(v); + print(v); }).catchError((err) { - console.log(err); + print(err); }); }`); expectWithTypes( @@ -306,9 +311,9 @@ void fn() { dynamic /* () => Promise */ fn; main() { fn().then((v) { - console.log(v); + print(v); }).catchError((err) { - console.log(err); + print(err); }); }`); expectWithTypes( @@ -319,9 +324,9 @@ main() { dynamic /* () => Promise */ fn; main() { fn().then((v) { - console.log(v); + print(v); }).catchError((err) { - console.log(err); + print(err); }); }`); }); From 7c1ffdb51d8f59b81bbd79f3d6081d0a2cb321cd Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Sat, 23 Apr 2016 17:33:24 +0100 Subject: [PATCH 070/108] Fix RegExp.exec (#194) (#365) Notes: - Limit transpilation to direct call on a regexp literal (otherwise, side-effects of multiple calls on a global regexp can't be easily replicated with Dart's RegExp; a quick visitation of the tree could tell us if a regexp is non-global or if `exec` is only called once on it, but that would be overkill so we're just backing out of `x.exec(...)` if `x` is not a `/literal/`) - Optimize case where `exec` result is only index-accessed --- lib/facade_converter.ts | 34 +++++++++++++++++++++++++++++----- test/e2e/helloworld.ts | 3 ++- test/facade_converter_test.ts | 11 +++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index a6e4106..76346c4 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -517,15 +517,39 @@ export class FacadeConverter extends base.TranspilerBase { } this.emit(')'); }, + 'RegExp.exec': (c: ts.CallExpression, context: ts.Expression) => { + if (context.kind !== ts.SyntaxKind.RegularExpressionLiteral) { + // Fail if the exec call isn't made directly on a regexp literal. + // Multiple exec calls on the same global regexp have side effects + // (each return the next match), which we can't reproduce with a simple + // Dart RegExp (users should switch to some facade / wrapper instead). + this.reportError( + c, 'exec is only supported on regexp literals, ' + + 'to avoid side-effect of multiple calls on global regexps.'); + } + if (c.parent.kind === ts.SyntaxKind.ElementAccessExpression) { + // The result of the exec call is used for immediate indexed access: + // this use-case can be accommodated by RegExp.firstMatch, which returns + // a Match instance with operator[] which returns groups (special index + // 0 returns the full text of the match). + this.visit(context); + this.emitMethodCall('firstMatch', c.arguments); + } else { + // In the general case, we want to return a List. To transform a Match + // into a List of its groups, we alias it in a local closure that we + // call with the Match value. We are then able to use the group method + // to generate a List large enough to hold groupCount groups + the + // full text of the match at special group index 0. + this.emit('((match) => new List.generate(1 + match.groupCount, match.group))('); + this.visit(context); + this.emitMethodCall('firstMatch', c.arguments); + this.emit(')'); + } + }, 'RegExp.test': (c: ts.CallExpression, context: ts.Expression) => { this.visit(context); this.emitMethodCall('hasMatch', c.arguments); }, - 'RegExp.exec': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('allMatches', c.arguments); - this.emitMethodCall('toList'); - }, 'String.substr': (c: ts.CallExpression, context: ts.Expression) => { this.reportError( c, 'substr is unsupported, use substring (but beware of the different semantics!)'); diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index de726b6..0fc6f98 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -29,7 +29,8 @@ function main(): void { }); t.test('regexp', function() { t.expect(/o\./g.test('fo.o'), t.equals(true)); - t.expect(/o/g.exec('fo.o').length, t.equals(2)); + t.expect(/o/g.exec('fo.o').length, t.equals(1)); + t.expect(/a(b)/g.exec('ab').length, t.equals(2)); }); t.test('const expr', function() { t.expect(SOME_ARRAY[0], t.equals(1)); }); t.test('generic types fn', function() { t.expect(callOne((a) => a, 1), t.equals(1)); }); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 949e471..e779fea 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -237,6 +237,17 @@ var y = x.length;`); var x = new RegExp(r'a'); x.hasMatch("a"); }`); + expectWithTypes('function f() { var result = /a(.)/g.exec("ab")[1]; }').to.equal(`f() { + var result = new RegExp(r'a(.)').firstMatch("ab")[1]; +}`); + expectWithTypes('function f() { let groups = /a(.)/g.exec("ab"); }').to.equal(`f() { + var groups = ((match) => new List.generate( + 1 + match.groupCount, match.group))(new RegExp(r'a(.)').firstMatch("ab")); +}`); + expectErroneousWithType('function f() { var x = /a(.)/g; x.exec("ab")[1]; }') + .to.throw( + 'exec is only supported on regexp literals, ' + + 'to avoid side-effect of multiple calls on global regexps.'); }); describe('promises', () => { From f59ea69f90302f6b110dbe21281bea8fba8670bb Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 09:38:49 -0700 Subject: [PATCH 071/108] feat: move to the TypeScript 1.9 preview. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1df6d0f..a2319f9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "minimist": "^1.1.1", "source-map": "^0.4.2", "source-map-support": "^0.3.1", - "typescript": "mprobst/TypeScript#pathMappingModuleResolution" + "typescript": "v1.9.0-dev.20160409" }, "devDependencies": { "chai": "^2.1.1", From 9d7adfe64c9eaf54243dbbb2946d2ea08570b4b7 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 09:41:29 -0700 Subject: [PATCH 072/108] rel: 0.9.0. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2319f9..f8dd5a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.8.12", + "version": "0.9.0", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 3cc8fb63106f79ad7e5a877358f7af49cafe4c30 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 11 Apr 2016 07:01:58 +0200 Subject: [PATCH 073/108] fix: support declared but untyped properties in named parameters. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D61 --- lib/declaration.ts | 2 +- test/function_test.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 0895aa0..3f8691b 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -455,7 +455,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { for (let i = 0; i < bp.elements.length; i++) { let elem = bp.elements[i]; let propDecl = propertyTypes[base.ident(elem.name)]; - if (propDecl) this.visit(propDecl.type); + if (propDecl && propDecl.type) this.visit(propDecl.type); this.visit(elem.name); if (elem.initializer && initMap[base.ident(elem.name)]) { this.reportError(elem, 'cannot have both an inner and outer initializer'); diff --git a/test/function_test.ts b/test/function_test.ts index 75d960b..547366b 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -81,14 +81,21 @@ describe('named parameters', () => { it('supports reference types on named parameters', () => { expectTranslate( 'interface Args { a: string; b: number }\n' + - 'function x({a, b}: Args) { return a + b; }', + 'function x({a, b, c}: Args) { return a + b; }', {translateBuiltins: true}) .to.equal(`abstract class Args { String a; num b; } -x({String a, num b}) { +x({String a, num b, c}) { + return a + b; +}`); + }); + it('supports declared, untyped named parameters', () => { + expectTranslate('function x({a, b}: {a: number, b}) { return a + b; }', { + translateBuiltins: true + }).to.equal(`x({num a, b}) { return a + b; }`); }); From 966d58bc7177e8b8c6508fb067fbe51d225e5150 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 10:28:31 -0700 Subject: [PATCH 074/108] rel: 0.9.1. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f8dd5a0..32f0511 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.0", + "version": "0.9.1", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From dd1bc087ca7a1272d7d55c27c11d55b19e1ffcb8 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 12:58:47 -0700 Subject: [PATCH 075/108] chore: fix .arcconfig. Reviews on master should not be based on v0.7. --- .arcconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.arcconfig b/.arcconfig index 77f4c60..894b55d 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,5 +1,4 @@ { - "base": "git:origin/v0.7", "phabricator.uri" : "https://reviews.angular.io/", "load": [ ".arc/npm-test" From 191b562a41696915f872f43aa6754fb4f11ceeec Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 11:26:19 -0700 Subject: [PATCH 076/108] feat: support passing in a tsconfig.json. Summary: This allows more fine grained configuration of TypeScript compilation, including baseUrl, paths, etc. When given a tsconfig.json, ts2dart prefer its options over other options, e.g. it uses rootDir and outDir as basePath and destination, respectively. This required some shoving around in ts2dart's path handling. I believe the result is saner - where we'd previously resolve paths to absolute paths and then relativize them again, we now just treat them as opaque and only relativize against the outputPath/rootDir, which is what we should have done in the first place. This seems to be most easily tested using an integration test, see gulpfile.js. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D77 --- gulpfile.js | 25 ++++++++++- lib/main.ts | 82 +++++++++++++++++++++++----------- lib/module.ts | 11 ++--- test/main_test.ts | 4 +- test/tsc_e2e/map_target/dep.ts | 1 + test/tsc_e2e/p1/user.ts | 5 +++ test/tsc_e2e/tsconfig.json | 12 +++++ tsconfig.json | 3 +- 8 files changed, 108 insertions(+), 35 deletions(-) create mode 100644 test/tsc_e2e/map_target/dep.ts create mode 100644 test/tsc_e2e/p1/user.ts create mode 100644 test/tsc_e2e/tsconfig.json diff --git a/gulpfile.js b/gulpfile.js index 3a21f46..dc5bca5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,6 +8,7 @@ var gulp = require('gulp'); var gutil = require('gulp-util'); var merge = require('merge2'); var mocha = require('gulp-mocha'); +var path = require('path'); var sourcemaps = require('gulp-sourcemaps'); var spawn = require('child_process').spawn; var ts = require('gulp-typescript'); @@ -120,7 +121,29 @@ gulp.task('test.e2e', ['test.compile'], function(done) { }); }); -gulp.task('test', ['test.check-format', 'test.check-lint', 'test.unit', 'test.e2e']); +gulp.task('test.tsc_e2e', function(done) { + // Test that "tsconfig.json" is read correctly. + var outDir = (__dirname.replace(/\\/g, '/') + '/build/tsc_e2e'); + if (fs.existsSync(outDir)) fsx.removeSync(outDir); + fs.mkdirSync(outDir); + + var cmd = 'node build/lib/main.js --translateBuiltins --tsconfig test/tsc_e2e/tsconfig.json ' + + '--generateLibraryName=true ' + + 'test/tsc_e2e/p1/user.ts'; + spawn('sh', ['-c', cmd], {stdio: 'inherit'}).on('close', function(code, signal) { + if (code > 0) { + onError(new Error('Failed to transpile ' + testfile + '.ts')); + return; + } + var content = fs.readFileSync(path.join(outDir, 'p1/user.dart'), 'utf-8'); + if (!content.match(/library p1\.user/) || !content.match(/import "package:mapped\/dep.dart"/)) { + throw new Error('incorrect content in p1.dart:\n' + content) + } + }); +}); + +gulp.task( + 'test', ['test.check-format', 'test.check-lint', 'test.unit', 'test.e2e', 'test.tsc_e2e']); gulp.task('watch', ['test.unit'], function() { failOnError = false; diff --git a/lib/main.ts b/lib/main.ts index 639e9ce..5bcdc5e 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -26,6 +26,8 @@ export interface TranspilerOptions { generateLibraryName?: boolean; /** Whether to generate source maps. */ generateSourceMap?: boolean; + /** A tsconfig.json to use to configure TypeScript compilation. */ + tsconfig?: string; /** * A base path to relativize absolute file paths against. This is useful for library name * generation (see above) and nicer file names in error messages. @@ -89,13 +91,39 @@ export class Transpiler { this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath)); } fileNames = fileNames.map((f) => this.normalizeSlashes(f)); - let host = this.createCompilerHost(); + + let host: ts.CompilerHost; + let compilerOpts: ts.CompilerOptions; + if (this.options.tsconfig) { + let {config, error} = + ts.readConfigFile(this.options.tsconfig, (f) => fs.readFileSync(f, 'utf-8')); + if (error) throw new Error(ts.flattenDiagnosticMessageText(error.messageText, '\n')); + let {options, errors} = ts.convertCompilerOptionsFromJson( + config.compilerOptions, path.dirname(this.options.tsconfig)); + if (errors && errors.length) { + throw new Error(errors.map((d) => this.diagnosticToString(d)).join('\n')); + } + host = ts.createCompilerHost(options, /*setParentNodes*/ true); + compilerOpts = options; + if (compilerOpts.rootDir != null && this.options.basePath == null) { + // Use the tsconfig's rootDir if basePath is not set. + this.options.basePath = compilerOpts.rootDir; + } + if (compilerOpts.outDir != null && destination == null) { + destination = compilerOpts.outDir; + console.log('dest', destination); + } + } else { + host = this.createCompilerHost(); + compilerOpts = this.getCompilerOptions(); + } + if (this.options.basePath && destination === undefined) { throw new Error( 'Must have a destination path when a basePath is specified ' + this.options.basePath); } let destinationRoot = destination || this.options.basePath || ''; - let program = ts.createProgram(fileNames, this.getCompilerOptions(), host); + let program = ts.createProgram(fileNames, compilerOpts, host); if (this.options.translateBuiltins) { this.fc.setTypeChecker(program.getTypeChecker()); } @@ -103,15 +131,15 @@ export class Transpiler { // Only write files that were explicitly passed in. let fileSet: {[s: string]: boolean} = {}; fileNames.forEach((f) => fileSet[f] = true); - this.errors = []; + program.getSourceFiles() .filter((sourceFile) => fileSet[sourceFile.fileName]) // Do not generate output for .d.ts files. .filter((sourceFile: ts.SourceFile) => !sourceFile.fileName.match(/\.d\.ts$/)) .forEach((f: ts.SourceFile) => { let dartCode = this.translate(f); - let outputFile = this.getOutputPath(path.resolve(f.fileName), destinationRoot); + let outputFile = this.getOutputPath(f.fileName, destinationRoot); mkdirP(path.dirname(outputFile)); fs.writeFileSync(outputFile, dartCode); }); @@ -175,8 +203,8 @@ export class Transpiler { private translate(sourceFile: ts.SourceFile): string { this.currentFile = sourceFile; - this.output = - new Output(sourceFile, this.getRelativeFileName(), this.options.generateSourceMap); + this.output = new Output( + sourceFile, this.getRelativeFileName(sourceFile.fileName), this.options.generateSourceMap); this.lastCommentIdx = -1; this.visit(sourceFile); let result = this.output.getResult(); @@ -203,17 +231,7 @@ export class Transpiler { diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); } - let diagnosticErrs = diagnostics.map((d) => { - let msg = ''; - if (d.file) { - let pos = d.file.getLineAndCharacterOfPosition(d.start); - let fn = this.getRelativeFileName(d.file.fileName); - msg += ` ${fn}:${pos.line + 1}:${pos.character + 1}`; - } - msg += ': '; - msg += ts.flattenDiagnosticMessageText(d.messageText, '\n'); - return msg; - }); + let diagnosticErrs = diagnostics.map((d) => this.diagnosticToString(d)); if (diagnosticErrs.length) errors = errors.concat(diagnosticErrs); if (errors.length) { @@ -223,21 +241,33 @@ export class Transpiler { } } + private diagnosticToString(diagnostic: ts.Diagnostic): string { + let msg = ''; + if (diagnostic.file) { + let pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + let fn = this.getRelativeFileName(diagnostic.file.fileName); + msg += ` ${fn}:${pos.line + 1}:${pos.character + 1}`; + } + msg += ': '; + msg += ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + return msg; + } + /** * Returns `filePath`, relativized to the program's `basePath`. - * @param filePath Optional path to relativize, defaults to the current file's path. + * @param filePath path to relativize. */ - getRelativeFileName(filePath?: string) { - if (filePath === undefined) filePath = path.resolve(this.currentFile.fileName); - // TODO(martinprobst): Use path.isAbsolute on node v0.12. - if (this.normalizeSlashes(path.resolve('/x/', filePath)) !== filePath) { - return filePath; // already relative. - } + getRelativeFileName(filePath: string) { let base = this.options.basePath || ''; - if (filePath.indexOf(base) !== 0 && !filePath.match(/\.d\.ts$/)) { + if (filePath[0] === '/' && filePath.indexOf(base) !== 0 && !filePath.match(/\.d\.ts$/)) { throw new Error(`Files must be located under base, got ${filePath} vs ${base}`); } - return this.normalizeSlashes(path.relative(base, filePath)); + let rel = path.relative(base, filePath); + if (rel.indexOf('../') === 0) { + // filePath is outside of rel, just use it directly. + rel = filePath; + } + return this.normalizeSlashes(rel); } emit(s: string) { this.output.emit(s); } diff --git a/lib/module.ts b/lib/module.ts index 8b8d12c..f38b1c1 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -11,13 +11,14 @@ export default class ModuleTranspiler extends base.TranspilerBase { visitNode(node: ts.Node): boolean { switch (node.kind) { case ts.SyntaxKind.SourceFile: + let sf = node; if (this.generateLibraryName) { this.emit('library'); - this.emit(this.getLibraryName()); + this.emit(this.getLibraryName(sf.fileName)); this.emit(';'); } - this.fc.emitExtraImports(node); - ts.forEachChild(node, this.visit.bind(this)); + this.fc.emitExtraImports(sf); + ts.forEachChild(sf, this.visit.bind(this)); break; case ts.SyntaxKind.EndOfFileToken: ts.forEachChild(node, this.visit.bind(this)); @@ -149,8 +150,8 @@ export default class ModuleTranspiler extends base.TranspilerBase { 'while with') .split(/ /); - getLibraryName(nameForTest?: string) { - let fileName = this.getRelativeFileName(nameForTest); + getLibraryName(fileName: string) { + fileName = this.getRelativeFileName(fileName); let parts = fileName.split('/'); return parts.filter((p) => p.length > 0) .map((p) => p.replace(/[^\w.]/g, '_')) diff --git a/test/main_test.ts b/test/main_test.ts index 9714592..e177633 100644 --- a/test/main_test.ts +++ b/test/main_test.ts @@ -119,9 +119,9 @@ class A { chai.expect(() => transpiler.getOutputPath('/outside/b/c.js', '/x')) .to.throw(/must be located under base/); }); - it('defaults to writing to the same location', () => { + it('defaults to writing to the full path', () => { let transpiler = new main.Transpiler({basePath: undefined}); - chai.expect(transpiler.getOutputPath('/a/b/c.js', '/e')).to.equal('/a/b/c.dart'); + chai.expect(transpiler.getOutputPath('/a/b/c.js', '/e')).to.equal('/e/a/b/c.dart'); chai.expect(transpiler.getOutputPath('b/c.js', '')).to.equal('b/c.dart'); }); it('translates .es6, .ts, and .js', () => { diff --git a/test/tsc_e2e/map_target/dep.ts b/test/tsc_e2e/map_target/dep.ts new file mode 100644 index 0000000..2e1873e --- /dev/null +++ b/test/tsc_e2e/map_target/dep.ts @@ -0,0 +1 @@ +export let msg = 'Hello, world!'; diff --git a/test/tsc_e2e/p1/user.ts b/test/tsc_e2e/p1/user.ts new file mode 100644 index 0000000..08c820f --- /dev/null +++ b/test/tsc_e2e/p1/user.ts @@ -0,0 +1,5 @@ +import {msg} from 'mapped/dep'; + +export function main() { + console.log(msg); +} diff --git a/test/tsc_e2e/tsconfig.json b/test/tsc_e2e/tsconfig.json new file mode 100644 index 0000000..3c31b36 --- /dev/null +++ b/test/tsc_e2e/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "baseUrl": ".", + "noEmit": true, + "noEmitOnError": true, + "paths": {"mapped/*": ["map_target/*"]}, + "rootDir": ".", + "outDir": "../../build/tsc_e2e" + } +} diff --git a/tsconfig.json b/tsconfig.json index 20b82bf..f7f0aea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ "exclude": [ "node_modules", "build", - "test/e2e" + "test/e2e", + "test/tsc_e2e" ] } From a00f9b8f308762432d545e2646aef23ae0892563 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 13:09:28 -0700 Subject: [PATCH 077/108] rel: 0.9.2. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32f0511..e7abf52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.1", + "version": "0.9.2", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 6ba84d0007aea1deeb29cac9cdb54a1a31a842a6 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 15:34:26 -0700 Subject: [PATCH 078/108] feat: translate 'angular/' imports to 'angular2/'. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D78 --- lib/module.ts | 4 +++- test/module_test.ts | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/module.ts b/lib/module.ts index f38b1c1..969d89b 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -122,7 +122,9 @@ export default class ModuleTranspiler extends base.TranspilerBase { // Strip './' to be more Dart-idiomatic. text = text.substring(2); } else if (!text.match(/^\.\.\//)) { - // Unprefixed imports are package imports. + // Replace '@angular' with 'angular2' for Dart. + text = text.replace(/^@angular\//, 'angular2/'); + // Unprefixed/absolute imports are package imports. text = 'package:' + text; } this.emit(JSON.stringify(text + '.dart')); diff --git a/test/module_test.ts b/test/module_test.ts index 2d59cfa..dc21df0 100644 --- a/test/module_test.ts +++ b/test/module_test.ts @@ -31,6 +31,10 @@ describe('imports', () => { }); it('fails for empty import specs', () => { expectErroneousCode('import {} from "baz";').to.throw(/empty import list/); }); + it('translates angular/ references to angular2/', () => { + expectTranslate(`import {foo} from '@angular/foo';`) + .to.equal(`import "package:angular2/foo.dart" show foo;`); + }); }); describe('exports', () => { From 13941e4ec06cafdf3545f248b0dbb9c98320d924 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 23 Apr 2016 16:17:28 -0700 Subject: [PATCH 079/108] rel: 0.9.3. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7abf52..1222bd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.2", + "version": "0.9.3", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From d757fc3d0c7281b7aec88dc767c5f9560f9e27e3 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sun, 24 Apr 2016 15:17:08 -0700 Subject: [PATCH 080/108] feat: strip leading at signs for library names. Reviewers: alexeagle, mhevery Reviewed By: alexeagle, mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D79 --- lib/module.ts | 1 + test/module_test.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/module.ts b/lib/module.ts index 969d89b..0ac177f 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -156,6 +156,7 @@ export default class ModuleTranspiler extends base.TranspilerBase { fileName = this.getRelativeFileName(fileName); let parts = fileName.split('/'); return parts.filter((p) => p.length > 0) + .map((p) => p.replace(/^@/, '')) .map((p) => p.replace(/[^\w.]/g, '_')) .map((p) => p.replace(/\.[jt]s$/g, '')) .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p) diff --git a/test/module_test.ts b/test/module_test.ts index dc21df0..4e1fb53 100644 --- a/test/module_test.ts +++ b/test/module_test.ts @@ -78,6 +78,8 @@ var x; }); it('leaves relative paths alone', () => { chai.expect(modTranspiler.getLibraryName('a/b')).to.equal('a.b'); }); + it('strips leading @ signs', + () => { chai.expect(modTranspiler.getLibraryName('@a/b')).to.equal('a.b'); }); it('handles reserved words', () => { chai.expect(modTranspiler.getLibraryName('/a/for/in/do/x')).to.equal('_for._in._do.x'); }); From 07b6c55982bd8f61d6dd7eef07aeae85c5dd6500 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 12:15:48 -0700 Subject: [PATCH 081/108] fix: depend on test.compile before tsc_e2e. Summary: Otherwise this task could run without its prerequisites. feat: handle lib.d.ts definitions from tsconfig When configured through tsconfig, instead of a custom compiler host, the fileName for default library definitions is the absolute path of the library. This change explicitly uses the compiler host's information for the location of lib.d.ts. Reviewers: alexeagle, mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D80 --- gulpfile.js | 5 +++-- lib/facade_converter.ts | 12 +++++++++--- lib/main.ts | 6 ++++-- test/tsc_e2e/p1/user.ts | 8 ++++++++ test/tsc_e2e/tsconfig.json | 3 ++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index dc5bca5..d0d0eac 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -121,7 +121,7 @@ gulp.task('test.e2e', ['test.compile'], function(done) { }); }); -gulp.task('test.tsc_e2e', function(done) { +gulp.task('test.tsc_e2e', ['test.compile'], function(done) { // Test that "tsconfig.json" is read correctly. var outDir = (__dirname.replace(/\\/g, '/') + '/build/tsc_e2e'); if (fs.existsSync(outDir)) fsx.removeSync(outDir); @@ -136,7 +136,8 @@ gulp.task('test.tsc_e2e', function(done) { return; } var content = fs.readFileSync(path.join(outDir, 'p1/user.dart'), 'utf-8'); - if (!content.match(/library p1\.user/) || !content.match(/import "package:mapped\/dep.dart"/)) { + if (!content.match(/library p1\.user/) || !content.match(/import "package:mapped\/dep.dart"/) || + !content.match(/Future/)) { throw new Error('incorrect content in p1.dart:\n' + content) } }); diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 76346c4..40e966c 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -25,6 +25,7 @@ function merge(...args: {[key: string]: any}[]): {[key: string]: any} { export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; + private defaultLibLocation: string; private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; private typingsRootRegex: RegExp; @@ -39,6 +40,11 @@ export class FacadeConverter extends base.TranspilerBase { this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); } + initializeTypeBasedConversion(tc: ts.TypeChecker, defaultLibLocation: string) { + this.tc = tc; + this.defaultLibLocation = defaultLibLocation; + } + private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) { for (let fileName of Object.keys(m)) { const file = m[fileName]; @@ -48,8 +54,6 @@ export class FacadeConverter extends base.TranspilerBase { } } - setTypeChecker(tc: ts.TypeChecker) { this.tc = tc; } - maybeHandleCall(c: ts.CallExpression): boolean { if (!this.tc) return false; let {context, symbol} = this.getCallInformation(c); @@ -266,7 +270,9 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - const fileName = decl.getSourceFile().fileName; + let fileName = decl.getSourceFile().fileName; + if (fileName === this.defaultLibLocation) fileName = 'lib'; + const canonicalFileName = this.getRelativeFileName(fileName) .replace(/(\.d)?\.ts$/, '') .replace(FACADE_NODE_MODULES_PREFIX, '') diff --git a/lib/main.ts b/lib/main.ts index 5bcdc5e..33ea37b 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -125,7 +125,8 @@ export class Transpiler { let destinationRoot = destination || this.options.basePath || ''; let program = ts.createProgram(fileNames, compilerOpts, host); if (this.options.translateBuiltins) { - this.fc.setTypeChecker(program.getTypeChecker()); + this.fc.initializeTypeBasedConversion( + program.getTypeChecker(), host.getDefaultLibFileName(compilerOpts)); } // Only write files that were explicitly passed in. @@ -148,7 +149,8 @@ export class Transpiler { translateProgram(program: ts.Program): {[path: string]: string} { if (this.options.translateBuiltins) { - this.fc.setTypeChecker(program.getTypeChecker()); + this.fc.initializeTypeBasedConversion( + program.getTypeChecker(), ts.getDefaultLibFileName(program.getCompilerOptions())); } let paths: {[path: string]: string} = {}; this.errors = []; diff --git a/test/tsc_e2e/p1/user.ts b/test/tsc_e2e/p1/user.ts index 08c820f..4bc9825 100644 --- a/test/tsc_e2e/p1/user.ts +++ b/test/tsc_e2e/p1/user.ts @@ -1,5 +1,13 @@ import {msg} from 'mapped/dep'; +function handle(v: any) { + return v; +} + export function main() { console.log(msg); + Promise.resolve(null) + .then((x) => console.log(1)) + .then(handle, handle) + .catch((e) => console.error(e)); } diff --git a/test/tsc_e2e/tsconfig.json b/test/tsc_e2e/tsconfig.json index 3c31b36..aa80fec 100644 --- a/test/tsc_e2e/tsconfig.json +++ b/test/tsc_e2e/tsconfig.json @@ -7,6 +7,7 @@ "noEmitOnError": true, "paths": {"mapped/*": ["map_target/*"]}, "rootDir": ".", - "outDir": "../../build/tsc_e2e" + "outDir": "../../build/tsc_e2e", + "target": "ES6" } } From 55a70527715aa4bd21addb26f2850e7586920890 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 14:42:51 -0700 Subject: [PATCH 082/108] rel: 0.9.4. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1222bd8..78399de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.3", + "version": "0.9.4", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From f261cc25ba0e68d0c770c351f561fb07ca834bfe Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 16:04:08 -0700 Subject: [PATCH 083/108] feat: support /* @ts2dart_const */ expressions. Summary: This allows marking an expression as const without JavaScript code for the `CONST_EXPR` call. `CONST_EXPR` is not recognised by simple bundlers such as rollup as a side-effect free function, which causes unnecessary symbols to be retained in the binary. Avoiding `CONST_EXPR` and instead using `/* @ts2dart_const */ (...)` should thus allow Angular 2 to reduce its binary size. Reviewers: mhevery, alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D83 --- lib/declaration.ts | 2 +- lib/facade_converter.ts | 31 +++++++++++++++++++++++++++---- test/facade_converter_test.ts | 9 +++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 3f8691b..ce0120f 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -242,7 +242,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { // "const" in TypeScript/ES6 corresponds to "final" in Dart, i.e. reference constness. // If a "const" variable is immediately initialized to a CONST_EXPR(), special case it to be // a deeply const constant, and generate "const ...". - isConst = this.fc.isConstCall(varDecl.initializer); + isConst = this.fc.isConstExpr(varDecl.initializer); } if (firstDecl === varDecl) { if (isConst) { diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 40e966c..8f92dae 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -307,12 +307,35 @@ export class FacadeConverter extends base.TranspilerBase { } isInsideConstExpr(node: ts.Node): boolean { - return this.isConstCall( - this.getAncestor(node, ts.SyntaxKind.CallExpression)); + while (node.parent) { + if (this.isConstExpr(node)) return true; + node = node.parent; + } + return false; } - isConstCall(node: ts.Expression): boolean { - return node && node.kind === ts.SyntaxKind.CallExpression && + /** + * isConstExpr returns true if the passed in expression itself is a const expression. const + * expressions are marked by the special comment @ts2dart_const (expr), or by the special + * function call CONST_EXPR. + */ + isConstExpr(node: ts.Node): boolean { + if (!node) return false; + + if (node.kind === ts.SyntaxKind.ParenthesizedExpression) { + let text = node.getFullText(); + let comments = ts.getLeadingCommentRanges(text, 0); + if (comments) { + for (let c of comments) { + let commentText = text.substring(c.pos, c.end); + if (commentText.indexOf('@ts2dart_const') !== -1) { + return true; + } + } + } + } + + return node.kind === ts.SyntaxKind.CallExpression && base.ident((node).expression) === 'CONST_EXPR'; } diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index e779fea..1922b48 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -394,6 +394,15 @@ const x = const {};`); .to.equal(`const MY_MAP = const {};`); }); + it('translates comment /* @ts2dart_const */ (...) to const (...)', () => { + expectWithTypes('const x = /* @ts2dart_const */ (1);').to.equal('const x = (1);'); + expectWithTypes(`const x = /* @ts2dart_const */ ([]);`).to.equal('const x = (const []);'); + // Nested parenthesized expressions. + expectWithTypes(`const x = /* @ts2dart_const */ ([([1])]);`).to.equal(`const x = (const [ + (const [1]) +]);`); + }); + it('translates forwardRef(() => T) to T', () => { expectWithTypes( From 195b2b6fbc87e99cdf6b41bd115c6aaec6c3e70e Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 17:25:48 -0700 Subject: [PATCH 084/108] rel: 0.9.5. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78399de..4840d09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.4", + "version": "0.9.5", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 1d6e6b10a1e447c10557e218acdd32a1251b6f74 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 19:40:09 -0700 Subject: [PATCH 085/108] feat: support comments in place of @CONST. Summary: ... to allow better results in rollup. Reviewers: mhevery, alexeagle Reviewed By: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D85 --- lib/base.ts | 8 -------- lib/call.ts | 2 +- lib/declaration.ts | 9 +++++---- lib/facade_converter.ts | 34 +++++++++++++++++++++++----------- test/declaration_test.ts | 9 +++++++++ 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/base.ts b/lib/base.ts index 709b28a..5129151 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -74,14 +74,6 @@ export class TranspilerBase { return n && (n.flags & flag) !== 0 || false; } - isConst(decl: ClassLike) { - return this.hasAnnotation(decl.decorators, 'CONST') || - (>decl.members).some((m) => { - if (m.kind !== ts.SyntaxKind.Constructor) return false; - return this.hasAnnotation(m.decorators, 'CONST'); - }); - } - maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] { let members = node.members; if (members.length !== 1 || members[0].kind !== ts.SyntaxKind.IndexSignature) { diff --git a/lib/call.ts b/lib/call.ts index 86aa01b..7287083 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -119,7 +119,7 @@ export default class CallTranspiler extends base.TranspilerBase { let errorThisAssignment = 'assignments in const constructors must assign into this.'; let parent = ctor.parent; - let parentIsConst = this.isConst(parent); + let parentIsConst = this.fc.isConstClass(parent); let superCall: ts.CallExpression; let expressions: ts.Expression[] = []; // Find super() calls and (if in a const ctor) collect assignment expressions (not statements!) diff --git a/lib/declaration.ts b/lib/declaration.ts index ce0120f..291ed6e 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -98,7 +98,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } if (!className) this.reportError(ctorDecl, 'cannot find outer class node'); this.visitDeclarationMetadata(ctorDecl); - if (this.isConst(ctorDecl.parent)) { + if (this.fc.isConstClass(ctorDecl.parent)) { this.emit('const'); } this.visit(className); @@ -340,8 +340,9 @@ export default class DeclarationTranspiler extends base.TranspilerBase { private visitProperty(decl: ts.PropertyDeclaration|ts.ParameterDeclaration, isParameter = false) { if (!isParameter) this.visitDeclarationMetadata(decl); let containingClass = (isParameter ? decl.parent.parent : decl.parent); - let isConstField = this.hasAnnotation(decl.decorators, 'CONST'); - let hasConstCtor = this.isConst(containingClass); + let isConstField = + this.fc.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST'); + let hasConstCtor = this.fc.isConstClass(containingClass); if (isConstField) { // const implies final this.emit('const'); @@ -392,7 +393,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visitEachIfPresent(decl.members); // Generate a constructor to host the const modifier, if needed - if (this.isConst(decl) && + if (this.fc.isConstClass(decl) && !(>decl.members) .some((m) => m.kind === ts.SyntaxKind.Constructor)) { this.emit('const'); diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 8f92dae..cbfac77 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -314,6 +314,14 @@ export class FacadeConverter extends base.TranspilerBase { return false; } + isConstClass(decl: base.ClassLike) { + return this.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST') || + (>decl.members).some((m) => { + if (m.kind !== ts.SyntaxKind.Constructor) return false; + return this.hasAnnotation(m.decorators, 'CONST'); + }); + } + /** * isConstExpr returns true if the passed in expression itself is a const expression. const * expressions are marked by the special comment @ts2dart_const (expr), or by the special @@ -322,23 +330,27 @@ export class FacadeConverter extends base.TranspilerBase { isConstExpr(node: ts.Node): boolean { if (!node) return false; - if (node.kind === ts.SyntaxKind.ParenthesizedExpression) { - let text = node.getFullText(); - let comments = ts.getLeadingCommentRanges(text, 0); - if (comments) { - for (let c of comments) { - let commentText = text.substring(c.pos, c.end); - if (commentText.indexOf('@ts2dart_const') !== -1) { - return true; - } - } - } + if (node.kind === ts.SyntaxKind.ParenthesizedExpression && this.hasConstComment(node)) { + return true; } return node.kind === ts.SyntaxKind.CallExpression && base.ident((node).expression) === 'CONST_EXPR'; } + hasConstComment(node: ts.Node): boolean { + let text = node.getFullText(); + let comments = ts.getLeadingCommentRanges(text, 0); + if (!comments) return false; + for (let c of comments) { + let commentText = text.substring(c.pos, c.end); + if (commentText.indexOf('@ts2dart_const') !== -1) { + return true; + } + } + return false; + } + private emitMethodCall(name: string, args?: ts.Expression[]) { this.emit('.'); this.emitCall(name, args); diff --git a/test/declaration_test.ts b/test/declaration_test.ts index bcb412b..8808161 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -171,6 +171,15 @@ class X { final bool _marbles; const X(this.foo, num b, [this._marbles = true]); }`); + expectTranslate( + '/* @ts2dart_const */ class X { ' + + 'constructor(public foo: string) {} }') + .to.equal(`/* @ts2dart_const */ +class X { + final String foo; + const X(this.foo); +}`); + }); }); }); From be66f248f54f9d994d51c8c6f81d26744e6a606d Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Apr 2016 20:10:14 -0700 Subject: [PATCH 086/108] rel: 0.9.6. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4840d09..369d15c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.5", + "version": "0.9.6", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 204d17edd5f5654fdb1e851bf5214ccb863175b8 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 13:13:29 -0700 Subject: [PATCH 087/108] feat: allow /* @ts2dart_const */ without parens. Reviewers: alexeagle, mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D86 --- lib/facade_converter.ts | 2 +- test/facade_converter_test.ts | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index cbfac77..2c64c73 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -330,7 +330,7 @@ export class FacadeConverter extends base.TranspilerBase { isConstExpr(node: ts.Node): boolean { if (!node) return false; - if (node.kind === ts.SyntaxKind.ParenthesizedExpression && this.hasConstComment(node)) { + if (this.hasConstComment(node)) { return true; } diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 1922b48..9fdb67f 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -396,11 +396,12 @@ const x = const {};`); it('translates comment /* @ts2dart_const */ (...) to const (...)', () => { expectWithTypes('const x = /* @ts2dart_const */ (1);').to.equal('const x = (1);'); - expectWithTypes(`const x = /* @ts2dart_const */ ([]);`).to.equal('const x = (const []);'); - // Nested parenthesized expressions. - expectWithTypes(`const x = /* @ts2dart_const */ ([([1])]);`).to.equal(`const x = (const [ - (const [1]) -]);`); + expectWithTypes('const x = /* @ts2dart_const */ 1 + 2;').to.equal('const x = 1 + 2;'); + expectWithTypes(`const x = /* @ts2dart_const */ [];`).to.equal('const x = const [];'); + // Nested expressions. + expectWithTypes(`const x = /* @ts2dart_const */ [[1]];`).to.equal(`const x = const [ + const [1] +];`); }); it('translates forwardRef(() => T) to T', From 9b6e66596ac82ccbed02360512b1980fff1fb9ca Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 13:21:37 -0700 Subject: [PATCH 088/108] rel: 0.9.7. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 369d15c..e48ed87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.6", + "version": "0.9.7", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 3c8e3f9a2cffae898ec80ca62a16f08e5f6e91f4 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 15:23:51 -0700 Subject: [PATCH 089/108] fix: move to a newer Dart `test` package to fix build failures. Summary: Installing `test` version 0.12.8 fails on Travis, but works locally. Version 0.12.13 works in both locations. This does not really make sense - `pub get` should be deterministic, and should also be able to get the older version of the test package, but whatever. Reviewers: vikerman Reviewed By: vikerman Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D87 --- test/e2e/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/pubspec.yaml b/test/e2e/pubspec.yaml index cebfd21..0f601eb 100644 --- a/test/e2e/pubspec.yaml +++ b/test/e2e/pubspec.yaml @@ -1,5 +1,5 @@ -name: e2e -description: Transpiled end-to-end tests for ts2dart. +name: e2e +description: Transpiled end-to-end tests for ts2dart. dependencies: - test: 0.12.8 + test: 0.12.13 From 20b521d4832d3bd4c8af70aac0c6593c9e611fe0 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 15:38:23 -0700 Subject: [PATCH 090/108] chore: configure arc to land on master. Summary: This is useful when the feature branch tracks a different upstream branch from master, which happens e.g. when you `git push --set-upstream feature feature`, which in turn is useful to have Travis test a change. Reviewers: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D88 --- .arcconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.arcconfig b/.arcconfig index 894b55d..b6b12c1 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,4 +1,5 @@ { + "base": "git:origin/master", "phabricator.uri" : "https://reviews.angular.io/", "load": [ ".arc/npm-test" From 3a7a40d91155b784d7fae537a97e95951ff125f0 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 16:54:09 -0700 Subject: [PATCH 091/108] feat: mark all parameter initialisers as const. Summary: In Dart, all default values have to be const. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D89 --- lib/facade_converter.ts | 5 +++++ test/function_test.ts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 2c64c73..d165c7f 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -308,6 +308,11 @@ export class FacadeConverter extends base.TranspilerBase { isInsideConstExpr(node: ts.Node): boolean { while (node.parent) { + if (node.parent.kind === ts.SyntaxKind.Parameter && + (node.parent as ts.ParameterDeclaration).initializer === node) { + // initializers of parameters must be const in Dart. + return true; + } if (this.isConstExpr(node)) return true; node = node.parent; } diff --git a/test/function_test.ts b/test/function_test.ts index 547366b..0d10d9f 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -10,6 +10,10 @@ describe('functions', () => { expectTranslate('function x(p1, a = 42, b = 1, p2) { return 42; }') .to.equal(`x(p1, [a = 42, b = 1, p2]) { return 42; +}`); + expectTranslate('function x(a = [], b = {}, c = new C()) { return 42; }') + .to.equal(`x([a = const [], b = const {}, c = const C()]) { + return 42; }`); }); it('translates optional parameters', () => { From b92b78714825f83185f53110cc25665e615957c7 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 18:55:49 -0700 Subject: [PATCH 092/108] fix: only apply const comments within an expression. Summary: This fixes the bug where all code in const marked classes was treated as const. Reviewers: mhevery Reviewed By: mhevery Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D90 --- lib/facade_converter.ts | 15 +++++++++++++++ test/declaration_test.ts | 12 +++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index d165c7f..53d2ec1 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -306,6 +306,16 @@ export class FacadeConverter extends base.TranspilerBase { `Please add type declarations to disambiguate.`); } + private static DECLARATIONS: {[k: number]: boolean} = { + [ts.SyntaxKind.ClassDeclaration]: true, + [ts.SyntaxKind.FunctionDeclaration]: true, + [ts.SyntaxKind.InterfaceDeclaration]: true, + [ts.SyntaxKind.MethodDeclaration]: true, + [ts.SyntaxKind.PropertyDeclaration]: true, + [ts.SyntaxKind.PropertyDeclaration]: true, + [ts.SyntaxKind.VariableDeclaration]: true, + }; + isInsideConstExpr(node: ts.Node): boolean { while (node.parent) { if (node.parent.kind === ts.SyntaxKind.Parameter && @@ -315,6 +325,11 @@ export class FacadeConverter extends base.TranspilerBase { } if (this.isConstExpr(node)) return true; node = node.parent; + if (FacadeConverter.DECLARATIONS[node.kind]) { + // Stop walking upwards when hitting a declaration - @ts2dart_const should only propagate + // to the immediate declaration it applies to (but should be transitive in expressions). + return false; + } } return false; } diff --git a/test/declaration_test.ts b/test/declaration_test.ts index 8808161..0bdc0ba 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -171,15 +171,17 @@ class X { final bool _marbles; const X(this.foo, num b, [this._marbles = true]); }`); - expectTranslate( - '/* @ts2dart_const */ class X { ' + - 'constructor(public foo: string) {} }') - .to.equal(`/* @ts2dart_const */ + expectTranslate(`/* @ts2dart_const */ class X { + constructor(public foo: string) {} + foo() { return new Bar(); } +}`).to.equal(`/* @ts2dart_const */ class X { final String foo; const X(this.foo); + foo() { + return new Bar(); + } }`); - }); }); }); From cb0f53851df55783b133ea72062e7353124316f9 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Apr 2016 18:59:29 -0700 Subject: [PATCH 093/108] rel: 0.9.8. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e48ed87..1ac0d60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.7", + "version": "0.9.8", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 78d37e4b85e01032058fe62660d9693a174e8174 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 27 Apr 2016 11:41:23 +0100 Subject: [PATCH 094/108] Merge pull request #367 from ochafik/fix-future-ctors fix: Future.{value,error} are named constructors, not statics --- lib/facade_converter.ts | 2 ++ test/facade_converter_test.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 53d2ec1..34b212f 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -770,10 +770,12 @@ export class FacadeConverter extends base.TranspilerBase { }; private es6PromisesProp: ts.Map = { 'resolve': (p: ts.PropertyAccessExpression) => { + this.emit('new '); this.visit(p.expression); this.emit('.value'); }, 'reject': (p: ts.PropertyAccessExpression) => { + this.emit('new '); this.visit(p.expression); this.emit('.error'); }, diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 9fdb67f..6f95d38 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -254,10 +254,10 @@ var y = x.length;`); it('translates into Futures', () => { expectWithTypes('let x: Promise = Promise.resolve(1);').to.equal(`import "dart:async"; -Future x = Future.value(1);`); +Future x = new Future.value(1);`); expectWithTypes('let x: Promise = Promise.reject(1);').to.equal(`import "dart:async"; -Future x = Future.error(1);`); +Future x = new Future.error(1);`); expectWithTypes('let x: Promise = new Promise((resolve) => {resolve(1);});') .to.equal(`import "dart:async"; From 31f9b38a8f8245135b9f9c3774e1eadea44ec713 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 27 Apr 2016 12:22:09 -0700 Subject: [PATCH 095/108] feat: clean up path handling. When using TypeScript's path support and driving ts2dart using a tsconfig.json, path resolution yields absolute paths. This change resolves the well known paths using TypeScript's own module resolver, and then looks up absolute file paths against that, greatly simplifying the path handling logic (woohoo!). Reviewers: alexeagle Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D94 --- lib/facade_converter.ts | 274 +++++++++++++++++----------------- lib/main.ts | 16 +- test/facade_converter_test.ts | 26 ---- test/test_support.ts | 15 +- 4 files changed, 152 insertions(+), 179 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 34b212f..b4cc699 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -1,5 +1,6 @@ import * as base from './base'; import * as ts from 'typescript'; +import * as path from 'path'; import {Transpiler} from './main'; type CallHandler = (c: ts.CallExpression, context: ts.Expression) => void; @@ -10,7 +11,7 @@ type Set = { const FACADE_DEBUG = false; -const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; +const DEFAULT_LIB_MARKER = '__ts2dart_default_lib'; function merge(...args: {[key: string]: any}[]): {[key: string]: any} { let returnObject: {[key: string]: any} = {}; @@ -22,27 +23,29 @@ function merge(...args: {[key: string]: any}[]): {[key: string]: any} { return returnObject; } - export class FacadeConverter extends base.TranspilerBase { private tc: ts.TypeChecker; private defaultLibLocation: string; private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; - private typingsRootRegex: RegExp; private genericMethodDeclDepth = 0; - constructor(transpiler: Transpiler, typingsRoot = '') { + constructor(transpiler: Transpiler) { super(transpiler); + this.extractPropertyNames(this.callHandlers, this.candidateProperties); this.extractPropertyNames(this.propertyHandlers, this.candidateProperties); - this.extractPropertyNames(this.TS_TO_DART_TYPENAMES, this.candidateTypes); - - this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); + this.extractPropertyNames(this.tsToDartTypeNames, this.candidateTypes); } - initializeTypeBasedConversion(tc: ts.TypeChecker, defaultLibLocation: string) { + initializeTypeBasedConversion( + tc: ts.TypeChecker, opts: ts.CompilerOptions, host: ts.CompilerHost) { this.tc = tc; - this.defaultLibLocation = defaultLibLocation; + this.defaultLibLocation = ts.getDefaultLibFilePath(opts).replace(/\.d\.ts$/, ''); + this.resolveModuleNames(opts, host, this.callHandlers); + this.resolveModuleNames(opts, host, this.propertyHandlers); + this.resolveModuleNames(opts, host, this.tsToDartTypeNames); + this.resolveModuleNames(opts, host, this.callHandlerReplaceNew); } private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) { @@ -54,6 +57,27 @@ export class FacadeConverter extends base.TranspilerBase { } } + private resolveModuleNames( + opts: ts.CompilerOptions, host: ts.CompilerHost, m: ts.Map>) { + for (let mn of Object.keys(m)) { + let actual: string; + let absolute: string; + if (mn === DEFAULT_LIB_MARKER) { + actual = this.defaultLibLocation; + } else { + let resolved = ts.resolveModuleName(mn, '', opts, host); + if (!resolved.resolvedModule) continue; + actual = resolved.resolvedModule.resolvedFileName.replace(/(\.d)?\.ts$/, ''); + // TypeScript's resolution returns relative paths here, but uses absolute ones in + // SourceFile.fileName later. Make sure to hit both use cases. + absolute = path.resolve(actual); + } + if (FACADE_DEBUG) console.log('Resolved module', mn, '->', actual); + m[actual] = m[mn]; + if (absolute) m[absolute] = m[mn]; + } + } + maybeHandleCall(c: ts.CallExpression): boolean { if (!this.tc) return false; let {context, symbol} = this.getCallInformation(c); @@ -185,7 +209,7 @@ export class FacadeConverter extends base.TranspilerBase { } let fileAndName = this.getFileAndName(typeName, symbol); if (fileAndName) { - let fileSubs = this.TS_TO_DART_TYPENAMES[fileAndName.fileName]; + let fileSubs = this.tsToDartTypeNames[fileAndName.fileName]; if (fileSubs && fileSubs.hasOwnProperty(fileAndName.qname)) { this.emit(fileSubs[fileAndName.qname]); return; @@ -222,7 +246,6 @@ export class FacadeConverter extends base.TranspilerBase { ident = base.ident(expr); if (!this.candidateProperties.hasOwnProperty(ident)) return {}; symbol = this.tc.getSymbolAtLocation(expr); - if (FACADE_DEBUG) console.error('s:', symbol); if (!symbol) { this.reportMissingType(c, ident); @@ -237,7 +260,6 @@ export class FacadeConverter extends base.TranspilerBase { if (!this.candidateProperties.hasOwnProperty(ident)) return {}; symbol = this.tc.getSymbolAtLocation(pa); - if (FACADE_DEBUG) console.error('s:', symbol); // Error will be reported by PropertyAccess handling below. if (!symbol) return {}; @@ -270,13 +292,8 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - let fileName = decl.getSourceFile().fileName; - if (fileName === this.defaultLibLocation) fileName = 'lib'; - - const canonicalFileName = this.getRelativeFileName(fileName) - .replace(/(\.d)?\.ts$/, '') - .replace(FACADE_NODE_MODULES_PREFIX, '') - .replace(this.typingsRootRegex, ''); + const canonicalFileName = + decl.getSourceFile().fileName.replace(/(\.d)?\.ts$/, '').replace(/(\.d)?\.ts$/, ''); let qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, @@ -284,20 +301,15 @@ export class FacadeConverter extends base.TranspilerBase { if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) { qname = symbol.getName(); } - if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); + if (FACADE_DEBUG) console.error('cfn:', canonicalFileName, 'qn:', qname); return {fileName: canonicalFileName, qname}; } - private isNamedType(node: ts.Node, fileName: string, qname: string): boolean { + private isNamedDefaultLibType(node: ts.Node, qname: string): boolean { let symbol = this.tc.getTypeAtLocation(node).getSymbol(); if (!symbol) return false; let actual = this.getFileAndName(node, symbol); - if (fileName === 'lib' && !(actual.fileName === 'lib' || actual.fileName === 'lib.es6')) { - return false; - } else { - if (fileName !== actual.fileName) return false; - } - return qname === actual.qname; + return actual.fileName === this.defaultLibLocation && qname === actual.qname; } private reportMissingType(n: ts.Node, ident: string) { @@ -406,9 +418,8 @@ export class FacadeConverter extends base.TranspilerBase { 'Location': 'dynamic', }; - private TS_TO_DART_TYPENAMES: ts.Map> = { - 'lib': this.stdlibTypeReplacements, - 'lib.es6': this.stdlibTypeReplacements, + private tsToDartTypeNames: ts.Map> = { + [DEFAULT_LIB_MARKER]: this.stdlibTypeReplacements, 'angular2/src/facade/lang': {'Date': 'DateTime'}, 'rxjs/Observable': {'Observable': 'Stream'}, @@ -481,7 +492,98 @@ export class FacadeConverter extends base.TranspilerBase { }, }; - private stdlibHandlers: ts.Map = merge(this.es6Promises, { + private es6Collections: ts.Map = { + 'Map.set': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('['); + this.visit(c.arguments[0]); + this.emit(']'); + this.emit('='); + this.visit(c.arguments[1]); + }, + 'Map.get': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('['); + this.visit(c.arguments[0]); + this.emit(']'); + }, + 'Map.has': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emitMethodCall('containsKey', c.arguments); + }, + 'Map.delete': (c: ts.CallExpression, context: ts.Expression) => { + // JS Map.delete(k) returns whether k was present in the map, + // convert to: + // (Map.containsKey(k) && (Map.remove(k) !== null || true)) + // (Map.remove(k) !== null || true) is required to always returns true + // when Map.containsKey(k) + this.emit('('); + this.visit(context); + this.emitMethodCall('containsKey', c.arguments); + this.emit('&& ('); + this.visit(context); + this.emitMethodCall('remove', c.arguments); + this.emit('!= null || true ) )'); + }, + 'Map.forEach': (c: ts.CallExpression, context: ts.Expression) => { + let cb: any; + let params: any; + + switch (c.arguments[0].kind) { + case ts.SyntaxKind.FunctionExpression: + cb = (c.arguments[0]); + params = cb.parameters; + if (params.length !== 2) { + this.reportError(c, 'Map.forEach callback requires exactly two arguments'); + return; + } + this.visit(context); + this.emit('. forEach ( ('); + this.visit(params[1]); + this.emit(','); + this.visit(params[0]); + this.emit(')'); + this.visit(cb.body); + this.emit(')'); + break; + + case ts.SyntaxKind.ArrowFunction: + cb = (c.arguments[0]); + params = cb.parameters; + if (params.length !== 2) { + this.reportError(c, 'Map.forEach callback requires exactly two arguments'); + return; + } + this.visit(context); + this.emit('. forEach ( ('); + this.visit(params[1]); + this.emit(','); + this.visit(params[0]); + this.emit(')'); + if (cb.body.kind !== ts.SyntaxKind.Block) { + this.emit('=>'); + } + this.visit(cb.body); + this.emit(')'); + break; + + default: + this.visit(context); + this.emit('. forEach ( ( k , v ) => ('); + this.visit(c.arguments[0]); + this.emit(') ( v , k ) )'); + break; + } + }, + 'Array.find': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('. firstWhere ('); + this.visit(c.arguments[0]); + this.emit(', orElse : ( ) => null )'); + }, + }; + + private stdlibHandlers: ts.Map = merge(this.es6Promises, this.es6Collections, { 'Array.push': (c: ts.CallExpression, context: ts.Expression) => { this.visit(context); this.emitMethodCall('add', c.arguments); @@ -532,7 +634,7 @@ export class FacadeConverter extends base.TranspilerBase { this.visit(context); this.emit(')'); c.arguments.forEach(arg => { - if (!this.isNamedType(arg, 'lib', 'Array')) { + if (!this.isNamedDefaultLibType(arg, 'Array')) { this.reportError(arg, 'Array.concat only takes Array arguments'); } this.emit('.. addAll ('); @@ -619,108 +721,12 @@ export class FacadeConverter extends base.TranspilerBase { }, }); - private es6Collections: ts.Map = { - 'Map.set': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emit('['); - this.visit(c.arguments[0]); - this.emit(']'); - this.emit('='); - this.visit(c.arguments[1]); - }, - 'Map.get': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emit('['); - this.visit(c.arguments[0]); - this.emit(']'); - }, - 'Map.has': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('containsKey', c.arguments); - }, - 'Map.delete': (c: ts.CallExpression, context: ts.Expression) => { - // JS Map.delete(k) returns whether k was present in the map, - // convert to: - // (Map.containsKey(k) && (Map.remove(k) !== null || true)) - // (Map.remove(k) !== null || true) is required to always returns true - // when Map.containsKey(k) - this.emit('('); - this.visit(context); - this.emitMethodCall('containsKey', c.arguments); - this.emit('&& ('); - this.visit(context); - this.emitMethodCall('remove', c.arguments); - this.emit('!= null || true ) )'); - }, - 'Map.forEach': (c: ts.CallExpression, context: ts.Expression) => { - let cb: any; - let params: any; - - switch (c.arguments[0].kind) { - case ts.SyntaxKind.FunctionExpression: - cb = (c.arguments[0]); - params = cb.parameters; - if (params.length !== 2) { - this.reportError(c, 'Map.forEach callback requires exactly two arguments'); - return; - } - this.visit(context); - this.emit('. forEach ( ('); - this.visit(params[1]); - this.emit(','); - this.visit(params[0]); - this.emit(')'); - this.visit(cb.body); - this.emit(')'); - break; - - case ts.SyntaxKind.ArrowFunction: - cb = (c.arguments[0]); - params = cb.parameters; - if (params.length !== 2) { - this.reportError(c, 'Map.forEach callback requires exactly two arguments'); - return; - } - this.visit(context); - this.emit('. forEach ( ('); - this.visit(params[1]); - this.emit(','); - this.visit(params[0]); - this.emit(')'); - if (cb.body.kind !== ts.SyntaxKind.Block) { - this.emit('=>'); - } - this.visit(cb.body); - this.emit(')'); - break; - - default: - this.visit(context); - this.emit('. forEach ( ( k , v ) => ('); - this.visit(c.arguments[0]); - this.emit(') ( v , k ) )'); - break; - } - }, - 'Array.find': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emit('. firstWhere ('); - this.visit(c.arguments[0]); - this.emit(', orElse : ( ) => null )'); - }, - }; - private callHandlerReplaceNew: ts.Map> = { - 'es6-promise/es6-promise': {'Promise': true}, - 'es6-shim/es6-shim': {'Promise': true}, + [DEFAULT_LIB_MARKER]: {'Promise': true}, }; private callHandlers: ts.Map> = { - 'lib': this.stdlibHandlers, - 'lib.es6': this.stdlibHandlers, - 'es6-promise/es6-promise': this.es6Promises, - 'es6-shim/es6-shim': merge(this.es6Promises, this.es6Collections), - 'es6-collections/es6-collections': this.es6Collections, + [DEFAULT_LIB_MARKER]: this.stdlibHandlers, 'angular2/manual_typings/globals': this.es6Collections, 'angular2/src/facade/collection': { 'Map': (c: ts.CallExpression, context: ts.Expression): boolean => { @@ -769,12 +775,12 @@ export class FacadeConverter extends base.TranspilerBase { }, }; private es6PromisesProp: ts.Map = { - 'resolve': (p: ts.PropertyAccessExpression) => { + 'PromiseConstructor.resolve': (p: ts.PropertyAccessExpression) => { this.emit('new '); this.visit(p.expression); this.emit('.value'); }, - 'reject': (p: ts.PropertyAccessExpression) => { + 'PromiseConstructor.reject': (p: ts.PropertyAccessExpression) => { this.emit('new '); this.visit(p.expression); this.emit('.error'); @@ -782,8 +788,6 @@ export class FacadeConverter extends base.TranspilerBase { }; private propertyHandlers: ts.Map> = { - 'es6-shim/es6-shim': this.es6CollectionsProp, - 'es6-collections/es6-collections': this.es6CollectionsProp, - 'es6-promise/es6-promise': this.es6PromisesProp, + [DEFAULT_LIB_MARKER]: merge(this.es6CollectionsProp, this.es6PromisesProp), }; } diff --git a/lib/main.ts b/lib/main.ts index 33ea37b..8e636c4 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -42,17 +42,13 @@ export interface TranspilerOptions { * Enforce conventions of public/private keyword and underscore prefix */ enforceUnderscoreConventions?: boolean; - /** - * Sets a root path to look for typings used by the facade converter. - */ - typingsRoot?: string; } export const COMPILER_OPTIONS: ts.CompilerOptions = { allowNonTsExtensions: true, experimentalDecorators: true, module: ts.ModuleKind.CommonJS, - target: ts.ScriptTarget.ES5, + target: ts.ScriptTarget.ES6, }; export class Transpiler { @@ -69,7 +65,7 @@ export class Transpiler { constructor(private options: TranspilerOptions = {}) { // TODO: Remove the angular2 default when angular uses typingsRoot. - this.fc = new FacadeConverter(this, options.typingsRoot || 'angular2/typings/'); + this.fc = new FacadeConverter(this); this.transpilers = [ new CallTranspiler(this, this.fc), // Has to come before StatementTranspiler! new DeclarationTranspiler(this, this.fc, options.enforceUnderscoreConventions), @@ -111,7 +107,6 @@ export class Transpiler { } if (compilerOpts.outDir != null && destination == null) { destination = compilerOpts.outDir; - console.log('dest', destination); } } else { host = this.createCompilerHost(); @@ -125,8 +120,7 @@ export class Transpiler { let destinationRoot = destination || this.options.basePath || ''; let program = ts.createProgram(fileNames, compilerOpts, host); if (this.options.translateBuiltins) { - this.fc.initializeTypeBasedConversion( - program.getTypeChecker(), host.getDefaultLibFileName(compilerOpts)); + this.fc.initializeTypeBasedConversion(program.getTypeChecker(), compilerOpts, host); } // Only write files that were explicitly passed in. @@ -147,10 +141,10 @@ export class Transpiler { this.checkForErrors(program); } - translateProgram(program: ts.Program): {[path: string]: string} { + translateProgram(program: ts.Program, host: ts.CompilerHost): {[path: string]: string} { if (this.options.translateBuiltins) { this.fc.initializeTypeBasedConversion( - program.getTypeChecker(), ts.getDefaultLibFileName(program.getCompilerOptions())); + program.getTypeChecker(), program.getCompilerOptions(), host); } let paths: {[path: string]: string} = {}; this.errors = []; diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 6f95d38..0c26dd7 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,37 +1,11 @@ /// -import * as fs from 'fs'; import {expectTranslate, FAKE_MAIN, translateSource} from './test_support'; import chai = require('chai'); -let es6RuntimeDeclarations = ` - interface Iterable {} - interface Symbol {} - interface Map { - get(key: K): V; - has(key: K): boolean; - set(key: K, value: V): Map; - size: number; - delete(key: K): boolean; - forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void; - } - interface Array { - find(predicate: (value: T, index: number, obj: Array) => boolean, thisArg?: any): T; - } - declare var Map: { - new(): Map; - prototype: Map; - }; - declare var Symbol; - `; - - function getSources(str: string): {[k: string]: string} { let srcs: {[k: string]: string} = { - 'some/path/to/typings/es6-shim/es6-shim': es6RuntimeDeclarations, 'angular2/src/core/di/forward_ref.d.ts': ` export declare function forwardRef(x: T): T;`, - 'some/path/to/typings/es6-promise/es6-promise.d.ts': - fs.readFileSync('typings/es6-promise/es6-promise.d.ts', 'utf-8'), 'node_modules/rxjs/Observable.d.ts': ` export declare class Observable {}`, 'angular2/src/facade/async.ts': ` diff --git a/test/test_support.ts b/test/test_support.ts index 0028161..8b1d66b 100644 --- a/test/test_support.ts +++ b/test/test_support.ts @@ -27,11 +27,11 @@ export function expectErroneousCode(tsCode: Input, options: main.TranspilerOptio } let compilerOptions = main.COMPILER_OPTIONS; -let defaultLibName = ts.getDefaultLibFileName(compilerOptions); +let defaultLibPath = ts.getDefaultLibFilePath(compilerOptions); let libSource = fs.readFileSync(ts.getDefaultLibFilePath(compilerOptions), 'utf-8'); let libSourceFile: ts.SourceFile; -export function parseFiles(nameToContent: StringMap): ts.Program { +export function parseFiles(nameToContent: StringMap): [ts.Program, ts.CompilerHost] { let result: string; let compilerHost: ts.CompilerHost = { getSourceFile: function(sourceName, languageVersion) { @@ -39,7 +39,7 @@ export function parseFiles(nameToContent: StringMap): ts.Program { return ts.createSourceFile( sourceName, nameToContent[sourceName], compilerOptions.target, true); } - if (sourceName === defaultLibName) { + if (sourceName === defaultLibPath) { if (!libSourceFile) { // Cache to avoid excessive test times. libSourceFile = ts.createSourceFile(sourceName, libSource, compilerOptions.target, true); @@ -51,7 +51,8 @@ export function parseFiles(nameToContent: StringMap): ts.Program { writeFile: function(name, text, writeByteOrderMark) { result = text; }, fileExists: (sourceName) => { return !!nameToContent[sourceName]; }, readFile: (filename): string => { throw new Error('unexpected call to readFile'); }, - getDefaultLibFileName: () => defaultLibName, + getDefaultLibLocation: () => defaultLibPath, + getDefaultLibFileName: () => defaultLibPath, useCaseSensitiveFileNames: () => false, getCanonicalFileName: (filename) => '../' + filename, getCurrentDirectory: () => '', @@ -66,7 +67,7 @@ export function parseFiles(nameToContent: StringMap): ts.Program { let first = program.getSyntacticDiagnostics()[0]; throw new Error(`${first.start}: ${first.messageText} in ${nameToContent[entryPoints[0]]}`); } - return program; + return [program, compilerHost]; } export const FAKE_MAIN = 'angular2/some/main.ts'; @@ -83,8 +84,8 @@ export function translateSources(contents: Input, options: main.TranspilerOption } options.enforceUnderscoreConventions = true; let transpiler = new main.Transpiler(options); - let program = parseFiles(namesToContent); - return transpiler.translateProgram(program); + let [program, host] = parseFiles(namesToContent); + return transpiler.translateProgram(program, host); } From d5a51033b98ee82e40a6f75870499a3d6d58f22c Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 19:06:05 -0700 Subject: [PATCH 096/108] feat: map immediate literals to const expressions. --- lib/declaration.ts | 4 +++- test/declaration_test.ts | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/declaration.ts b/lib/declaration.ts index 291ed6e..c992c69 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -242,7 +242,9 @@ export default class DeclarationTranspiler extends base.TranspilerBase { // "const" in TypeScript/ES6 corresponds to "final" in Dart, i.e. reference constness. // If a "const" variable is immediately initialized to a CONST_EXPR(), special case it to be // a deeply const constant, and generate "const ...". - isConst = this.fc.isConstExpr(varDecl.initializer); + isConst = varDecl.initializer.kind === ts.SyntaxKind.StringLiteral || + varDecl.initializer.kind === ts.SyntaxKind.NumericLiteral || + this.fc.isConstExpr(varDecl.initializer); } if (firstDecl === varDecl) { if (isConst) { diff --git a/test/declaration_test.ts b/test/declaration_test.ts index 0bdc0ba..d57a855 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -28,8 +28,11 @@ describe('variables', () => { it('supports const', () => { // NB: const X = CONST_EXPR(1); is translated as deep-const, see tests in facade_converter_test. - expectTranslate('const A = 1, B = 2;').to.equal('final A = 1, B = 2;'); - expectTranslate('const A: number = 1;').to.equal('final num A = 1;'); + // Arbitrary expressions translate const ==> final... + expectTranslate('const A = 1 + 2;').to.equal('final A = 1 + 2;'); + // ... but literals are special cased to be deep const. + expectTranslate('const A = 1, B = 2;').to.equal('const A = 1, B = 2;'); + expectTranslate('const A: number = 1;').to.equal('const num A = 1;'); }); }); From 2752ef9d4e7ad9cc9945e651afc5870bc9ebf293 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 20:52:57 -0700 Subject: [PATCH 097/108] feat: report last location on crashes. --- lib/main.ts | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/main.ts b/lib/main.ts index 8e636c4..32d8475 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -282,25 +282,27 @@ export class Transpiler { visit(node: ts.Node) { this.output.addSourceMapping(node); - let comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart()); - if (comments) { - comments.forEach((c) => { - if (c.pos <= this.lastCommentIdx) return; - this.lastCommentIdx = c.pos; - let text = this.currentFile.text.substring(c.pos, c.end); - this.emitNoSpace('\n'); - this.emit(this.translateComment(text)); - if (c.hasTrailingNewLine) this.emitNoSpace('\n'); - }); - } + try { + let comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart()); + if (comments) { + comments.forEach((c) => { + if (c.pos <= this.lastCommentIdx) return; + this.lastCommentIdx = c.pos; + let text = this.currentFile.text.substring(c.pos, c.end); + this.emitNoSpace('\n'); + this.emit(this.translateComment(text)); + if (c.hasTrailingNewLine) this.emitNoSpace('\n'); + }); + } - for (let i = 0; i < this.transpilers.length; i++) { - if (this.transpilers[i].visitNode(node)) return; + for (let i = 0; i < this.transpilers.length; i++) { + if (this.transpilers[i].visitNode(node)) return; + } + this.reportError( + node, `Unsupported node type ${(ts).SyntaxKind[node.kind]}: ${node.getFullText()}`); + } catch (e) { + this.reportError(node, 'ts2dart crashed ' + e.stack); } - - this.reportError( - node, - 'Unsupported node type ' + (ts).SyntaxKind[node.kind] + ': ' + node.getFullText()); } private normalizeSlashes(path: string) { return path.replace(/\\/g, '/'); } From 764a50c6d1b3ea627c8c0a5088532cddb4e8bf99 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 20:54:29 -0700 Subject: [PATCH 098/108] chore: report right source for erroneous tests. The last entry in the array is the code under test for multi-file test cases. --- test/test_support.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_support.ts b/test/test_support.ts index 8b1d66b..33b036b 100644 --- a/test/test_support.ts +++ b/test/test_support.ts @@ -65,7 +65,8 @@ export function parseFiles(nameToContent: StringMap): [ts.Program, ts.CompilerHo if (program.getSyntacticDiagnostics().length > 0) { // Throw first error. let first = program.getSyntacticDiagnostics()[0]; - throw new Error(`${first.start}: ${first.messageText} in ${nameToContent[entryPoints[0]]}`); + let src = nameToContent[entryPoints[entryPoints.length - 1]]; + throw new Error(`${first.start}: ${first.messageText} in ${src}`); } return [program, compilerHost]; } From a832f102d558ce3be22d31506ad63c028e14ab54 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 20:56:02 -0700 Subject: [PATCH 099/108] feat: translate /* @ts2dart_Provider */ comments. These are used to mark object literals as providers that need to be translated to `new Provider(...)` in Dart. --- lib/facade_converter.ts | 72 ++++++++++++++++++++++++++++++++++- lib/literal.ts | 3 +- test/facade_converter_test.ts | 20 ++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index b4cc699..f7b7f99 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -12,6 +12,8 @@ type Set = { const FACADE_DEBUG = false; const DEFAULT_LIB_MARKER = '__ts2dart_default_lib'; +const PROVIDER_IMPORT_MARKER = '__ts2dart_has_provider_import'; +const TS2DART_PROVIDER_COMMENT = '@ts2dart_Provider'; function merge(...args: {[key: string]: any}[]): {[key: string]: any} { let returnObject: {[key: string]: any} = {}; @@ -78,6 +80,47 @@ export class FacadeConverter extends base.TranspilerBase { } } + /** + * To avoid strongly referencing the Provider class (which could bloat binary size), Angular 2 + * write providers as object literals. However the Dart transformers don't recognize this, so + * ts2dart translates the special syntax `/* @ts2dart_Provider * / {provide: Class, param1: ...}` + * into `const Provider(Class, param1: ...)`. + */ + maybeHandleProvider(ole: ts.ObjectLiteralExpression): boolean { + if (!this.hasMarkerComment(ole, TS2DART_PROVIDER_COMMENT)) return false; + let classParam: ts.Expression; + for (let e of ole.properties) { + if (e.kind !== ts.SyntaxKind.PropertyAssignment) { + this.reportError(e, TS2DART_PROVIDER_COMMENT + ' elements must be property assignments'); + return false; + } + if ('provide' === base.ident(e.name)) { + classParam = (e as ts.PropertyAssignment).initializer; + // Keep iterating to check all elements for PropertyAssignment. + } + } + if (!classParam) { + this.reportError(ole, 'missing provide: element'); + return false; + } + + this.emit('const Provider('); + this.visit(classParam); + if (ole.properties.length > 1) { + this.emit(','); + for (let i = 1; i < ole.properties.length; i++) { + let e = ole.properties[i]; + if (e.kind !== ts.SyntaxKind.PropertyAssignment) this.visit(e.name); + this.emit(base.ident(e.name)); + this.emit(':'); + this.visit((e as ts.PropertyAssignment).initializer); + if ((i + 1) < ole.properties.length) this.emit(','); + } + this.emit(')'); + } + return true; + } + maybeHandleCall(c: ts.CallExpression): boolean { if (!this.tc) return false; let {context, symbol} = this.getCallInformation(c); @@ -131,6 +174,29 @@ export class FacadeConverter extends base.TranspilerBase { } } + // Support for importing "Provider" in case /* @ts2dart_Provider */ comments are present. + if (n.kind === ts.SyntaxKind.ImportDeclaration) { + // See if there is already code importing 'Provider' from angular2/core. + let id = n; + if ((id.moduleSpecifier as ts.StringLiteral).text === 'angular2/core') { + if (id.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { + let ni = id.importClause.namedBindings as ts.NamedImports; + for (let nb of ni.elements) { + if (base.ident(nb.name) === 'Provider') { + emitted[PROVIDER_IMPORT_MARKER] = true; + break; + } + } + } + } + } + + if (!emitted[PROVIDER_IMPORT_MARKER] && this.hasMarkerComment(n, TS2DART_PROVIDER_COMMENT)) { + // if 'Provider' has not been imported yet, and there's a @ts2dart_Provider, add it. + this.emit(`import "package:angular2/core.dart" show Provider;`); + emitted[PROVIDER_IMPORT_MARKER] = true; + } + n.getChildren(sourceFile) .forEach((child: ts.Node) => this.emitImports(child, libraries, emitted, sourceFile)); } @@ -370,13 +436,15 @@ export class FacadeConverter extends base.TranspilerBase { base.ident((node).expression) === 'CONST_EXPR'; } - hasConstComment(node: ts.Node): boolean { + hasConstComment(node: ts.Node): boolean { return this.hasMarkerComment(node, '@ts2dart_const'); } + + private hasMarkerComment(node: ts.Node, markerText: string): boolean { let text = node.getFullText(); let comments = ts.getLeadingCommentRanges(text, 0); if (!comments) return false; for (let c of comments) { let commentText = text.substring(c.pos, c.end); - if (commentText.indexOf('@ts2dart_const') !== -1) { + if (commentText.indexOf(markerText) !== -1) { return true; } } diff --git a/lib/literal.ts b/lib/literal.ts index efe1b0b..b8095fa 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -57,8 +57,9 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.emit(']'); break; case ts.SyntaxKind.ObjectLiteralExpression: - if (this.shouldBeConst(node)) this.emit('const'); let ole = node; + if (this.fc.maybeHandleProvider(ole)) return true; + if (this.shouldBeConst(node)) this.emit('const'); this.handleReifiedMap(ole); this.emit('{'); this.visitList(ole.properties); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 0c26dd7..4a42147 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -444,3 +444,23 @@ var y = X.get({"a": 1}, "a");`); }); }); }); + +describe('@ts2dart_Provider', () => { + it('transforms expressions', () => { + expectWithTypes(` +var x = /* @ts2dart_Provider */ { + provide: SomeThing, useClass: XHRImpl, multi: true +};`).to.equal(`import "package:angular2/core.dart" show Provider; + +var x = const Provider(SomeThing, useClass: XHRImpl, multi: true);`); + }); + + it('does not add multiple imports', () => { + expectWithTypes(` +import {Provider} from 'angular2/core'; +var x = /* @ts2dart_Provider */ {provide: SomeThing, useClass: X};`) + .to.equal(`import "package:angular2/core.dart" show Provider; + +var x = const Provider(SomeThing, useClass: X);`); + }); +}); From e61af88a59b9ae0ae2ca078b5daa2f9658cf8d81 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 22:19:19 -0700 Subject: [PATCH 100/108] chore: fix integration test. TypeScript resolves files to absolute path names only when they are discovered through an import. To avoid that mess, resolve all paths before proceeding. Also port the remaining e2e test to use a tsconfig.json. --- gulpfile.js | 11 +++++------ lib/facade_converter.ts | 22 +++++++++++----------- lib/main.ts | 3 ++- test/e2e/helloworld.ts | 1 - test/e2e/tsconfig.json | 12 ++++++++++++ 5 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 test/e2e/tsconfig.json diff --git a/gulpfile.js b/gulpfile.js index d0d0eac..191db4e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -93,15 +93,14 @@ gulp.task('test.e2e', ['test.compile'], function(done) { var dir = (__dirname.replace(/\\/g, '/') + '/build/e2e'); if (fs.existsSync(dir)) fsx.removeSync(dir); fs.mkdirSync(dir); - fsx.copySync(__dirname + '/test/e2e', dir); - fsx.copySync(__dirname + '/typings', dir + '/typings'); + fsx.copySync(__dirname + '/test/e2e/pubspec.yaml', dir + '/pubspec.yaml'); // run node with a shell so we can wildcard all the .ts files - var cmd = 'node ../lib/main.js --translateBuiltins --basePath=. --destination=. ' + - '--typingsRoot=typings/ ' + - '*.ts angular2/src/facade/lang.d.ts typings/es6-promise/es6-promise.d.ts'; + var cmd = 'node build/lib/main.js --translateBuiltins --tsconfig test/e2e/tsconfig.json ' + + '--generateLibraryName=true ' + + 'test/e2e/*.ts'; // Paths must be relative to our source root, so run with cwd == dir. - spawn('sh', ['-c', cmd], {stdio: 'inherit', cwd: dir}).on('close', function(code, signal) { + spawn('sh', ['-c', cmd], {stdio: 'inherit'}).on('close', function(code, signal) { if (code > 0) { onError(new Error('Failed to transpile ' + testfile + '.ts')); } else { diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index f7b7f99..7891f58 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -89,16 +89,17 @@ export class FacadeConverter extends base.TranspilerBase { maybeHandleProvider(ole: ts.ObjectLiteralExpression): boolean { if (!this.hasMarkerComment(ole, TS2DART_PROVIDER_COMMENT)) return false; let classParam: ts.Expression; - for (let e of ole.properties) { + let remaining = ole.properties.filter((e) => { if (e.kind !== ts.SyntaxKind.PropertyAssignment) { this.reportError(e, TS2DART_PROVIDER_COMMENT + ' elements must be property assignments'); - return false; } if ('provide' === base.ident(e.name)) { classParam = (e as ts.PropertyAssignment).initializer; - // Keep iterating to check all elements for PropertyAssignment. + return false; } - } + return true; // include below. + }); + if (!classParam) { this.reportError(ole, 'missing provide: element'); return false; @@ -106,15 +107,15 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('const Provider('); this.visit(classParam); - if (ole.properties.length > 1) { + if (remaining.length > 0) { this.emit(','); - for (let i = 1; i < ole.properties.length; i++) { - let e = ole.properties[i]; + for (let i = 0; i < remaining.length; i++) { + let e = remaining[i]; if (e.kind !== ts.SyntaxKind.PropertyAssignment) this.visit(e.name); this.emit(base.ident(e.name)); this.emit(':'); this.visit((e as ts.PropertyAssignment).initializer); - if ((i + 1) < ole.properties.length) this.emit(','); + if ((i + 1) < remaining.length) this.emit(','); } this.emit(')'); } @@ -177,7 +178,7 @@ export class FacadeConverter extends base.TranspilerBase { // Support for importing "Provider" in case /* @ts2dart_Provider */ comments are present. if (n.kind === ts.SyntaxKind.ImportDeclaration) { // See if there is already code importing 'Provider' from angular2/core. - let id = n; + let id = n as ts.ImportDeclaration; if ((id.moduleSpecifier as ts.StringLiteral).text === 'angular2/core') { if (id.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { let ni = id.importClause.namedBindings as ts.NamedImports; @@ -358,8 +359,7 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - const canonicalFileName = - decl.getSourceFile().fileName.replace(/(\.d)?\.ts$/, '').replace(/(\.d)?\.ts$/, ''); + const canonicalFileName = decl.getSourceFile().fileName.replace(/(\.d)?\.ts$/, ''); let qname = this.tc.getFullyQualifiedName(symbol); // Some Qualified Names include their file name. Might be a bug in TypeScript, diff --git a/lib/main.ts b/lib/main.ts index 32d8475..2d08446 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -86,7 +86,7 @@ export class Transpiler { if (this.options.basePath) { this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath)); } - fileNames = fileNames.map((f) => this.normalizeSlashes(f)); + fileNames = fileNames.map((f) => this.normalizeSlashes(path.resolve(f))); let host: ts.CompilerHost; let compilerOpts: ts.CompilerOptions; @@ -112,6 +112,7 @@ export class Transpiler { host = this.createCompilerHost(); compilerOpts = this.getCompilerOptions(); } + if (this.options.basePath) this.options.basePath = path.resolve(this.options.basePath); if (this.options.basePath && destination === undefined) { throw new Error( diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index 0fc6f98..875eee0 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,5 +1,4 @@ /// -/// import t = require('test/test'); import {MyClass, MySubclass, SOME_ARRAY} from './lib'; diff --git a/test/e2e/tsconfig.json b/test/e2e/tsconfig.json new file mode 100644 index 0000000..0871692 --- /dev/null +++ b/test/e2e/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "baseUrl": ".", + "noEmit": true, + "noEmitOnError": true, + "rootDir": ".", + "outDir": "../../build/e2e", + "target": "ES6" + } +} From 7eec6e8a71f3c4c61a37989e3c1e995ac95e0c40 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Thu, 28 Apr 2016 22:21:37 -0700 Subject: [PATCH 101/108] rel: 0.9.9. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ac0d60..b1e2a1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.8", + "version": "0.9.9", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From b50823824dc8601c3b5258378a275a7bab988e45 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 30 Apr 2016 11:25:47 -0700 Subject: [PATCH 102/108] fix: support generic methods. Summary: Previously only worked for functions. Fixes #282. Reviewers: tbosch Reviewed By: tbosch Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D100 --- lib/facade_converter.ts | 6 +++++- test/function_test.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 7891f58..8e459a9 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -250,7 +250,11 @@ export class FacadeConverter extends base.TranspilerBase { if (symbol !== t.symbol) return false; // Check that the Type Parameter has been declared by a function declaration. - return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration); + return symbol.declarations.some( + // Constructors are handled separately. + d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration || + d.parent.kind === ts.SyntaxKind.MethodDeclaration || + d.parent.kind === ts.SyntaxKind.MethodSignature); } visitTypeName(typeName: ts.EntityName) { diff --git a/test/function_test.ts b/test/function_test.ts index 0d10d9f..4c3df81 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -118,6 +118,19 @@ describe('generic functions', () => { translateBuiltins: true }).to.equal(`List sort/*< T, U >*/(List xs) { return xs; +}`); + expectTranslate('function inGeneric(x: T, y: Y): T { return x; }', { + translateBuiltins: true + }).to.equal(`dynamic/*= T */ inGeneric/*< T, U >*/( + dynamic/*= T */ x, Y y) { + return x; +}`); + expectTranslate('class X { sort(xs: T[]): T[] { return xs; } }', { + translateBuiltins: true + }).to.equal(`class X { + List sort/*< T, U >*/(List xs) { + return xs; + } }`); }); it('replaces type usage sites, but not idents', () => { From 70caeff55dceed423be3fa725bfc84c79596bf59 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Sat, 30 Apr 2016 11:27:55 -0700 Subject: [PATCH 103/108] rel: 0.9.10. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1e2a1d..ce70e69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.9", + "version": "0.9.10", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "typings": "build/definitions/main.d.ts", From 6da6640622ebd84032615c230a8c96b0a46a0a53 Mon Sep 17 00:00:00 2001 From: Luis Vargas Date: Mon, 15 Aug 2016 20:53:30 -0400 Subject: [PATCH 104/108] Add ability to install globally and execute as command line app (#372) * Add ability to install globally and execute as command line app * reformat code * add showHelp method and upgrade test to 0.12.15+3 in pubspec.yaml * correct typo --- .gitignore | 1 + README.md | 5 +++++ lib/declaration.ts | 3 ++- lib/expression.ts | 3 ++- lib/facade_converter.ts | 8 +++++--- lib/literal.ts | 3 ++- lib/main.ts | 30 ++++++++++++++++++++++++++++++ lib/module.ts | 3 ++- lib/type.ts | 3 ++- package.json | 1 + test/call_test.ts | 2 +- test/declaration_test.ts | 2 +- test/decorator_test.ts | 2 +- test/e2e/pubspec.yaml | 2 +- test/expression_test.ts | 2 +- test/facade_converter_test.ts | 3 ++- test/function_test.ts | 2 +- test/literal_test.ts | 2 +- 18 files changed, 61 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 0810fe6..731fe64 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ node_modules # IDEs .idea/ +/ts2dart.iml diff --git a/README.md b/README.md index a134fb5..ef7886f 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ ts2dart is a TypeScript to Dart transpiler. It's mainly used to translate Angular 2 from TypeScript to Dart for its Dart user base. +## Usage + +- To install as Command Line Tool execute: `npm i -g ts2dart` +- Once installed you could run it doing: `ts2dart inputFile.ts` + ## Installation - execute `npm i` to install the dependencies, diff --git a/lib/declaration.ts b/lib/declaration.ts index c992c69..faa4ca8 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; -import {Transpiler} from './main'; import {FacadeConverter} from './facade_converter'; +import {Transpiler} from './main'; export default class DeclarationTranspiler extends base.TranspilerBase { constructor( diff --git a/lib/expression.ts b/lib/expression.ts index 5c42d68..5e34015 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; -import {Transpiler} from './main'; import {FacadeConverter} from './facade_converter'; +import {Transpiler} from './main'; export default class ExpressionTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 8e459a9..38add1d 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -1,6 +1,7 @@ -import * as base from './base'; -import * as ts from 'typescript'; import * as path from 'path'; +import * as ts from 'typescript'; + +import * as base from './base'; import {Transpiler} from './main'; type CallHandler = (c: ts.CallExpression, context: ts.Expression) => void; @@ -384,7 +385,8 @@ export class FacadeConverter extends base.TranspilerBase { private reportMissingType(n: ts.Node, ident: string) { this.reportError( - n, `Untyped property access to "${ident}" which could be ` + `a special ts2dart builtin. ` + + n, `Untyped property access to "${ident}" which could be ` + + `a special ts2dart builtin. ` + `Please add type declarations to disambiguate.`); } diff --git a/lib/literal.ts b/lib/literal.ts index b8095fa..219f0a7 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; -import {Transpiler} from './main'; import {FacadeConverter} from './facade_converter'; +import {Transpiler} from './main'; export default class LiteralTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } diff --git a/lib/main.ts b/lib/main.ts index 2d08446..33d925a 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -1,3 +1,5 @@ +#! /usr/bin/env node + require('source-map-support').install(); import {SourceMapGenerator} from 'source-map'; import * as fs from 'fs'; @@ -405,9 +407,37 @@ class Output { } } +function showHelp() { + console.log(` +Usage: ts2dart [input-files] [arguments] + + --help show this dialog + + --failFast Fail on the first error, do not collect multiple. Allows easier debugging + as stack traces lead directly to the offending line + + --generateLibraryName Whether to generate 'library a.b.c;' names from relative file paths. + + --generateSourceMap Whether to generate source maps. + + --tsconfig A tsconfig.json to use to configure TypeScript compilation. + + --basePath A base path to relativize absolute file paths against. This + is useful for library name generation (see above) and nicer + file names in error messages. + + --translateBuiltins Translate calls to builtins, i.e. seemlessly convert from \` Array\` to \` List\`, + and convert the corresponding methods. Requires type checking. + + --enforceUnderscoreConventions Enforce conventions of public/private keyword and underscore prefix +`); + process.exit(0); +} + // CLI entry point if (require.main === module) { let args = require('minimist')(process.argv.slice(2), {base: 'string'}); + if (args.help) showHelp(); try { let transpiler = new Transpiler(args); console.error('Transpiling', args._, 'to', args.destination); diff --git a/lib/module.ts b/lib/module.ts index 0ac177f..e55056a 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; -import {Transpiler} from './main'; import {FacadeConverter} from './facade_converter'; +import {Transpiler} from './main'; export default class ModuleTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibraryName: boolean) { diff --git a/lib/type.ts b/lib/type.ts index fa15a61..d558d5e 100644 --- a/lib/type.ts +++ b/lib/type.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; -import {Transpiler} from './main'; import {FacadeConverter} from './facade_converter'; +import {Transpiler} from './main'; export default class TypeTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } diff --git a/package.json b/package.json index ce70e69..c7aa73c 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.9.10", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", + "bin": "build/lib/main.js", "typings": "build/definitions/main.d.ts", "directories": { "test": "test" diff --git a/test/call_test.ts b/test/call_test.ts index 91b1518..33fbbc6 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('calls', () => { it('translates destructuring parameters', () => { diff --git a/test/declaration_test.ts b/test/declaration_test.ts index d57a855..12ee780 100644 --- a/test/declaration_test.ts +++ b/test/declaration_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('variables', () => { it('should print variable declaration with initializer', diff --git a/test/decorator_test.ts b/test/decorator_test.ts index 72e0086..27c5229 100644 --- a/test/decorator_test.ts +++ b/test/decorator_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('decorators', () => { it('translates plain decorators', () => { diff --git a/test/e2e/pubspec.yaml b/test/e2e/pubspec.yaml index 0f601eb..d70d897 100644 --- a/test/e2e/pubspec.yaml +++ b/test/e2e/pubspec.yaml @@ -2,4 +2,4 @@ name: e2e description: Transpiled end-to-end tests for ts2dart. dependencies: - test: 0.12.13 + test: 0.12.15+3 diff --git a/test/expression_test.ts b/test/expression_test.ts index 85eec7b..a8b63a8 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; function expectTranslates(cases: any) { for (let tsCode of Object.keys(cases)) { diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 4a42147..b611a0e 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,5 +1,6 @@ /// -import {expectTranslate, FAKE_MAIN, translateSource} from './test_support'; +import {FAKE_MAIN, expectTranslate, translateSource} from './test_support'; + import chai = require('chai'); function getSources(str: string): {[k: string]: string} { diff --git a/test/function_test.ts b/test/function_test.ts index 4c3df81..f188ebc 100644 --- a/test/function_test.ts +++ b/test/function_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('functions', () => { it('supports declarations', () => { expectTranslate('function x() {}').to.equal('x() {}'); }); diff --git a/test/literal_test.ts b/test/literal_test.ts index fe17250..9203340 100644 --- a/test/literal_test.ts +++ b/test/literal_test.ts @@ -1,5 +1,5 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('literals', () => { it('translates string literals', () => { From 67e6cd0f32a95818988ab8f30dbbfa3654cb087f Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 15 Aug 2016 17:54:24 -0700 Subject: [PATCH 105/108] rel: 0.9.11. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c7aa73c..4d678ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts2dart", - "version": "0.9.10", + "version": "0.9.11", "description": "Transpile TypeScript code to Dart", "main": "build/lib/main.js", "bin": "build/lib/main.js", From f19eb49a7e90dbc1e567374964a596fccce5c2a6 Mon Sep 17 00:00:00 2001 From: Jumper Chen Date: Tue, 29 Nov 2016 18:30:21 +0800 Subject: [PATCH 106/108] init for keikai project --- lib/base.ts | 1 + lib/call.ts | 12 +++++++++++- lib/declaration.ts | 31 +++++++++++++++++++++++++++++-- lib/expression.ts | 22 +++++++++++++++------- lib/facade_converter.ts | 32 ++++++++++++++++++++++++++++---- lib/literal.ts | 8 ++++---- lib/main.ts | 30 +++++++++++++++++++++++++----- lib/module.ts | 4 ++-- package.json | 1 + 9 files changed, 116 insertions(+), 25 deletions(-) diff --git a/lib/base.ts b/lib/base.ts index 5129151..f63ad39 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -19,6 +19,7 @@ export class TranspilerBase { visit(n: ts.Node) { this.transpiler.visit(n); } emit(s: string) { this.transpiler.emit(s); } + emitBefore(s: string, search: string) { this.transpiler.emitBefore(s, search); } emitNoSpace(s: string) { this.transpiler.emitNoSpace(s); } reportError(n: ts.Node, message: string) { this.transpiler.reportError(n, message); } diff --git a/lib/call.ts b/lib/call.ts index 7287083..5f350d1 100644 --- a/lib/call.ts +++ b/lib/call.ts @@ -62,7 +62,17 @@ export default class CallTranspiler extends base.TranspilerBase { } this.emit('('); if (c.arguments && !this.handleNamedParamsCall(c)) { - this.visitList(c.arguments); + if ((c).expression.text == 'RegExp') { + if (c.arguments.length > 1) { + if ((c.arguments[1]).text == 'i') { + this.visit(c.arguments[0]); + this.emit(', caseSensitive: false)'); + return; + } + } + } else { + this.visitList(c.arguments); + } } this.emit(')'); } diff --git a/lib/declaration.ts b/lib/declaration.ts index faa4ca8..ecd51f0 100644 --- a/lib/declaration.ts +++ b/lib/declaration.ts @@ -209,14 +209,37 @@ export default class DeclarationTranspiler extends base.TranspilerBase { // Abstract classes are handled in `case ts.SyntaxKind.ClassDeclaration` above. break; case ts.SyntaxKind.PrivateKeyword: + this.emit('/*private*/'); // no-op, handled through '_' naming convention in Dart. break; case ts.SyntaxKind.PublicKeyword: - // Handled in `visitDeclarationMetadata` below. + this.emit('/*public*/'); break; case ts.SyntaxKind.ProtectedKeyword: + this.emit('/*protected*/'); + break; + case ts.SyntaxKind.AwaitExpression: // Handled in `visitDeclarationMetadata` below. + this.emit('await'); + this.visit((node).expression); + break; + case ts.SyntaxKind.AsyncKeyword: + (this).__async = true; break; + case ts.SyntaxKind.ObjectBindingPattern: + this.emit('/*'); + const n: any = node; + let first: boolean = true; + for (var e of n.elements) { + if (!first) { + this.emit(','); + } + first = false; + this.emit(e.name.text); + } + this.emit('*/'); + break; + default: return false; @@ -333,6 +356,10 @@ export default class DeclarationTranspiler extends base.TranspilerBase { } this.emit(')'); + if ((this)['__async']) { + this.emit('async'); + (this)['__async'] = false; + } } /** @@ -432,7 +459,7 @@ export default class DeclarationTranspiler extends base.TranspilerBase { this.visitEachIfPresent(decl.modifiers); if (this.hasFlag(decl.modifiers, ts.NodeFlags.Protected)) { - this.reportError(decl, 'protected declarations are unsupported'); + // this.reportError(decl, 'protected declarations are unsupported'); return; } if (!this.enforceUnderscoreConventions) return; diff --git a/lib/expression.ts b/lib/expression.ts index 5e34015..5f49d2d 100644 --- a/lib/expression.ts +++ b/lib/expression.ts @@ -16,12 +16,16 @@ export default class ExpressionTranspiler extends base.TranspilerBase { switch (operatorKind) { case ts.SyntaxKind.EqualsEqualsEqualsToken: case ts.SyntaxKind.ExclamationEqualsEqualsToken: - if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) this.emit('!'); - this.emit('identical ('); + // this.emit('identical ('); this.visit(binExpr.left); - this.emit(','); + + if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) { + this.emit('!='); + } else { + this.emit('=='); + } this.visit(binExpr.right); - this.emit(')'); + // this.emit(')'); break; case ts.SyntaxKind.CaretToken: case ts.SyntaxKind.BarToken: @@ -88,13 +92,17 @@ export default class ExpressionTranspiler extends base.TranspilerBase { this.visit(conditional.whenFalse); break; case ts.SyntaxKind.DeleteExpression: - this.reportError(node, 'delete operator is unsupported'); + this.emit('/*delete*/'); + // this.reportError(node, 'delete operator is unsupported'); break; case ts.SyntaxKind.VoidExpression: - this.reportError(node, 'void operator is unsupported'); + this.emit('/*void*/'); + // this.reportError(node, 'void operator is unsupported'); break; case ts.SyntaxKind.TypeOfExpression: - this.reportError(node, 'typeof operator is unsupported'); + this.emit('/*typeof*/'); + this.visit((node).expression); + // this.reportError(node, 'typeof operator is unsupported'); break; case ts.SyntaxKind.ParenthesizedExpression: diff --git a/lib/facade_converter.ts b/lib/facade_converter.ts index 38add1d..cd4fcc4 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -140,7 +140,9 @@ export class FacadeConverter extends base.TranspilerBase { if (!this.candidateProperties.hasOwnProperty(ident)) return false; let symbol = this.tc.getSymbolAtLocation(pa.name); if (!symbol) { - this.reportMissingType(pa, ident); + if (!this.stdlibTypeReplacements[ident]) { + this.reportMissingType(pa, ident); + } return false; } @@ -157,7 +159,8 @@ export class FacadeConverter extends base.TranspilerBase { 'KeyboardEvent': 'dart:html', 'Uint8Array': 'dart:typed_arrays', 'ArrayBuffer': 'dart:typed_arrays', - 'Promise': 'dart:async', + 'Promise': 'dart:async', + 'HttpRequest.getString': 'dart:html', }; let emitted: Set = {}; this.emitImports(sourceFile, libraries, emitted, sourceFile); @@ -170,7 +173,7 @@ export class FacadeConverter extends base.TranspilerBase { if (libraries.hasOwnProperty(type)) { let toEmit = libraries[type]; if (!emitted[toEmit]) { - this.emit(`import "${toEmit}";`); + this.emit(`import '${toEmit}';`); emitted[toEmit] = true; } } @@ -276,9 +279,22 @@ export class FacadeConverter extends base.TranspilerBase { if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { let symbol = this.tc.getSymbolAtLocation(typeName); if (!symbol) { - this.reportMissingType(typeName, ident); + if (!this.stdlibTypeReplacements[ident]) { + this.reportMissingType(typeName, ident); + } else { + this.emit(this.stdlibTypeReplacements[ident]); + if (ident == 'require') { + this.emitBefore('import \'dart:html\';', 'import'); + } else if (ident == 'Math') { + this.emitBefore('import \'dart:math\' as Math;', 'import'); + } + } return; } + if (this.stdlibTypeReplacements[ident]) { + this.emit(this.stdlibTypeReplacements[ident]); + return; + } let fileAndName = this.getFileAndName(typeName, symbol); if (fileAndName) { let fileSubs = this.tsToDartTypeNames[fileAndName.fileName]; @@ -476,6 +492,14 @@ export class FacadeConverter extends base.TranspilerBase { 'Uint8Array': 'Uint8List', 'ArrayBuffer': 'ByteBuffer', 'Promise': 'Future', + 'undefined': 'null', + 'replace': 'replaceFirst', + 'require': 'HttpRequest.getString', + 'then': 'then', + 'Object': 'Map', + 'parseFloat': 'double.parse', + 'parseInt': 'int.parse', + 'Math': 'Math', // Dart has two different incompatible DOM APIs // https://github.com/angular/angular/issues/2770 diff --git a/lib/literal.ts b/lib/literal.ts index 219f0a7..64e37c4 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -70,9 +70,9 @@ export default class LiteralTranspiler extends base.TranspilerBase { let propAssign = node; if (propAssign.name.kind === ts.SyntaxKind.Identifier) { // Dart identifiers in Map literals need quoting. - this.emitNoSpace(' "'); + this.emitNoSpace(' \''); this.emitNoSpace((propAssign.name).text); - this.emitNoSpace('"'); + this.emitNoSpace('\''); } else { this.visit(propAssign.name); } @@ -81,9 +81,9 @@ export default class LiteralTranspiler extends base.TranspilerBase { break; case ts.SyntaxKind.ShorthandPropertyAssignment: let shorthand = node; - this.emitNoSpace(' "'); + this.emitNoSpace(' \''); this.emitNoSpace(shorthand.name.text); - this.emitNoSpace('"'); + this.emitNoSpace('\''); this.emit(':'); this.visit(shorthand.name); break; diff --git a/lib/main.ts b/lib/main.ts index 33d925a..f85096a 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -137,8 +137,12 @@ export class Transpiler { .filter((sourceFile: ts.SourceFile) => !sourceFile.fileName.match(/\.d\.ts$/)) .forEach((f: ts.SourceFile) => { let dartCode = this.translate(f); - let outputFile = this.getOutputPath(f.fileName, destinationRoot); + let outputFile = this.getOutputPath(f.fileName, destinationRoot) + .replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}); + if (outputFile.charAt(0) == '_') + outputFile = outputFile.substring(1); mkdirP(path.dirname(outputFile)); + console.log(dartCode); fs.writeFileSync(outputFile, dartCode); }); this.checkForErrors(program); @@ -270,6 +274,7 @@ export class Transpiler { } emit(s: string) { this.output.emit(s); } + emitBefore(s: string, search: string) { this.output.emitBefore(s, search); } emitNoSpace(s: string) { this.output.emitNoSpace(s); } reportError(n: ts.Node, message: string) { @@ -366,10 +371,25 @@ class Output { } } - emit(str: string) { - this.emitNoSpace(' '); - this.emitNoSpace(str); - } + emit(str: string) { + this.emitNoSpace(' '); + this.emitNoSpace(str); + } + + emitBefore(str: string, search: string) { + const idx:number = this.result.indexOf(search); + if (idx < 0) return; + str = str + ' '; + this.result = this.result.substring(0, idx) + str + this.result.substring(idx); + for (let i = 0; i < str.length; i++) { + if (str[i] === '\n') { + this.line++; + this.column = 0; + } else { + this.column++; + } + } + } emitNoSpace(str: string) { this.result += str; diff --git a/lib/module.ts b/lib/module.ts index e55056a..f046aa5 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -121,10 +121,10 @@ export default class ModuleTranspiler extends base.TranspilerBase { let text = moduleName.text; if (text.match(/^\.\//)) { // Strip './' to be more Dart-idiomatic. - text = text.substring(2); + text = text.substring(2).replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}).substring(1); } else if (!text.match(/^\.\.\//)) { // Replace '@angular' with 'angular2' for Dart. - text = text.replace(/^@angular\//, 'angular2/'); + text = text.replace(/^@keikai\//, 'keikai/'); // Unprefixed/absolute imports are package imports. text = 'package:' + text; } diff --git a/package.json b/package.json index 4d678ea..a161e9c 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "temp": "^0.8.1", "tsd": "^0.6.0", "tslint": "^3.7.1", + "typescript": "^2.0.0", "which": "^1.0.9" }, "scripts": { From 3ac0315a8dbd9a29d2083219b0ef986f1d0978ac Mon Sep 17 00:00:00 2001 From: Jumper Chen Date: Tue, 29 Nov 2016 18:36:34 +0800 Subject: [PATCH 107/108] add build/*.js --- .gitignore | 1 - build/definitions/base.d.ts | 31 + build/definitions/call.d.ts | 28 + build/definitions/declaration.d.ts | 29 + build/definitions/expression.d.ts | 10 + build/definitions/facade_converter.d.ts | 69 ++ build/definitions/literal.d.ts | 13 + build/definitions/main.d.ts | 68 ++ build/definitions/mkdirp.d.ts | 1 + build/definitions/module.d.ts | 16 + build/definitions/statement.d.ts | 7 + build/definitions/type.d.ts | 10 + build/lib/base.js | 108 +++ build/lib/base.js.map | 1 + build/lib/call.js | 243 +++++++ build/lib/call.js.map | 1 + build/lib/declaration.js | 561 +++++++++++++++ build/lib/declaration.js.map | 1 + build/lib/expression.js | 163 +++++ build/lib/expression.js.map | 1 + build/lib/facade_converter.js | 871 ++++++++++++++++++++++++ build/lib/facade_converter.js.map | 1 + build/lib/literal.js | 180 +++++ build/lib/literal.js.map | 1 + build/lib/main.js | 391 +++++++++++ build/lib/main.js.map | 1 + build/lib/mkdirp.js | 20 + build/lib/mkdirp.js.map | 1 + build/lib/module.js | 176 +++++ build/lib/module.js.map | 1 + build/lib/statement.js | 186 +++++ build/lib/statement.js.map | 1 + build/lib/type.js | 119 ++++ build/lib/type.js.map | 1 + 34 files changed, 3311 insertions(+), 1 deletion(-) create mode 100644 build/definitions/base.d.ts create mode 100644 build/definitions/call.d.ts create mode 100644 build/definitions/declaration.d.ts create mode 100644 build/definitions/expression.d.ts create mode 100644 build/definitions/facade_converter.d.ts create mode 100644 build/definitions/literal.d.ts create mode 100644 build/definitions/main.d.ts create mode 100644 build/definitions/mkdirp.d.ts create mode 100644 build/definitions/module.d.ts create mode 100644 build/definitions/statement.d.ts create mode 100644 build/definitions/type.d.ts create mode 100644 build/lib/base.js create mode 100644 build/lib/base.js.map create mode 100644 build/lib/call.js create mode 100644 build/lib/call.js.map create mode 100644 build/lib/declaration.js create mode 100644 build/lib/declaration.js.map create mode 100644 build/lib/expression.js create mode 100644 build/lib/expression.js.map create mode 100644 build/lib/facade_converter.js create mode 100644 build/lib/facade_converter.js.map create mode 100644 build/lib/literal.js create mode 100644 build/lib/literal.js.map create mode 100755 build/lib/main.js create mode 100644 build/lib/main.js.map create mode 100644 build/lib/mkdirp.js create mode 100644 build/lib/mkdirp.js.map create mode 100644 build/lib/module.js create mode 100644 build/lib/module.js.map create mode 100644 build/lib/statement.js create mode 100644 build/lib/statement.js.map create mode 100644 build/lib/type.js create mode 100644 build/lib/type.js.map diff --git a/.gitignore b/.gitignore index 731fe64..8730bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Compiled JS -build # Logs logs diff --git a/build/definitions/base.d.ts b/build/definitions/base.d.ts new file mode 100644 index 0000000..07666cc --- /dev/null +++ b/build/definitions/base.d.ts @@ -0,0 +1,31 @@ +import * as ts from 'typescript'; +import { Transpiler } from './main'; +export declare type ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration; +export declare function ident(n: ts.Node): string; +export declare class TranspilerBase { + private transpiler; + private idCounter; + constructor(transpiler: Transpiler); + visit(n: ts.Node): void; + emit(s: string): void; + emitBefore(s: string, search: string): void; + emitNoSpace(s: string): void; + reportError(n: ts.Node, message: string): void; + visitNode(n: ts.Node): boolean; + visitEach(nodes: ts.Node[]): void; + visitEachIfPresent(nodes?: ts.Node[]): void; + visitList(nodes: ts.Node[], separator?: string): void; + uniqueId(name: string): string; + assert(c: ts.Node, condition: boolean, reason: string): void; + getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node; + hasAncestor(n: ts.Node, kind: ts.SyntaxKind): boolean; + hasAnnotation(decorators: ts.NodeArray, name: string): boolean; + hasFlag(n: { + flags: number; + }, flag: ts.NodeFlags): boolean; + maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode]; + getRelativeFileName(fileName: string): string; + maybeVisitTypeArguments(n: { + typeArguments?: ts.NodeArray; + }): void; +} diff --git a/build/definitions/call.d.ts b/build/definitions/call.d.ts new file mode 100644 index 0000000..bfafb7f --- /dev/null +++ b/build/definitions/call.d.ts @@ -0,0 +1,28 @@ +import ts = require('typescript'); +import base = require('./base'); +import ts2dart = require('./main'); +import { FacadeConverter } from './facade_converter'; +export default class CallTranspiler extends base.TranspilerBase { + private fc; + constructor(tr: ts2dart.Transpiler, fc: FacadeConverter); + visitNode(node: ts.Node): boolean; + private visitCall(c); + private handleNamedParamsCall(c); + /** + * Handles constructor initializer lists and bodies. + * + *

Dart's super() ctor calls have to be moved to the constructors initializer list, and `const` + * constructors must be completely empty, only assigning into fields through the initializer list. + * The code below finds super() calls and handles const constructors, marked with the special + * `@CONST` annotation on the class. + * + *

Not emitting super() calls when traversing the ctor body is handled by maybeHandleSuperCall + * below. + */ + private visitConstructorBody(ctor); + /** + * Checks whether `callExpr` is a super() call that should be ignored because it was already + * handled by `maybeEmitSuperInitializer` above. + */ + private maybeHandleSuperCall(callExpr); +} diff --git a/build/definitions/declaration.d.ts b/build/definitions/declaration.d.ts new file mode 100644 index 0000000..d821ac2 --- /dev/null +++ b/build/definitions/declaration.d.ts @@ -0,0 +1,29 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { FacadeConverter } from './facade_converter'; +import { Transpiler } from './main'; +export default class DeclarationTranspiler extends base.TranspilerBase { + private fc; + private enforceUnderscoreConventions; + constructor(tr: Transpiler, fc: FacadeConverter, enforceUnderscoreConventions: boolean); + visitNode(node: ts.Node): boolean; + private visitVariableDeclarationType(varDecl); + private visitFunctionLike(fn, accessor?); + private visitParameters(parameters); + /** + * Visit a property declaration. + * In the special case of property parameters in a constructor, we also allow a parameter to be + * emitted as a property. + */ + private visitProperty(decl, isParameter?); + private visitClassLike(keyword, decl); + private visitDecorators(decorators); + private visitDeclarationMetadata(decl); + private visitNamedParameter(paramDecl); + private getInitializers(paramDecl); + /** + * Handles a function typedef-like interface, i.e. an interface that only declares a single + * call signature, by translating to a Dart `typedef`. + */ + private visitFunctionTypedefInterface(name, signature, typeParameters); +} diff --git a/build/definitions/expression.d.ts b/build/definitions/expression.d.ts new file mode 100644 index 0000000..eeb43a7 --- /dev/null +++ b/build/definitions/expression.d.ts @@ -0,0 +1,10 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { FacadeConverter } from './facade_converter'; +import { Transpiler } from './main'; +export default class ExpressionTranspiler extends base.TranspilerBase { + private fc; + constructor(tr: Transpiler, fc: FacadeConverter); + visitNode(node: ts.Node): boolean; + visitAndWrapAsInt(n: ts.Expression): void; +} diff --git a/build/definitions/facade_converter.d.ts b/build/definitions/facade_converter.d.ts new file mode 100644 index 0000000..3c94e37 --- /dev/null +++ b/build/definitions/facade_converter.d.ts @@ -0,0 +1,69 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { Transpiler } from './main'; +export declare class FacadeConverter extends base.TranspilerBase { + private tc; + private defaultLibLocation; + private candidateProperties; + private candidateTypes; + private genericMethodDeclDepth; + constructor(transpiler: Transpiler); + initializeTypeBasedConversion(tc: ts.TypeChecker, opts: ts.CompilerOptions, host: ts.CompilerHost): void; + private extractPropertyNames(m, candidates); + private resolveModuleNames(opts, host, m); + /** + * To avoid strongly referencing the Provider class (which could bloat binary size), Angular 2 + * write providers as object literals. However the Dart transformers don't recognize this, so + * ts2dart translates the special syntax `/* @ts2dart_Provider * / {provide: Class, param1: ...}` + * into `const Provider(Class, param1: ...)`. + */ + maybeHandleProvider(ole: ts.ObjectLiteralExpression): boolean; + maybeHandleCall(c: ts.CallExpression): boolean; + handlePropertyAccess(pa: ts.PropertyAccessExpression): boolean; + /** + * Searches for type references that require extra imports and emits the imports as necessary. + */ + emitExtraImports(sourceFile: ts.SourceFile): void; + private emitImports(n, libraries, emitted, sourceFile); + pushTypeParameterNames(n: ts.FunctionLikeDeclaration): void; + popTypeParameterNames(n: ts.FunctionLikeDeclaration): void; + resolvePropertyTypes(tn: ts.TypeNode): ts.Map; + /** + * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate + * generic methods in Dart. ts2dart has to hack around this and keep track of which type names + * in the current scope are actually DDC type parameters and need to be emitted in comments. + * + * TODO(martinprobst): Remove this once the DDC hack has made it into Dart proper. + */ + private isGenericMethodTypeParameterName(name); + visitTypeName(typeName: ts.EntityName): void; + shouldEmitNew(c: ts.CallExpression): boolean; + private getCallInformation(c); + private getHandler(n, symbol, m); + private getFileAndName(n, originalSymbol); + private isNamedDefaultLibType(node, qname); + private reportMissingType(n, ident); + private static DECLARATIONS; + isInsideConstExpr(node: ts.Node): boolean; + isConstClass(decl: base.ClassLike): boolean; + /** + * isConstExpr returns true if the passed in expression itself is a const expression. const + * expressions are marked by the special comment @ts2dart_const (expr), or by the special + * function call CONST_EXPR. + */ + isConstExpr(node: ts.Node): boolean; + hasConstComment(node: ts.Node): boolean; + private hasMarkerComment(node, markerText); + private emitMethodCall(name, args?); + private emitCall(name, args?); + private stdlibTypeReplacements; + private tsToDartTypeNames; + private es6Promises; + private es6Collections; + private stdlibHandlers; + private callHandlerReplaceNew; + private callHandlers; + private es6CollectionsProp; + private es6PromisesProp; + private propertyHandlers; +} diff --git a/build/definitions/literal.d.ts b/build/definitions/literal.d.ts new file mode 100644 index 0000000..e03d9d4 --- /dev/null +++ b/build/definitions/literal.d.ts @@ -0,0 +1,13 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { FacadeConverter } from './facade_converter'; +import { Transpiler } from './main'; +export default class LiteralTranspiler extends base.TranspilerBase { + private fc; + constructor(tr: Transpiler, fc: FacadeConverter); + visitNode(node: ts.Node): boolean; + private shouldBeConst(n); + private escapeTextForTemplateString(n); + private handleReifiedArray(node); + private handleReifiedMap(node); +} diff --git a/build/definitions/main.d.ts b/build/definitions/main.d.ts new file mode 100644 index 0000000..be682fb --- /dev/null +++ b/build/definitions/main.d.ts @@ -0,0 +1,68 @@ +import * as ts from 'typescript'; +export interface TranspilerOptions { + /** + * Fail on the first error, do not collect multiple. Allows easier debugging as stack traces lead + * directly to the offending line. + */ + failFast?: boolean; + /** Whether to generate 'library a.b.c;' names from relative file paths. */ + generateLibraryName?: boolean; + /** Whether to generate source maps. */ + generateSourceMap?: boolean; + /** A tsconfig.json to use to configure TypeScript compilation. */ + tsconfig?: string; + /** + * A base path to relativize absolute file paths against. This is useful for library name + * generation (see above) and nicer file names in error messages. + */ + basePath?: string; + /** + * Translate calls to builtins, i.e. seemlessly convert from `Array` to `List`, and convert the + * corresponding methods. Requires type checking. + */ + translateBuiltins?: boolean; + /** + * Enforce conventions of public/private keyword and underscore prefix + */ + enforceUnderscoreConventions?: boolean; +} +export declare const COMPILER_OPTIONS: ts.CompilerOptions; +export declare class Transpiler { + private options; + private output; + private currentFile; + private lastCommentIdx; + private errors; + private transpilers; + private fc; + constructor(options?: TranspilerOptions); + /** + * Transpiles the given files to Dart. + * @param fileNames The input files. + * @param destination Location to write files to. Creates files next to their sources if absent. + */ + transpile(fileNames: string[], destination?: string): void; + translateProgram(program: ts.Program, host: ts.CompilerHost): { + [path: string]: string; + }; + private getCompilerOptions(); + private createCompilerHost(); + getOutputPath(filePath: string, destinationRoot: string): string; + private translate(sourceFile); + private formatCode(code, context); + private checkForErrors(program); + private diagnosticToString(diagnostic); + /** + * Returns `filePath`, relativized to the program's `basePath`. + * @param filePath path to relativize. + */ + getRelativeFileName(filePath: string): string; + emit(s: string): void; + emitBefore(s: string, search: string): void; + emitNoSpace(s: string): void; + reportError(n: ts.Node, message: string): void; + visit(node: ts.Node): void; + private normalizeSlashes(path); + private translateComment(comment); +} +export declare function getModuleResolver(compilerHost: ts.CompilerHost): (moduleNames: string[], containingFile: string) => ts.ResolvedModule[]; diff --git a/build/definitions/mkdirp.d.ts b/build/definitions/mkdirp.d.ts new file mode 100644 index 0000000..bf2f2a2 --- /dev/null +++ b/build/definitions/mkdirp.d.ts @@ -0,0 +1 @@ +export default function mkdirP(p: string): void; diff --git a/build/definitions/module.d.ts b/build/definitions/module.d.ts new file mode 100644 index 0000000..d9bbda2 --- /dev/null +++ b/build/definitions/module.d.ts @@ -0,0 +1,16 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { FacadeConverter } from './facade_converter'; +import { Transpiler } from './main'; +export default class ModuleTranspiler extends base.TranspilerBase { + private fc; + private generateLibraryName; + constructor(tr: Transpiler, fc: FacadeConverter, generateLibraryName: boolean); + visitNode(node: ts.Node): boolean; + private static isIgnoredImport(e); + private visitExternalModuleReferenceExpr(expr); + private isEmptyImport(n); + private filterImports(ns); + private static DART_RESERVED_WORDS; + getLibraryName(fileName: string): string; +} diff --git a/build/definitions/statement.d.ts b/build/definitions/statement.d.ts new file mode 100644 index 0000000..753f3bb --- /dev/null +++ b/build/definitions/statement.d.ts @@ -0,0 +1,7 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { Transpiler } from './main'; +export default class StatementTranspiler extends base.TranspilerBase { + constructor(tr: Transpiler); + visitNode(node: ts.Node): boolean; +} diff --git a/build/definitions/type.d.ts b/build/definitions/type.d.ts new file mode 100644 index 0000000..25df739 --- /dev/null +++ b/build/definitions/type.d.ts @@ -0,0 +1,10 @@ +import * as ts from 'typescript'; +import * as base from './base'; +import { FacadeConverter } from './facade_converter'; +import { Transpiler } from './main'; +export default class TypeTranspiler extends base.TranspilerBase { + private fc; + constructor(tr: Transpiler, fc: FacadeConverter); + visitNode(node: ts.Node): boolean; + isReifiedTypeLiteral(node: ts.TypeAssertion): boolean; +} diff --git a/build/lib/base.js b/build/lib/base.js new file mode 100644 index 0000000..07cbf3f --- /dev/null +++ b/build/lib/base.js @@ -0,0 +1,108 @@ +"use strict"; +var ts = require('typescript'); +function ident(n) { + if (n.kind === ts.SyntaxKind.Identifier) + return n.text; + if (n.kind === ts.SyntaxKind.QualifiedName) { + var qname = n; + var leftName = ident(qname.left); + if (leftName) + return leftName + '.' + ident(qname.right); + } + return null; +} +exports.ident = ident; +var TranspilerBase = (function () { + function TranspilerBase(transpiler) { + this.transpiler = transpiler; + this.idCounter = 0; + } + TranspilerBase.prototype.visit = function (n) { this.transpiler.visit(n); }; + TranspilerBase.prototype.emit = function (s) { this.transpiler.emit(s); }; + TranspilerBase.prototype.emitBefore = function (s, search) { this.transpiler.emitBefore(s, search); }; + TranspilerBase.prototype.emitNoSpace = function (s) { this.transpiler.emitNoSpace(s); }; + TranspilerBase.prototype.reportError = function (n, message) { this.transpiler.reportError(n, message); }; + TranspilerBase.prototype.visitNode = function (n) { throw new Error('not implemented'); }; + TranspilerBase.prototype.visitEach = function (nodes) { + var _this = this; + nodes.forEach(function (n) { return _this.visit(n); }); + }; + TranspilerBase.prototype.visitEachIfPresent = function (nodes) { + if (nodes) + this.visitEach(nodes); + }; + TranspilerBase.prototype.visitList = function (nodes, separator) { + if (separator === void 0) { separator = ','; } + for (var i = 0; i < nodes.length; i++) { + this.visit(nodes[i]); + if (i < nodes.length - 1) + this.emit(separator); + } + }; + TranspilerBase.prototype.uniqueId = function (name) { + var id = this.idCounter++; + return "_" + name + "$$ts2dart$" + id; + }; + TranspilerBase.prototype.assert = function (c, condition, reason) { + if (!condition) { + this.reportError(c, reason); + throw new Error(reason); + } + }; + TranspilerBase.prototype.getAncestor = function (n, kind) { + for (var parent_1 = n; parent_1; parent_1 = parent_1.parent) { + if (parent_1.kind === kind) + return parent_1; + } + return null; + }; + TranspilerBase.prototype.hasAncestor = function (n, kind) { return !!this.getAncestor(n, kind); }; + TranspilerBase.prototype.hasAnnotation = function (decorators, name) { + if (!decorators) + return false; + return decorators.some(function (d) { + var decName = ident(d.expression); + if (decName === name) + return true; + if (d.expression.kind !== ts.SyntaxKind.CallExpression) + return false; + var callExpr = d.expression; + decName = ident(callExpr.expression); + return decName === name; + }); + }; + TranspilerBase.prototype.hasFlag = function (n, flag) { + return n && (n.flags & flag) !== 0 || false; + }; + TranspilerBase.prototype.maybeDestructureIndexType = function (node) { + var members = node.members; + if (members.length !== 1 || members[0].kind !== ts.SyntaxKind.IndexSignature) { + return null; + } + var indexSig = (members[0]); + if (indexSig.parameters.length > 1) { + this.reportError(indexSig, 'Expected an index signature to have a single parameter'); + } + return [indexSig.parameters[0].type, indexSig.type]; + }; + TranspilerBase.prototype.getRelativeFileName = function (fileName) { + return this.transpiler.getRelativeFileName(fileName); + }; + TranspilerBase.prototype.maybeVisitTypeArguments = function (n) { + if (n.typeArguments) { + // If it's a single type argument ``, ignore it and emit nothing. + // This is particularly useful for `Promise`, see + // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639 + if (n.typeArguments.length === 1 && n.typeArguments[0].kind === ts.SyntaxKind.VoidKeyword) { + return; + } + this.emitNoSpace('<'); + this.visitList(n.typeArguments); + this.emit('>'); + } + }; + return TranspilerBase; +}()); +exports.TranspilerBase = TranspilerBase; + +//# sourceMappingURL=base.js.map diff --git a/build/lib/base.js.map b/build/lib/base.js.map new file mode 100644 index 0000000..23a78b3 --- /dev/null +++ b/build/lib/base.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["base.ts"],"names":[],"mappings":"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","file":"base.js","sourcesContent":["import * as ts from 'typescript';\nimport {Transpiler} from './main';\n\nexport type ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration;\n\nexport function ident(n: ts.Node): string {\n if (n.kind === ts.SyntaxKind.Identifier) return (n).text;\n if (n.kind === ts.SyntaxKind.QualifiedName) {\n let qname = (n);\n let leftName = ident(qname.left);\n if (leftName) return leftName + '.' + ident(qname.right);\n }\n return null;\n}\n\nexport class TranspilerBase {\n private idCounter: number = 0;\n constructor(private transpiler: Transpiler) {}\n\n visit(n: ts.Node) { this.transpiler.visit(n); }\n emit(s: string) { this.transpiler.emit(s); }\n emitBefore(s: string, search: string) { this.transpiler.emitBefore(s, search); }\n emitNoSpace(s: string) { this.transpiler.emitNoSpace(s); }\n reportError(n: ts.Node, message: string) { this.transpiler.reportError(n, message); }\n\n visitNode(n: ts.Node): boolean { throw new Error('not implemented'); }\n\n visitEach(nodes: ts.Node[]) { nodes.forEach((n) => this.visit(n)); }\n\n visitEachIfPresent(nodes?: ts.Node[]) {\n if (nodes) this.visitEach(nodes);\n }\n\n visitList(nodes: ts.Node[], separator = ',') {\n for (let i = 0; i < nodes.length; i++) {\n this.visit(nodes[i]);\n if (i < nodes.length - 1) this.emit(separator);\n }\n }\n\n uniqueId(name: string): string {\n const id = this.idCounter++;\n return `_${name}\\$\\$ts2dart\\$${id}`;\n }\n\n assert(c: ts.Node, condition: boolean, reason: string): void {\n if (!condition) {\n this.reportError(c, reason);\n throw new Error(reason);\n }\n }\n\n getAncestor(n: ts.Node, kind: ts.SyntaxKind): ts.Node {\n for (let parent = n; parent; parent = parent.parent) {\n if (parent.kind === kind) return parent;\n }\n return null;\n }\n\n hasAncestor(n: ts.Node, kind: ts.SyntaxKind): boolean { return !!this.getAncestor(n, kind); }\n\n hasAnnotation(decorators: ts.NodeArray, name: string): boolean {\n if (!decorators) return false;\n return decorators.some((d) => {\n let decName = ident(d.expression);\n if (decName === name) return true;\n if (d.expression.kind !== ts.SyntaxKind.CallExpression) return false;\n let callExpr = (d.expression);\n decName = ident(callExpr.expression);\n return decName === name;\n });\n }\n\n hasFlag(n: {flags: number}, flag: ts.NodeFlags): boolean {\n return n && (n.flags & flag) !== 0 || false;\n }\n\n maybeDestructureIndexType(node: ts.TypeLiteralNode): [ts.TypeNode, ts.TypeNode] {\n let members = node.members;\n if (members.length !== 1 || members[0].kind !== ts.SyntaxKind.IndexSignature) {\n return null;\n }\n let indexSig = (members[0]);\n if (indexSig.parameters.length > 1) {\n this.reportError(indexSig, 'Expected an index signature to have a single parameter');\n }\n return [indexSig.parameters[0].type, indexSig.type];\n }\n\n\n getRelativeFileName(fileName: string): string {\n return this.transpiler.getRelativeFileName(fileName);\n }\n\n maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray}) {\n if (n.typeArguments) {\n // If it's a single type argument ``, ignore it and emit nothing.\n // This is particularly useful for `Promise`, see\n // https://github.com/dart-lang/sdk/issues/2231#issuecomment-108313639\n if (n.typeArguments.length === 1 && n.typeArguments[0].kind === ts.SyntaxKind.VoidKeyword) {\n return;\n }\n this.emitNoSpace('<');\n this.visitList(n.typeArguments);\n this.emit('>');\n }\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/call.js b/build/lib/call.js new file mode 100644 index 0000000..efc3d53 --- /dev/null +++ b/build/lib/call.js @@ -0,0 +1,243 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var CallTranspiler = (function (_super) { + __extends(CallTranspiler, _super); + function CallTranspiler(tr, fc) { + _super.call(this, tr); + this.fc = fc; + } + CallTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.Block: + // This is a bit ugly: to separate Declarations from Calls, this code has to special case + // blocks that are actually constructor bodies. + if (node.parent && node.parent.kind === ts.SyntaxKind.Constructor) { + return this.visitConstructorBody(node.parent); + } + return false; + case ts.SyntaxKind.NewExpression: + var newExpr = node; + if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) { + // Constructor calls in annotations must be const constructor calls. + this.emit('const'); + } + else if (this.fc.isInsideConstExpr(node)) { + this.emit('const'); + } + else { + // Some implementations can replace the `new` keyword. + if (this.fc.shouldEmitNew(newExpr)) { + this.emit('new'); + } + } + if (this.fc.maybeHandleCall(newExpr)) + break; + this.visitCall(newExpr); + break; + case ts.SyntaxKind.CallExpression: + var callExpr = node; + if (this.fc.maybeHandleCall(callExpr)) + break; + if (this.maybeHandleSuperCall(callExpr)) + break; + this.visitCall(callExpr); + break; + case ts.SyntaxKind.SuperKeyword: + this.emit('super'); + break; + default: + return false; + } + return true; + }; + CallTranspiler.prototype.visitCall = function (c) { + if (c.expression.kind === ts.SyntaxKind.Identifier) { + this.fc.visitTypeName(c.expression); + } + else { + this.visit(c.expression); + } + if (c.typeArguments) { + // For DDC, emit generic method arguments in /* block comments */ + // NB: Surprisingly, whitespace within the comment is significant here :-( + // TODO(martinprobst): Remove once Dart natively supports generic methods. + if (c.kind !== ts.SyntaxKind.NewExpression) + this.emit('/*'); + this.maybeVisitTypeArguments(c); + if (c.kind !== ts.SyntaxKind.NewExpression) + this.emitNoSpace('*/'); + } + this.emit('('); + if (c.arguments && !this.handleNamedParamsCall(c)) { + if (c.expression.text == 'RegExp') { + if (c.arguments.length > 1) { + if (c.arguments[1].text == 'i') { + this.visit(c.arguments[0]); + this.emit(', caseSensitive: false)'); + return; + } + } + } + else { + this.visitList(c.arguments); + } + } + this.emit(')'); + }; + CallTranspiler.prototype.handleNamedParamsCall = function (c) { + // Preamble: This is all committed in the name of backwards compat with the traceur transpiler. + // Terrible hack: transform foo(a, b, {c: d}) into foo(a, b, c: d), which is Dart's calling + // syntax for named/optional parameters. An alternative would be to transform the method + // declaration to take a plain object literal and destructure in the method, but then client + // code written against Dart wouldn't get nice named parameters. + if (c.arguments.length === 0) + return false; + var last = c.arguments[c.arguments.length - 1]; + if (last.kind !== ts.SyntaxKind.ObjectLiteralExpression) + return false; + var objLit = last; + if (objLit.properties.length === 0) + return false; + // Even worse: foo(a, b, {'c': d}) is considered to *not* be a named parameters call. + var hasNonPropAssignments = objLit.properties.some(function (p) { + return (p.kind !== ts.SyntaxKind.PropertyAssignment || + p.name.kind !== ts.SyntaxKind.Identifier); + }); + if (hasNonPropAssignments) + return false; + var len = c.arguments.length - 1; + this.visitList(c.arguments.slice(0, len)); + if (len) + this.emit(','); + var props = objLit.properties; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + this.emit(base.ident(prop.name)); + this.emit(':'); + this.visit(prop.initializer); + if (i < objLit.properties.length - 1) + this.emit(','); + } + return true; + }; + /** + * Handles constructor initializer lists and bodies. + * + *

Dart's super() ctor calls have to be moved to the constructors initializer list, and `const` + * constructors must be completely empty, only assigning into fields through the initializer list. + * The code below finds super() calls and handles const constructors, marked with the special + * `@CONST` annotation on the class. + * + *

Not emitting super() calls when traversing the ctor body is handled by maybeHandleSuperCall + * below. + */ + CallTranspiler.prototype.visitConstructorBody = function (ctor) { + var _this = this; + var body = ctor.body; + if (!body) + return false; + var errorAssignmentsSuper = 'const constructors can only contain assignments and super calls'; + var errorThisAssignment = 'assignments in const constructors must assign into this.'; + var parent = ctor.parent; + var parentIsConst = this.fc.isConstClass(parent); + var superCall; + var expressions = []; + // Find super() calls and (if in a const ctor) collect assignment expressions (not statements!) + body.statements.forEach(function (stmt) { + if (stmt.kind !== ts.SyntaxKind.ExpressionStatement) { + if (parentIsConst) + _this.reportError(stmt, errorAssignmentsSuper); + return; + } + var nestedExpr = stmt.expression; + // super() call? + if (nestedExpr.kind === ts.SyntaxKind.CallExpression) { + var callExpr = nestedExpr; + if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) { + if (parentIsConst) + _this.reportError(stmt, errorAssignmentsSuper); + return; + } + superCall = callExpr; + return; + } + // this.x assignment? + if (parentIsConst) { + // Check for assignment. + if (nestedExpr.kind !== ts.SyntaxKind.BinaryExpression) { + _this.reportError(nestedExpr, errorAssignmentsSuper); + return; + } + var binExpr = nestedExpr; + if (binExpr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) { + _this.reportError(binExpr, errorAssignmentsSuper); + return; + } + // Check for 'this.' + if (binExpr.left.kind !== ts.SyntaxKind.PropertyAccessExpression) { + _this.reportError(binExpr, errorThisAssignment); + return; + } + var lhs = binExpr.left; + if (lhs.expression.kind !== ts.SyntaxKind.ThisKeyword) { + _this.reportError(binExpr, errorThisAssignment); + return; + } + var ident = lhs.name; + binExpr.left = ident; + expressions.push(nestedExpr); + } + }); + var hasInitializerExpr = expressions.length > 0; + if (hasInitializerExpr) { + // Write out the assignments. + this.emit(':'); + this.visitList(expressions); + } + if (superCall) { + this.emit(hasInitializerExpr ? ',' : ':'); + this.emit('super ('); + if (!this.handleNamedParamsCall(superCall)) { + this.visitList(superCall.arguments); + } + this.emit(')'); + } + if (parentIsConst) { + // Const ctors don't have bodies. + this.emit(';'); + return true; // completely handled. + } + else { + return false; + } + }; + /** + * Checks whether `callExpr` is a super() call that should be ignored because it was already + * handled by `maybeEmitSuperInitializer` above. + */ + CallTranspiler.prototype.maybeHandleSuperCall = function (callExpr) { + if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) + return false; + // Sanity check that there was indeed a ctor directly above this call. + var exprStmt = callExpr.parent; + var ctorBody = exprStmt.parent; + var ctor = ctorBody.parent; + if (ctor.kind !== ts.SyntaxKind.Constructor) { + this.reportError(callExpr, 'super calls must be immediate children of their constructors'); + return false; + } + this.emit('/* super call moved to initializer */'); + return true; + }; + return CallTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = CallTranspiler; + +//# sourceMappingURL=call.js.map diff --git a/build/lib/call.js.map b/build/lib/call.js.map new file mode 100644 index 0000000..3888732 --- /dev/null +++ b/build/lib/call.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["call.ts"],"names":[],"mappings":";;;;;;AAAA,IAAO,EAAE,WAAW,YAAY,CAAC,CAAC;AAClC,IAAO,IAAI,WAAW,QAAQ,CAAC,CAAC;AAIhC;IAA4C,kCAAmB;IAC7D,wBAAY,EAAsB,EAAU,EAAmB;QAAI,kBAAM,EAAE,CAAC,CAAC;QAAjC,OAAE,GAAF,EAAE,CAAiB;IAAe,CAAC;IAE/E,kCAAS,GAAT,UAAU,IAAa;QACrB,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAClB,KAAK,EAAE,CAAC,UAAU,CAAC,KAAK;gBACtB,yFAAyF;gBACzF,+CAA+C;gBAC/C,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;oBAClE,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAA4B,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC3E,CAAC;gBACD,MAAM,CAAC,KAAK,CAAC;YACf,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa;gBAC9B,IAAI,OAAO,GAAqB,IAAI,CAAC;gBACrC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBACpD,oEAAoE;oBACpE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,CAAC;gBAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,CAAC;gBAAC,IAAI,CAAC,CAAC;oBACN,sDAAsD;oBACtD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBACnC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACnB,CAAC;gBACH,CAAC;gBACD,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;oBAAC,KAAK,CAAC;gBAC5C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACxB,KAAK,CAAC;YACR,KAAK,EAAE,CAAC,UAAU,CAAC,cAAc;gBAC/B,IAAI,QAAQ,GAAsB,IAAI,CAAC;gBACvC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;oBAAC,KAAK,CAAC;gBAC7C,EAAE,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;oBAAC,KAAK,CAAC;gBAC/C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBACzB,KAAK,CAAC;YACR,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY;gBAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACnB,KAAK,CAAC;YACR;gBACE,MAAM,CAAC,KAAK,CAAC;QACjB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAEO,kCAAS,GAAjB,UAAkB,CAAoB;QACpC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;YACnD,IAAI,CAAC,EAAE,CAAC,aAAa,CAAgB,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,CAAC;QAAC,IAAI,CAAC,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QACD,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;YACpB,iEAAiE;YACjE,0EAA0E;YAC1E,0EAA0E;YAC1E,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5D,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;YAChC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAClD,EAAE,CAAC,CAAO,CAAE,CAAC,UAAU,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC;gBACzC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC3B,EAAE,CAAC,CAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;wBACtC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC3B,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;wBACrC,MAAM,CAAC;oBACT,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,IAAI,CAAC,CAAC;gBACN,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAEO,8CAAqB,GAA7B,UAA8B,CAAoB;QAChD,+FAA+F;QAE/F,2FAA2F;QAC3F,wFAAwF;QACxF,4FAA4F;QAC5F,gEAAgE;QAChE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QAC3C,IAAI,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/C,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,uBAAuB,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QACtE,IAAI,MAAM,GAA+B,IAAI,CAAC;QAC9C,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QACjD,qFAAqF;QACrF,IAAI,qBAAqB,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAC9C,UAAC,CAAC;YACE,OAAA,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,kBAAkB;gBACnB,CAAE,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QADnE,CACmE,CAAC,CAAC;QAC7E,EAAE,CAAC,CAAC,qBAAqB,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QAExC,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1C,EAAE,CAAC,CAAC,GAAG,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;QAC9B,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,IAAI,GAA0B,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC7B,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;OAUG;IACK,6CAAoB,GAA5B,UAA6B,IAA+B;QAA5D,iBA+EC;QA9EC,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QAExB,IAAI,qBAAqB,GAAG,iEAAiE,CAAC;QAC9F,IAAI,mBAAmB,GAAG,0DAA0D,CAAC;QAErF,IAAI,MAAM,GAAmB,IAAI,CAAC,MAAM,CAAC;QACzC,IAAI,aAAa,GAAG,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,SAA4B,CAAC;QACjC,IAAI,WAAW,GAAoB,EAAE,CAAC;QACtC,+FAA+F;QAC/F,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,UAAC,IAAI;YAC3B,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBACpD,EAAE,CAAC,CAAC,aAAa,CAAC;oBAAC,KAAI,CAAC,WAAW,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;gBACjE,MAAM,CAAC;YACT,CAAC;YACD,IAAI,UAAU,GAA4B,IAAK,CAAC,UAAU,CAAC;YAE3D,gBAAgB;YAChB,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;gBACrD,IAAI,QAAQ,GAAsB,UAAU,CAAC;gBAC7C,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;oBAC5D,EAAE,CAAC,CAAC,aAAa,CAAC;wBAAC,KAAI,CAAC,WAAW,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;oBACjE,MAAM,CAAC;gBACT,CAAC;gBACD,SAAS,GAAG,QAAQ,CAAC;gBACrB,MAAM,CAAC;YACT,CAAC;YAED,qBAAqB;YACrB,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;gBAClB,wBAAwB;gBACxB,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;oBACvD,KAAI,CAAC,WAAW,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;oBACpD,MAAM,CAAC;gBACT,CAAC;gBACD,IAAI,OAAO,GAAwB,UAAU,CAAC;gBAC9C,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;oBAC7D,KAAI,CAAC,WAAW,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;oBACjD,MAAM,CAAC;gBACT,CAAC;gBACD,oBAAoB;gBACpB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC,CAAC;oBACjE,KAAI,CAAC,WAAW,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;oBAC/C,MAAM,CAAC;gBACT,CAAC;gBACD,IAAI,GAAG,GAAgC,OAAO,CAAC,IAAI,CAAC;gBACpD,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;oBACtD,KAAI,CAAC,WAAW,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;oBAC/C,MAAM,CAAC;gBACT,CAAC;gBACD,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;gBACrB,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC;gBACrB,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,kBAAkB,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;QAChD,EAAE,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACvB,6BAA6B;YAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC9B,CAAC;QACD,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,IAAI,CAAC,kBAAkB,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACrB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC3C,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QACD,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;YAClB,iCAAiC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,CAAE,sBAAsB;QACtC,CAAC;QAAC,IAAI,CAAC,CAAC;YACN,MAAM,CAAC,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,6CAAoB,GAA5B,UAA6B,QAA2B;QACtD,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC;QAC1E,sEAAsE;QACtE,IAAI,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,IAAI,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,IAAI,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC3B,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;YAC5C,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,8DAA8D,CAAC,CAAC;YAC3F,MAAM,CAAC,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IACH,qBAAC;AAAD,CAxNA,AAwNC,CAxN2C,IAAI,CAAC,cAAc,GAwN9D;AAxND;mCAwNC,CAAA","file":"call.js","sourcesContent":["import ts = require('typescript');\nimport base = require('./base');\nimport ts2dart = require('./main');\nimport {FacadeConverter} from './facade_converter';\n\nexport default class CallTranspiler extends base.TranspilerBase {\n constructor(tr: ts2dart.Transpiler, private fc: FacadeConverter) { super(tr); }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.Block:\n // This is a bit ugly: to separate Declarations from Calls, this code has to special case\n // blocks that are actually constructor bodies.\n if (node.parent && node.parent.kind === ts.SyntaxKind.Constructor) {\n return this.visitConstructorBody(node.parent);\n }\n return false;\n case ts.SyntaxKind.NewExpression:\n let newExpr = node;\n if (this.hasAncestor(node, ts.SyntaxKind.Decorator)) {\n // Constructor calls in annotations must be const constructor calls.\n this.emit('const');\n } else if (this.fc.isInsideConstExpr(node)) {\n this.emit('const');\n } else {\n // Some implementations can replace the `new` keyword.\n if (this.fc.shouldEmitNew(newExpr)) {\n this.emit('new');\n }\n }\n if (this.fc.maybeHandleCall(newExpr)) break;\n this.visitCall(newExpr);\n break;\n case ts.SyntaxKind.CallExpression:\n let callExpr = node;\n if (this.fc.maybeHandleCall(callExpr)) break;\n if (this.maybeHandleSuperCall(callExpr)) break;\n this.visitCall(callExpr);\n break;\n case ts.SyntaxKind.SuperKeyword:\n this.emit('super');\n break;\n default:\n return false;\n }\n return true;\n }\n\n private visitCall(c: ts.CallExpression) {\n if (c.expression.kind === ts.SyntaxKind.Identifier) {\n this.fc.visitTypeName(c.expression);\n } else {\n this.visit(c.expression);\n }\n if (c.typeArguments) {\n // For DDC, emit generic method arguments in /* block comments */\n // NB: Surprisingly, whitespace within the comment is significant here :-(\n // TODO(martinprobst): Remove once Dart natively supports generic methods.\n if (c.kind !== ts.SyntaxKind.NewExpression) this.emit('/*');\n this.maybeVisitTypeArguments(c);\n if (c.kind !== ts.SyntaxKind.NewExpression) this.emitNoSpace('*/');\n }\n this.emit('(');\n if (c.arguments && !this.handleNamedParamsCall(c)) {\n if ((c).expression.text == 'RegExp') {\n if (c.arguments.length > 1) {\n if ((c.arguments[1]).text == 'i') {\n this.visit(c.arguments[0]);\n this.emit(', caseSensitive: false)');\n return;\n }\n }\n } else {\n this.visitList(c.arguments);\n }\n }\n this.emit(')');\n }\n\n private handleNamedParamsCall(c: ts.CallExpression): boolean {\n // Preamble: This is all committed in the name of backwards compat with the traceur transpiler.\n\n // Terrible hack: transform foo(a, b, {c: d}) into foo(a, b, c: d), which is Dart's calling\n // syntax for named/optional parameters. An alternative would be to transform the method\n // declaration to take a plain object literal and destructure in the method, but then client\n // code written against Dart wouldn't get nice named parameters.\n if (c.arguments.length === 0) return false;\n let last = c.arguments[c.arguments.length - 1];\n if (last.kind !== ts.SyntaxKind.ObjectLiteralExpression) return false;\n let objLit = last;\n if (objLit.properties.length === 0) return false;\n // Even worse: foo(a, b, {'c': d}) is considered to *not* be a named parameters call.\n let hasNonPropAssignments = objLit.properties.some(\n (p) =>\n (p.kind !== ts.SyntaxKind.PropertyAssignment ||\n (p).name.kind !== ts.SyntaxKind.Identifier));\n if (hasNonPropAssignments) return false;\n\n let len = c.arguments.length - 1;\n this.visitList(c.arguments.slice(0, len));\n if (len) this.emit(',');\n let props = objLit.properties;\n for (let i = 0; i < props.length; i++) {\n let prop = props[i];\n this.emit(base.ident(prop.name));\n this.emit(':');\n this.visit(prop.initializer);\n if (i < objLit.properties.length - 1) this.emit(',');\n }\n return true;\n }\n\n /**\n * Handles constructor initializer lists and bodies.\n *\n *

Dart's super() ctor calls have to be moved to the constructors initializer list, and `const`\n * constructors must be completely empty, only assigning into fields through the initializer list.\n * The code below finds super() calls and handles const constructors, marked with the special\n * `@CONST` annotation on the class.\n *\n *

Not emitting super() calls when traversing the ctor body is handled by maybeHandleSuperCall\n * below.\n */\n private visitConstructorBody(ctor: ts.ConstructorDeclaration): boolean {\n let body = ctor.body;\n if (!body) return false;\n\n let errorAssignmentsSuper = 'const constructors can only contain assignments and super calls';\n let errorThisAssignment = 'assignments in const constructors must assign into this.';\n\n let parent = ctor.parent;\n let parentIsConst = this.fc.isConstClass(parent);\n let superCall: ts.CallExpression;\n let expressions: ts.Expression[] = [];\n // Find super() calls and (if in a const ctor) collect assignment expressions (not statements!)\n body.statements.forEach((stmt) => {\n if (stmt.kind !== ts.SyntaxKind.ExpressionStatement) {\n if (parentIsConst) this.reportError(stmt, errorAssignmentsSuper);\n return;\n }\n let nestedExpr = (stmt).expression;\n\n // super() call?\n if (nestedExpr.kind === ts.SyntaxKind.CallExpression) {\n let callExpr = nestedExpr;\n if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) {\n if (parentIsConst) this.reportError(stmt, errorAssignmentsSuper);\n return;\n }\n superCall = callExpr;\n return;\n }\n\n // this.x assignment?\n if (parentIsConst) {\n // Check for assignment.\n if (nestedExpr.kind !== ts.SyntaxKind.BinaryExpression) {\n this.reportError(nestedExpr, errorAssignmentsSuper);\n return;\n }\n let binExpr = nestedExpr;\n if (binExpr.operatorToken.kind !== ts.SyntaxKind.EqualsToken) {\n this.reportError(binExpr, errorAssignmentsSuper);\n return;\n }\n // Check for 'this.'\n if (binExpr.left.kind !== ts.SyntaxKind.PropertyAccessExpression) {\n this.reportError(binExpr, errorThisAssignment);\n return;\n }\n let lhs = binExpr.left;\n if (lhs.expression.kind !== ts.SyntaxKind.ThisKeyword) {\n this.reportError(binExpr, errorThisAssignment);\n return;\n }\n let ident = lhs.name;\n binExpr.left = ident;\n expressions.push(nestedExpr);\n }\n });\n\n let hasInitializerExpr = expressions.length > 0;\n if (hasInitializerExpr) {\n // Write out the assignments.\n this.emit(':');\n this.visitList(expressions);\n }\n if (superCall) {\n this.emit(hasInitializerExpr ? ',' : ':');\n this.emit('super (');\n if (!this.handleNamedParamsCall(superCall)) {\n this.visitList(superCall.arguments);\n }\n this.emit(')');\n }\n if (parentIsConst) {\n // Const ctors don't have bodies.\n this.emit(';');\n return true; // completely handled.\n } else {\n return false;\n }\n }\n\n /**\n * Checks whether `callExpr` is a super() call that should be ignored because it was already\n * handled by `maybeEmitSuperInitializer` above.\n */\n private maybeHandleSuperCall(callExpr: ts.CallExpression): boolean {\n if (callExpr.expression.kind !== ts.SyntaxKind.SuperKeyword) return false;\n // Sanity check that there was indeed a ctor directly above this call.\n let exprStmt = callExpr.parent;\n let ctorBody = exprStmt.parent;\n let ctor = ctorBody.parent;\n if (ctor.kind !== ts.SyntaxKind.Constructor) {\n this.reportError(callExpr, 'super calls must be immediate children of their constructors');\n return false;\n }\n this.emit('/* super call moved to initializer */');\n return true;\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/declaration.js b/build/lib/declaration.js new file mode 100644 index 0000000..86e51b3 --- /dev/null +++ b/build/lib/declaration.js @@ -0,0 +1,561 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var DeclarationTranspiler = (function (_super) { + __extends(DeclarationTranspiler, _super); + function DeclarationTranspiler(tr, fc, enforceUnderscoreConventions) { + _super.call(this, tr); + this.fc = fc; + this.enforceUnderscoreConventions = enforceUnderscoreConventions; + } + DeclarationTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.VariableDeclarationList: + // Note: VariableDeclarationList can only occur as part of a for loop. + var varDeclList = node; + this.visitList(varDeclList.declarations); + break; + case ts.SyntaxKind.VariableDeclaration: + var varDecl = node; + this.visitVariableDeclarationType(varDecl); + this.visit(varDecl.name); + if (varDecl.initializer) { + this.emit('='); + this.visit(varDecl.initializer); + } + break; + case ts.SyntaxKind.ClassDeclaration: + var classDecl = node; + if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abstract)) { + this.visitClassLike('abstract class', classDecl); + } + else { + this.visitClassLike('class', classDecl); + } + break; + case ts.SyntaxKind.InterfaceDeclaration: + var ifDecl = node; + // Function type interface in an interface with a single declaration + // of a call signature (http://goo.gl/ROC5jN). + if (ifDecl.members.length === 1 && ifDecl.members[0].kind === ts.SyntaxKind.CallSignature) { + var member_1 = ifDecl.members[0]; + this.visitFunctionTypedefInterface(ifDecl.name.text, member_1, ifDecl.typeParameters); + } + else { + this.visitClassLike('abstract class', ifDecl); + } + break; + case ts.SyntaxKind.HeritageClause: + var heritageClause = node; + if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword && + heritageClause.parent.kind !== ts.SyntaxKind.InterfaceDeclaration) { + this.emit('extends'); + } + else { + this.emit('implements'); + } + // Can only have one member for extends clauses. + this.visitList(heritageClause.types); + break; + case ts.SyntaxKind.ExpressionWithTypeArguments: + var exprWithTypeArgs = node; + this.visit(exprWithTypeArgs.expression); + this.maybeVisitTypeArguments(exprWithTypeArgs); + break; + case ts.SyntaxKind.EnumDeclaration: + var decl = node; + // The only legal modifier for an enum decl is const. + var isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Const); + if (isConst) { + this.reportError(node, 'const enums are not supported'); + } + this.emit('enum'); + this.fc.visitTypeName(decl.name); + this.emit('{'); + // Enums can be empty in TS ... + if (decl.members.length === 0) { + // ... but not in Dart. + this.reportError(node, 'empty enums are not supported'); + } + this.visitList(decl.members); + this.emit('}'); + break; + case ts.SyntaxKind.EnumMember: + var member = node; + this.visit(member.name); + if (member.initializer) { + this.reportError(node, 'enum initializers are not supported'); + } + break; + case ts.SyntaxKind.Constructor: + var ctorDecl = node; + // Find containing class name. + var className = void 0; + for (var parent_1 = ctorDecl.parent; parent_1; parent_1 = parent_1.parent) { + if (parent_1.kind === ts.SyntaxKind.ClassDeclaration) { + className = parent_1.name; + break; + } + } + if (!className) + this.reportError(ctorDecl, 'cannot find outer class node'); + this.visitDeclarationMetadata(ctorDecl); + if (this.fc.isConstClass(ctorDecl.parent)) { + this.emit('const'); + } + this.visit(className); + this.visitParameters(ctorDecl.parameters); + this.visit(ctorDecl.body); + break; + case ts.SyntaxKind.PropertyDeclaration: + this.visitProperty(node); + break; + case ts.SyntaxKind.SemicolonClassElement: + // No-op, don't emit useless declarations. + break; + case ts.SyntaxKind.MethodDeclaration: + this.visitDeclarationMetadata(node); + this.visitFunctionLike(node); + break; + case ts.SyntaxKind.GetAccessor: + this.visitDeclarationMetadata(node); + this.visitFunctionLike(node, 'get'); + break; + case ts.SyntaxKind.SetAccessor: + this.visitDeclarationMetadata(node); + this.visitFunctionLike(node, 'set'); + break; + case ts.SyntaxKind.FunctionDeclaration: + var funcDecl = node; + this.visitDecorators(funcDecl.decorators); + this.visitFunctionLike(funcDecl); + break; + case ts.SyntaxKind.ArrowFunction: + var arrowFunc = node; + // Dart only allows expressions following the fat arrow operator. + // If the body is a block, we have to drop the fat arrow and emit an + // anonymous function instead. + if (arrowFunc.body.kind === ts.SyntaxKind.Block) { + this.visitFunctionLike(arrowFunc); + } + else { + this.visitParameters(arrowFunc.parameters); + this.emit('=>'); + this.visit(arrowFunc.body); + } + break; + case ts.SyntaxKind.FunctionExpression: + var funcExpr = node; + this.visitFunctionLike(funcExpr); + break; + case ts.SyntaxKind.PropertySignature: + var propSig = node; + this.visitProperty(propSig); + break; + case ts.SyntaxKind.MethodSignature: + var methodSignatureDecl = node; + this.visitEachIfPresent(methodSignatureDecl.modifiers); + this.visitFunctionLike(methodSignatureDecl); + break; + case ts.SyntaxKind.Parameter: + var paramDecl = node; + // Property parameters will have an explicit property declaration, so we just + // need the dart assignment shorthand to reference the property. + if (this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Public) || + this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Private) || + this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Protected)) { + this.visitDeclarationMetadata(paramDecl); + this.emit('this .'); + this.visit(paramDecl.name); + if (paramDecl.initializer) { + this.emit('='); + this.visit(paramDecl.initializer); + } + break; + } + if (paramDecl.dotDotDotToken) + this.reportError(node, 'rest parameters are unsupported'); + if (paramDecl.name.kind === ts.SyntaxKind.ObjectBindingPattern) { + this.visitNamedParameter(paramDecl); + break; + } + this.visitDecorators(paramDecl.decorators); + if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType) { + // Dart uses "returnType paramName ( parameters )" syntax. + var fnType = paramDecl.type; + var hasRestParameter = fnType.parameters.some(function (p) { return !!p.dotDotDotToken; }); + if (hasRestParameter) { + // Dart does not support rest parameters/varargs, degenerate to just "Function". + this.emit('Function'); + this.visit(paramDecl.name); + } + else { + this.visit(fnType.type); + this.visit(paramDecl.name); + this.visitParameters(fnType.parameters); + } + } + else { + if (paramDecl.type) + this.visit(paramDecl.type); + this.visit(paramDecl.name); + } + if (paramDecl.initializer) { + this.emit('='); + this.visit(paramDecl.initializer); + } + break; + case ts.SyntaxKind.StaticKeyword: + this.emit('static'); + break; + case ts.SyntaxKind.AbstractKeyword: + // Abstract methods in Dart simply lack implementation, + // and don't use the 'abstract' modifier + // Abstract classes are handled in `case ts.SyntaxKind.ClassDeclaration` above. + break; + case ts.SyntaxKind.PrivateKeyword: + this.emit('/*private*/'); + // no-op, handled through '_' naming convention in Dart. + break; + case ts.SyntaxKind.PublicKeyword: + this.emit('/*public*/'); + break; + case ts.SyntaxKind.ProtectedKeyword: + this.emit('/*protected*/'); + break; + case ts.SyntaxKind.AwaitExpression: + // Handled in `visitDeclarationMetadata` below. + this.emit('await'); + this.visit(node.expression); + break; + case ts.SyntaxKind.AsyncKeyword: + this.__async = true; + break; + case ts.SyntaxKind.ObjectBindingPattern: + this.emit('/*'); + var n = node; + var first = true; + for (var _i = 0, _a = n.elements; _i < _a.length; _i++) { + var e = _a[_i]; + if (!first) { + this.emit(','); + } + first = false; + this.emit(e.name.text); + } + this.emit('*/'); + break; + default: + return false; + } + return true; + }; + DeclarationTranspiler.prototype.visitVariableDeclarationType = function (varDecl) { + /* Note: VariableDeclarationList can only occur as part of a for loop. This helper method + * is meant for processing for-loop variable declaration types only. + * + * In Dart, all variables in a variable declaration list must have the same type. Since + * we are doing syntax directed translation, we cannot reliably determine if distinct + * variables are declared with the same type or not. Hence we support the following cases: + * + * - A variable declaration list with a single variable can be explicitly typed. + * - When more than one variable is in the list, all must be implicitly typed. + */ + var firstDecl = varDecl.parent.declarations[0]; + var msg = 'Variables in a declaration list of more than one variable cannot by typed'; + var isFinal = this.hasFlag(varDecl.parent, ts.NodeFlags.Const); + var isConst = false; + if (isFinal && varDecl.initializer) { + // "const" in TypeScript/ES6 corresponds to "final" in Dart, i.e. reference constness. + // If a "const" variable is immediately initialized to a CONST_EXPR(), special case it to be + // a deeply const constant, and generate "const ...". + isConst = varDecl.initializer.kind === ts.SyntaxKind.StringLiteral || + varDecl.initializer.kind === ts.SyntaxKind.NumericLiteral || + this.fc.isConstExpr(varDecl.initializer); + } + if (firstDecl === varDecl) { + if (isConst) { + this.emit('const'); + } + else if (isFinal) { + this.emit('final'); + } + if (!varDecl.type) { + if (!isFinal) + this.emit('var'); + } + else if (varDecl.parent.declarations.length > 1) { + this.reportError(varDecl, msg); + } + else { + this.visit(varDecl.type); + } + } + else if (varDecl.type) { + this.reportError(varDecl, msg); + } + }; + DeclarationTranspiler.prototype.visitFunctionLike = function (fn, accessor) { + this.fc.pushTypeParameterNames(fn); + try { + if (fn.type) { + if (fn.kind === ts.SyntaxKind.ArrowFunction || + fn.kind === ts.SyntaxKind.FunctionExpression) { + // The return type is silently dropped for function expressions (including arrow + // functions), it is not supported in Dart. + this.emit('/*'); + this.visit(fn.type); + this.emit('*/'); + } + else { + this.visit(fn.type); + } + } + if (accessor) + this.emit(accessor); + if (fn.name) + this.visit(fn.name); + if (fn.typeParameters) { + this.emit('/*<'); + // Emit the names literally instead of visiting, otherwise they will be replaced with the + // comment hack themselves. + this.emit(fn.typeParameters.map(function (p) { return base.ident(p.name); }).join(', ')); + this.emit('>*/'); + } + // Dart does not even allow the parens of an empty param list on getter + if (accessor !== 'get') { + this.visitParameters(fn.parameters); + } + else { + if (fn.parameters && fn.parameters.length > 0) { + this.reportError(fn, 'getter should not accept parameters'); + } + } + if (fn.body) { + this.visit(fn.body); + } + else { + this.emit(';'); + } + } + finally { + this.fc.popTypeParameterNames(fn); + } + }; + DeclarationTranspiler.prototype.visitParameters = function (parameters) { + this.emit('('); + var firstInitParamIdx = 0; + for (; firstInitParamIdx < parameters.length; firstInitParamIdx++) { + // ObjectBindingPatterns are handled within the parameter visit. + var isOpt = parameters[firstInitParamIdx].initializer || parameters[firstInitParamIdx].questionToken; + if (isOpt && parameters[firstInitParamIdx].name.kind !== ts.SyntaxKind.ObjectBindingPattern) { + break; + } + } + if (firstInitParamIdx !== 0) { + var requiredParams = parameters.slice(0, firstInitParamIdx); + this.visitList(requiredParams); + } + if (firstInitParamIdx !== parameters.length) { + if (firstInitParamIdx !== 0) + this.emit(','); + var positionalOptional = parameters.slice(firstInitParamIdx, parameters.length); + this.emit('['); + this.visitList(positionalOptional); + this.emit(']'); + } + this.emit(')'); + if (this['__async']) { + this.emit('async'); + this['__async'] = false; + } + }; + /** + * Visit a property declaration. + * In the special case of property parameters in a constructor, we also allow a parameter to be + * emitted as a property. + */ + DeclarationTranspiler.prototype.visitProperty = function (decl, isParameter) { + if (isParameter === void 0) { isParameter = false; } + if (!isParameter) + this.visitDeclarationMetadata(decl); + var containingClass = (isParameter ? decl.parent.parent : decl.parent); + var isConstField = this.fc.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST'); + var hasConstCtor = this.fc.isConstClass(containingClass); + if (isConstField) { + // const implies final + this.emit('const'); + } + else { + if (hasConstCtor) { + this.emit('final'); + } + } + if (decl.type) { + this.visit(decl.type); + } + else if (!isConstField && !hasConstCtor) { + this.emit('var'); + } + this.visit(decl.name); + if (decl.initializer && !isParameter) { + this.emit('='); + this.visit(decl.initializer); + } + this.emit(';'); + }; + DeclarationTranspiler.prototype.visitClassLike = function (keyword, decl) { + var _this = this; + this.visitDecorators(decl.decorators); + this.emit(keyword); + this.fc.visitTypeName(decl.name); + if (decl.typeParameters) { + this.emit('<'); + this.visitList(decl.typeParameters); + this.emit('>'); + } + this.visitEachIfPresent(decl.heritageClauses); + this.emit('{'); + // Synthesize explicit properties for ctor with 'property parameters' + var synthesizePropertyParam = function (param) { + if (_this.hasFlag(param.modifiers, ts.NodeFlags.Public) || + _this.hasFlag(param.modifiers, ts.NodeFlags.Private) || + _this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) { + // TODO: we should enforce the underscore prefix on privates + _this.visitProperty(param, true); + } + }; + decl.members + .filter(function (m) { return m.kind === ts.SyntaxKind.Constructor; }) + .forEach(function (ctor) { + return ctor.parameters.forEach(synthesizePropertyParam); + }); + this.visitEachIfPresent(decl.members); + // Generate a constructor to host the const modifier, if needed + if (this.fc.isConstClass(decl) && + !decl.members + .some(function (m) { return m.kind === ts.SyntaxKind.Constructor; })) { + this.emit('const'); + this.fc.visitTypeName(decl.name); + this.emit('();'); + } + this.emit('}'); + }; + DeclarationTranspiler.prototype.visitDecorators = function (decorators) { + var _this = this; + if (!decorators) + return; + decorators.forEach(function (d) { + // Special case @CONST + var name = base.ident(d.expression); + if (!name && d.expression.kind === ts.SyntaxKind.CallExpression) { + // Unwrap @CONST() + var callExpr = d.expression; + name = base.ident(callExpr.expression); + } + // Make sure these match IGNORED_ANNOTATIONS below. + if (name === 'CONST') { + // Ignore @CONST - it is handled above in visitClassLike. + return; + } + _this.emit('@'); + _this.visit(d.expression); + }); + }; + DeclarationTranspiler.prototype.visitDeclarationMetadata = function (decl) { + this.visitDecorators(decl.decorators); + this.visitEachIfPresent(decl.modifiers); + if (this.hasFlag(decl.modifiers, ts.NodeFlags.Protected)) { + // this.reportError(decl, 'protected declarations are unsupported'); + return; + } + if (!this.enforceUnderscoreConventions) + return; + // Early return in case this is a decl with no name, such as a constructor + if (!decl.name) + return; + var name = base.ident(decl.name); + if (!name) + return; + var isPrivate = this.hasFlag(decl.modifiers, ts.NodeFlags.Private); + var matchesPrivate = !!name.match(/^_/); + if (isPrivate && !matchesPrivate) { + this.reportError(decl, 'private members must be prefixed with "_"'); + } + if (!isPrivate && matchesPrivate) { + this.reportError(decl, 'public members must not be prefixed with "_"'); + } + }; + DeclarationTranspiler.prototype.visitNamedParameter = function (paramDecl) { + this.visitDecorators(paramDecl.decorators); + var bp = paramDecl.name; + var propertyTypes = this.fc.resolvePropertyTypes(paramDecl.type); + var initMap = this.getInitializers(paramDecl); + this.emit('{'); + for (var i = 0; i < bp.elements.length; i++) { + var elem = bp.elements[i]; + var propDecl = propertyTypes[base.ident(elem.name)]; + if (propDecl && propDecl.type) + this.visit(propDecl.type); + this.visit(elem.name); + if (elem.initializer && initMap[base.ident(elem.name)]) { + this.reportError(elem, 'cannot have both an inner and outer initializer'); + } + var init = elem.initializer || initMap[base.ident(elem.name)]; + if (init) { + this.emit(':'); + this.visit(init); + } + if (i + 1 < bp.elements.length) + this.emit(','); + } + this.emit('}'); + }; + DeclarationTranspiler.prototype.getInitializers = function (paramDecl) { + var res = {}; + if (!paramDecl.initializer) + return res; + if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) { + this.reportError(paramDecl, 'initializers for named parameters must be object literals'); + return res; + } + for (var _i = 0, _a = paramDecl.initializer.properties; _i < _a.length; _i++) { + var i = _a[_i]; + if (i.kind !== ts.SyntaxKind.PropertyAssignment) { + this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind); + continue; + } + var ole = i; + res[base.ident(ole.name)] = ole.initializer; + } + return res; + }; + /** + * Handles a function typedef-like interface, i.e. an interface that only declares a single + * call signature, by translating to a Dart `typedef`. + */ + DeclarationTranspiler.prototype.visitFunctionTypedefInterface = function (name, signature, typeParameters) { + this.emit('typedef'); + if (signature.type) { + this.visit(signature.type); + } + this.emit(name); + if (typeParameters) { + this.emit('<'); + this.visitList(typeParameters); + this.emit('>'); + } + this.visitParameters(signature.parameters); + this.emit(';'); + }; + return DeclarationTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = DeclarationTranspiler; + +//# sourceMappingURL=declaration.js.map diff --git a/build/lib/declaration.js.map b/build/lib/declaration.js.map new file mode 100644 index 0000000..c076888 --- /dev/null +++ b/build/lib/declaration.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["declaration.ts"],"names":[],"mappings":"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","file":"declaration.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class DeclarationTranspiler extends base.TranspilerBase {\n constructor(\n tr: Transpiler, private fc: FacadeConverter, private enforceUnderscoreConventions: boolean) {\n super(tr);\n }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.VariableDeclarationList:\n // Note: VariableDeclarationList can only occur as part of a for loop.\n let varDeclList = node;\n this.visitList(varDeclList.declarations);\n break;\n case ts.SyntaxKind.VariableDeclaration:\n let varDecl = node;\n this.visitVariableDeclarationType(varDecl);\n this.visit(varDecl.name);\n if (varDecl.initializer) {\n this.emit('=');\n this.visit(varDecl.initializer);\n }\n break;\n\n case ts.SyntaxKind.ClassDeclaration:\n let classDecl = node;\n if (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Abstract)) {\n this.visitClassLike('abstract class', classDecl);\n } else {\n this.visitClassLike('class', classDecl);\n }\n break;\n case ts.SyntaxKind.InterfaceDeclaration:\n let ifDecl = node;\n // Function type interface in an interface with a single declaration\n // of a call signature (http://goo.gl/ROC5jN).\n if (ifDecl.members.length === 1 && ifDecl.members[0].kind === ts.SyntaxKind.CallSignature) {\n let member = ifDecl.members[0];\n this.visitFunctionTypedefInterface(ifDecl.name.text, member, ifDecl.typeParameters);\n } else {\n this.visitClassLike('abstract class', ifDecl);\n }\n break;\n case ts.SyntaxKind.HeritageClause:\n let heritageClause = node;\n if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword &&\n heritageClause.parent.kind !== ts.SyntaxKind.InterfaceDeclaration) {\n this.emit('extends');\n } else {\n this.emit('implements');\n }\n // Can only have one member for extends clauses.\n this.visitList(heritageClause.types);\n break;\n case ts.SyntaxKind.ExpressionWithTypeArguments:\n let exprWithTypeArgs = node;\n this.visit(exprWithTypeArgs.expression);\n this.maybeVisitTypeArguments(exprWithTypeArgs);\n break;\n case ts.SyntaxKind.EnumDeclaration:\n let decl = node;\n // The only legal modifier for an enum decl is const.\n let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Const);\n if (isConst) {\n this.reportError(node, 'const enums are not supported');\n }\n this.emit('enum');\n this.fc.visitTypeName(decl.name);\n this.emit('{');\n // Enums can be empty in TS ...\n if (decl.members.length === 0) {\n // ... but not in Dart.\n this.reportError(node, 'empty enums are not supported');\n }\n this.visitList(decl.members);\n this.emit('}');\n break;\n case ts.SyntaxKind.EnumMember:\n let member = node;\n this.visit(member.name);\n if (member.initializer) {\n this.reportError(node, 'enum initializers are not supported');\n }\n break;\n case ts.SyntaxKind.Constructor:\n let ctorDecl = node;\n // Find containing class name.\n let className: ts.Identifier;\n for (let parent = ctorDecl.parent; parent; parent = parent.parent) {\n if (parent.kind === ts.SyntaxKind.ClassDeclaration) {\n className = (parent).name;\n break;\n }\n }\n if (!className) this.reportError(ctorDecl, 'cannot find outer class node');\n this.visitDeclarationMetadata(ctorDecl);\n if (this.fc.isConstClass(ctorDecl.parent)) {\n this.emit('const');\n }\n this.visit(className);\n this.visitParameters(ctorDecl.parameters);\n this.visit(ctorDecl.body);\n break;\n case ts.SyntaxKind.PropertyDeclaration:\n this.visitProperty(node);\n break;\n case ts.SyntaxKind.SemicolonClassElement:\n // No-op, don't emit useless declarations.\n break;\n case ts.SyntaxKind.MethodDeclaration:\n this.visitDeclarationMetadata(node);\n this.visitFunctionLike(node);\n break;\n case ts.SyntaxKind.GetAccessor:\n this.visitDeclarationMetadata(node);\n this.visitFunctionLike(node, 'get');\n break;\n case ts.SyntaxKind.SetAccessor:\n this.visitDeclarationMetadata(node);\n this.visitFunctionLike(node, 'set');\n break;\n case ts.SyntaxKind.FunctionDeclaration:\n let funcDecl = node;\n this.visitDecorators(funcDecl.decorators);\n this.visitFunctionLike(funcDecl);\n break;\n case ts.SyntaxKind.ArrowFunction:\n let arrowFunc = node;\n // Dart only allows expressions following the fat arrow operator.\n // If the body is a block, we have to drop the fat arrow and emit an\n // anonymous function instead.\n if (arrowFunc.body.kind === ts.SyntaxKind.Block) {\n this.visitFunctionLike(arrowFunc);\n } else {\n this.visitParameters(arrowFunc.parameters);\n this.emit('=>');\n this.visit(arrowFunc.body);\n }\n break;\n case ts.SyntaxKind.FunctionExpression:\n let funcExpr = node;\n this.visitFunctionLike(funcExpr);\n break;\n case ts.SyntaxKind.PropertySignature:\n let propSig = node;\n this.visitProperty(propSig);\n break;\n case ts.SyntaxKind.MethodSignature:\n let methodSignatureDecl = node;\n this.visitEachIfPresent(methodSignatureDecl.modifiers);\n this.visitFunctionLike(methodSignatureDecl);\n break;\n case ts.SyntaxKind.Parameter:\n let paramDecl = node;\n // Property parameters will have an explicit property declaration, so we just\n // need the dart assignment shorthand to reference the property.\n if (this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Public) ||\n this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Private) ||\n this.hasFlag(paramDecl.modifiers, ts.NodeFlags.Protected)) {\n this.visitDeclarationMetadata(paramDecl);\n this.emit('this .');\n this.visit(paramDecl.name);\n if (paramDecl.initializer) {\n this.emit('=');\n this.visit(paramDecl.initializer);\n }\n break;\n }\n if (paramDecl.dotDotDotToken) this.reportError(node, 'rest parameters are unsupported');\n if (paramDecl.name.kind === ts.SyntaxKind.ObjectBindingPattern) {\n this.visitNamedParameter(paramDecl);\n break;\n }\n this.visitDecorators(paramDecl.decorators);\n\n if (paramDecl.type && paramDecl.type.kind === ts.SyntaxKind.FunctionType) {\n // Dart uses \"returnType paramName ( parameters )\" syntax.\n let fnType = paramDecl.type;\n let hasRestParameter = fnType.parameters.some(p => !!p.dotDotDotToken);\n if (hasRestParameter) {\n // Dart does not support rest parameters/varargs, degenerate to just \"Function\".\n this.emit('Function');\n this.visit(paramDecl.name);\n } else {\n this.visit(fnType.type);\n this.visit(paramDecl.name);\n this.visitParameters(fnType.parameters);\n }\n } else {\n if (paramDecl.type) this.visit(paramDecl.type);\n this.visit(paramDecl.name);\n }\n if (paramDecl.initializer) {\n this.emit('=');\n this.visit(paramDecl.initializer);\n }\n break;\n case ts.SyntaxKind.StaticKeyword:\n this.emit('static');\n break;\n case ts.SyntaxKind.AbstractKeyword:\n // Abstract methods in Dart simply lack implementation,\n // and don't use the 'abstract' modifier\n // Abstract classes are handled in `case ts.SyntaxKind.ClassDeclaration` above.\n break;\n case ts.SyntaxKind.PrivateKeyword:\n this.emit('/*private*/');\n // no-op, handled through '_' naming convention in Dart.\n break;\n case ts.SyntaxKind.PublicKeyword:\n this.emit('/*public*/');\n break;\n case ts.SyntaxKind.ProtectedKeyword:\n this.emit('/*protected*/');\n break;\n case ts.SyntaxKind.AwaitExpression:\n // Handled in `visitDeclarationMetadata` below.\n this.emit('await');\n this.visit((node).expression);\n break;\n case ts.SyntaxKind.AsyncKeyword:\n (this).__async = true;\n break;\n case ts.SyntaxKind.ObjectBindingPattern:\n this.emit('/*');\n const n: any = node;\n let first: boolean = true;\n for (var e of n.elements) {\n if (!first) {\n this.emit(',');\n }\n first = false;\n this.emit(e.name.text);\n }\n this.emit('*/');\n break;\n\n\n default:\n return false;\n }\n return true;\n }\n\n private visitVariableDeclarationType(varDecl: ts.VariableDeclaration) {\n /* Note: VariableDeclarationList can only occur as part of a for loop. This helper method\n * is meant for processing for-loop variable declaration types only.\n *\n * In Dart, all variables in a variable declaration list must have the same type. Since\n * we are doing syntax directed translation, we cannot reliably determine if distinct\n * variables are declared with the same type or not. Hence we support the following cases:\n *\n * - A variable declaration list with a single variable can be explicitly typed.\n * - When more than one variable is in the list, all must be implicitly typed.\n */\n let firstDecl = varDecl.parent.declarations[0];\n let msg = 'Variables in a declaration list of more than one variable cannot by typed';\n let isFinal = this.hasFlag(varDecl.parent, ts.NodeFlags.Const);\n let isConst = false;\n if (isFinal && varDecl.initializer) {\n // \"const\" in TypeScript/ES6 corresponds to \"final\" in Dart, i.e. reference constness.\n // If a \"const\" variable is immediately initialized to a CONST_EXPR(), special case it to be\n // a deeply const constant, and generate \"const ...\".\n isConst = varDecl.initializer.kind === ts.SyntaxKind.StringLiteral ||\n varDecl.initializer.kind === ts.SyntaxKind.NumericLiteral ||\n this.fc.isConstExpr(varDecl.initializer);\n }\n if (firstDecl === varDecl) {\n if (isConst) {\n this.emit('const');\n } else if (isFinal) {\n this.emit('final');\n }\n if (!varDecl.type) {\n if (!isFinal) this.emit('var');\n } else if (varDecl.parent.declarations.length > 1) {\n this.reportError(varDecl, msg);\n } else {\n this.visit(varDecl.type);\n }\n } else if (varDecl.type) {\n this.reportError(varDecl, msg);\n }\n }\n\n private visitFunctionLike(fn: ts.FunctionLikeDeclaration, accessor?: string) {\n this.fc.pushTypeParameterNames(fn);\n try {\n if (fn.type) {\n if (fn.kind === ts.SyntaxKind.ArrowFunction ||\n fn.kind === ts.SyntaxKind.FunctionExpression) {\n // The return type is silently dropped for function expressions (including arrow\n // functions), it is not supported in Dart.\n this.emit('/*');\n this.visit(fn.type);\n this.emit('*/');\n } else {\n this.visit(fn.type);\n }\n }\n if (accessor) this.emit(accessor);\n if (fn.name) this.visit(fn.name);\n if (fn.typeParameters) {\n this.emit('/*<');\n // Emit the names literally instead of visiting, otherwise they will be replaced with the\n // comment hack themselves.\n this.emit(fn.typeParameters.map(p => base.ident(p.name)).join(', '));\n this.emit('>*/');\n }\n // Dart does not even allow the parens of an empty param list on getter\n if (accessor !== 'get') {\n this.visitParameters(fn.parameters);\n } else {\n if (fn.parameters && fn.parameters.length > 0) {\n this.reportError(fn, 'getter should not accept parameters');\n }\n }\n if (fn.body) {\n this.visit(fn.body);\n } else {\n this.emit(';');\n }\n } finally {\n this.fc.popTypeParameterNames(fn);\n }\n }\n\n private visitParameters(parameters: ts.ParameterDeclaration[]) {\n this.emit('(');\n let firstInitParamIdx = 0;\n for (; firstInitParamIdx < parameters.length; firstInitParamIdx++) {\n // ObjectBindingPatterns are handled within the parameter visit.\n let isOpt =\n parameters[firstInitParamIdx].initializer || parameters[firstInitParamIdx].questionToken;\n if (isOpt && parameters[firstInitParamIdx].name.kind !== ts.SyntaxKind.ObjectBindingPattern) {\n break;\n }\n }\n\n if (firstInitParamIdx !== 0) {\n let requiredParams = parameters.slice(0, firstInitParamIdx);\n this.visitList(requiredParams);\n }\n\n if (firstInitParamIdx !== parameters.length) {\n if (firstInitParamIdx !== 0) this.emit(',');\n let positionalOptional = parameters.slice(firstInitParamIdx, parameters.length);\n this.emit('[');\n this.visitList(positionalOptional);\n this.emit(']');\n }\n\n this.emit(')');\n if ((this)['__async']) {\n this.emit('async');\n (this)['__async'] = false;\n }\n }\n\n /**\n * Visit a property declaration.\n * In the special case of property parameters in a constructor, we also allow a parameter to be\n * emitted as a property.\n */\n private visitProperty(decl: ts.PropertyDeclaration|ts.ParameterDeclaration, isParameter = false) {\n if (!isParameter) this.visitDeclarationMetadata(decl);\n let containingClass = (isParameter ? decl.parent.parent : decl.parent);\n let isConstField =\n this.fc.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST');\n let hasConstCtor = this.fc.isConstClass(containingClass);\n if (isConstField) {\n // const implies final\n this.emit('const');\n } else {\n if (hasConstCtor) {\n this.emit('final');\n }\n }\n if (decl.type) {\n this.visit(decl.type);\n } else if (!isConstField && !hasConstCtor) {\n this.emit('var');\n }\n this.visit(decl.name);\n if (decl.initializer && !isParameter) {\n this.emit('=');\n this.visit(decl.initializer);\n }\n this.emit(';');\n }\n\n private visitClassLike(keyword: string, decl: base.ClassLike) {\n this.visitDecorators(decl.decorators);\n this.emit(keyword);\n this.fc.visitTypeName(decl.name);\n if (decl.typeParameters) {\n this.emit('<');\n this.visitList(decl.typeParameters);\n this.emit('>');\n }\n this.visitEachIfPresent(decl.heritageClauses);\n this.emit('{');\n\n // Synthesize explicit properties for ctor with 'property parameters'\n let synthesizePropertyParam = (param: ts.ParameterDeclaration) => {\n if (this.hasFlag(param.modifiers, ts.NodeFlags.Public) ||\n this.hasFlag(param.modifiers, ts.NodeFlags.Private) ||\n this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) {\n // TODO: we should enforce the underscore prefix on privates\n this.visitProperty(param, true);\n }\n };\n (>decl.members)\n .filter((m) => m.kind === ts.SyntaxKind.Constructor)\n .forEach(\n (ctor) =>\n (ctor).parameters.forEach(synthesizePropertyParam));\n this.visitEachIfPresent(decl.members);\n\n // Generate a constructor to host the const modifier, if needed\n if (this.fc.isConstClass(decl) &&\n !(>decl.members)\n .some((m) => m.kind === ts.SyntaxKind.Constructor)) {\n this.emit('const');\n this.fc.visitTypeName(decl.name);\n this.emit('();');\n }\n this.emit('}');\n }\n\n private visitDecorators(decorators: ts.NodeArray) {\n if (!decorators) return;\n\n decorators.forEach((d) => {\n // Special case @CONST\n let name = base.ident(d.expression);\n if (!name && d.expression.kind === ts.SyntaxKind.CallExpression) {\n // Unwrap @CONST()\n let callExpr = (d.expression);\n name = base.ident(callExpr.expression);\n }\n // Make sure these match IGNORED_ANNOTATIONS below.\n if (name === 'CONST') {\n // Ignore @CONST - it is handled above in visitClassLike.\n return;\n }\n this.emit('@');\n this.visit(d.expression);\n });\n }\n\n private visitDeclarationMetadata(decl: ts.Declaration) {\n this.visitDecorators(decl.decorators);\n this.visitEachIfPresent(decl.modifiers);\n\n if (this.hasFlag(decl.modifiers, ts.NodeFlags.Protected)) {\n // this.reportError(decl, 'protected declarations are unsupported');\n return;\n }\n if (!this.enforceUnderscoreConventions) return;\n // Early return in case this is a decl with no name, such as a constructor\n if (!decl.name) return;\n let name = base.ident(decl.name);\n if (!name) return;\n let isPrivate = this.hasFlag(decl.modifiers, ts.NodeFlags.Private);\n let matchesPrivate = !!name.match(/^_/);\n if (isPrivate && !matchesPrivate) {\n this.reportError(decl, 'private members must be prefixed with \"_\"');\n }\n if (!isPrivate && matchesPrivate) {\n this.reportError(decl, 'public members must not be prefixed with \"_\"');\n }\n }\n\n private visitNamedParameter(paramDecl: ts.ParameterDeclaration) {\n this.visitDecorators(paramDecl.decorators);\n let bp = paramDecl.name;\n let propertyTypes = this.fc.resolvePropertyTypes(paramDecl.type);\n let initMap = this.getInitializers(paramDecl);\n this.emit('{');\n for (let i = 0; i < bp.elements.length; i++) {\n let elem = bp.elements[i];\n let propDecl = propertyTypes[base.ident(elem.name)];\n if (propDecl && propDecl.type) this.visit(propDecl.type);\n this.visit(elem.name);\n if (elem.initializer && initMap[base.ident(elem.name)]) {\n this.reportError(elem, 'cannot have both an inner and outer initializer');\n }\n let init = elem.initializer || initMap[base.ident(elem.name)];\n if (init) {\n this.emit(':');\n this.visit(init);\n }\n if (i + 1 < bp.elements.length) this.emit(',');\n }\n this.emit('}');\n }\n\n private getInitializers(paramDecl: ts.ParameterDeclaration) {\n let res: ts.Map = {};\n if (!paramDecl.initializer) return res;\n if (paramDecl.initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression) {\n this.reportError(paramDecl, 'initializers for named parameters must be object literals');\n return res;\n }\n for (let i of (paramDecl.initializer).properties) {\n if (i.kind !== ts.SyntaxKind.PropertyAssignment) {\n this.reportError(i, 'named parameter initializers must be properties, got ' + i.kind);\n continue;\n }\n let ole = i;\n res[base.ident(ole.name)] = ole.initializer;\n }\n return res;\n }\n\n /**\n * Handles a function typedef-like interface, i.e. an interface that only declares a single\n * call signature, by translating to a Dart `typedef`.\n */\n private visitFunctionTypedefInterface(\n name: string, signature: ts.CallSignatureDeclaration,\n typeParameters: ts.NodeArray) {\n this.emit('typedef');\n if (signature.type) {\n this.visit(signature.type);\n }\n this.emit(name);\n if (typeParameters) {\n this.emit('<');\n this.visitList(typeParameters);\n this.emit('>');\n }\n this.visitParameters(signature.parameters);\n this.emit(';');\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/expression.js b/build/lib/expression.js new file mode 100644 index 0000000..ea28353 --- /dev/null +++ b/build/lib/expression.js @@ -0,0 +1,163 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var ExpressionTranspiler = (function (_super) { + __extends(ExpressionTranspiler, _super); + function ExpressionTranspiler(tr, fc) { + _super.call(this, tr); + this.fc = fc; + } + ExpressionTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.BinaryExpression: + var binExpr = node; + var operatorKind = binExpr.operatorToken.kind; + var tokenStr = ts.tokenToString(operatorKind); + switch (operatorKind) { + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + // this.emit('identical ('); + this.visit(binExpr.left); + if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) { + this.emit('!='); + } + else { + this.emit('=='); + } + this.visit(binExpr.right); + // this.emit(')'); + break; + case ts.SyntaxKind.CaretToken: + case ts.SyntaxKind.BarToken: + case ts.SyntaxKind.AmpersandToken: + case ts.SyntaxKind.GreaterThanGreaterThanToken: + case ts.SyntaxKind.LessThanLessThanToken: + case ts.SyntaxKind.CaretEqualsToken: + case ts.SyntaxKind.BarEqualsToken: + case ts.SyntaxKind.AmpersandEqualsToken: + case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: + case ts.SyntaxKind.LessThanLessThanEqualsToken: + // In Dart, the bitwise operators are only available on int, so the number types ts2dart + // deals with have to be converted to int explicitly to match JS's semantics in Dart. + if (tokenStr[tokenStr.length - 1] === '=') { + // For assignments, strip the trailing `=` sign to emit just the operator itself. + this.visit(binExpr.left); + this.emit('='); + this.visitAndWrapAsInt(binExpr.left); + this.emit(tokenStr.slice(0, -1)); + } + else { + // normal case (LHS [op]) + this.visitAndWrapAsInt(binExpr.left); + this.emit(tokenStr); + } + this.visitAndWrapAsInt(binExpr.right); + break; + case ts.SyntaxKind.InKeyword: + this.reportError(node, 'in operator is unsupported'); + break; + case ts.SyntaxKind.InstanceOfKeyword: + this.visit(binExpr.left); + this.emit('is'); + this.fc.visitTypeName(binExpr.right); + break; + default: + this.visit(binExpr.left); + this.emit(tokenStr); + this.visit(binExpr.right); + break; + } + break; + case ts.SyntaxKind.PrefixUnaryExpression: + var prefixUnary = node; + var operator = ts.tokenToString(prefixUnary.operator); + this.emit(operator); + if (prefixUnary.operator === ts.SyntaxKind.TildeToken) { + this.visitAndWrapAsInt(prefixUnary.operand); + } + else { + this.visit(prefixUnary.operand); + } + break; + case ts.SyntaxKind.PostfixUnaryExpression: + var postfixUnary = node; + this.visit(postfixUnary.operand); + this.emit(ts.tokenToString(postfixUnary.operator)); + break; + case ts.SyntaxKind.ConditionalExpression: + var conditional = node; + this.visit(conditional.condition); + this.emit('?'); + this.visit(conditional.whenTrue); + this.emit(':'); + this.visit(conditional.whenFalse); + break; + case ts.SyntaxKind.DeleteExpression: + this.emit('/*delete*/'); + // this.reportError(node, 'delete operator is unsupported'); + break; + case ts.SyntaxKind.VoidExpression: + this.emit('/*void*/'); + // this.reportError(node, 'void operator is unsupported'); + break; + case ts.SyntaxKind.TypeOfExpression: + this.emit('/*typeof*/'); + this.visit(node.expression); + // this.reportError(node, 'typeof operator is unsupported'); + break; + case ts.SyntaxKind.ParenthesizedExpression: + var parenExpr = node; + this.emit('('); + this.visit(parenExpr.expression); + this.emit(')'); + break; + case ts.SyntaxKind.PropertyAccessExpression: + var propAccess = node; + if (propAccess.name.text === 'stack' && + this.hasAncestor(propAccess, ts.SyntaxKind.CatchClause)) { + // Handle `e.stack` accesses in catch clauses by mangling to `e_stack`. + // FIXME: Use type checker/FacadeConverter to make sure this is actually Error.stack. + this.visit(propAccess.expression); + this.emitNoSpace('_stack'); + } + else { + if (this.fc.handlePropertyAccess(propAccess)) + break; + this.visit(propAccess.expression); + this.emit('.'); + this.visit(propAccess.name); + } + break; + case ts.SyntaxKind.ElementAccessExpression: + var elemAccess = node; + this.visit(elemAccess.expression); + this.emit('['); + this.visit(elemAccess.argumentExpression); + this.emit(']'); + break; + default: + return false; + } + return true; + }; + ExpressionTranspiler.prototype.visitAndWrapAsInt = function (n) { + var lhsIsHexLit = n.kind === ts.SyntaxKind.NumericLiteral; + if (lhsIsHexLit) { + this.visit(n); + return; + } + this.emit('('); + this.visit(n); + this.emit('as int)'); + }; + return ExpressionTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = ExpressionTranspiler; + +//# sourceMappingURL=expression.js.map diff --git a/build/lib/expression.js.map b/build/lib/expression.js.map new file mode 100644 index 0000000..06b6296 --- /dev/null +++ b/build/lib/expression.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["expression.ts"],"names":[],"mappings":"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","file":"expression.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class ExpressionTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.BinaryExpression:\n let binExpr = node;\n let operatorKind = binExpr.operatorToken.kind;\n let tokenStr = ts.tokenToString(operatorKind);\n switch (operatorKind) {\n case ts.SyntaxKind.EqualsEqualsEqualsToken:\n case ts.SyntaxKind.ExclamationEqualsEqualsToken:\n // this.emit('identical (');\n this.visit(binExpr.left);\n\n if (operatorKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {\n this.emit('!=');\n } else {\n this.emit('==');\n }\n this.visit(binExpr.right);\n // this.emit(')');\n break;\n case ts.SyntaxKind.CaretToken:\n case ts.SyntaxKind.BarToken:\n case ts.SyntaxKind.AmpersandToken:\n case ts.SyntaxKind.GreaterThanGreaterThanToken:\n case ts.SyntaxKind.LessThanLessThanToken:\n case ts.SyntaxKind.CaretEqualsToken:\n case ts.SyntaxKind.BarEqualsToken:\n case ts.SyntaxKind.AmpersandEqualsToken:\n case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken:\n case ts.SyntaxKind.LessThanLessThanEqualsToken:\n // In Dart, the bitwise operators are only available on int, so the number types ts2dart\n // deals with have to be converted to int explicitly to match JS's semantics in Dart.\n if (tokenStr[tokenStr.length - 1] === '=') {\n // For assignments, strip the trailing `=` sign to emit just the operator itself.\n this.visit(binExpr.left);\n this.emit('=');\n this.visitAndWrapAsInt(binExpr.left);\n this.emit(tokenStr.slice(0, -1));\n } else {\n // normal case (LHS [op])\n this.visitAndWrapAsInt(binExpr.left);\n this.emit(tokenStr);\n }\n this.visitAndWrapAsInt(binExpr.right);\n break;\n case ts.SyntaxKind.InKeyword:\n this.reportError(node, 'in operator is unsupported');\n break;\n case ts.SyntaxKind.InstanceOfKeyword:\n this.visit(binExpr.left);\n this.emit('is');\n this.fc.visitTypeName(binExpr.right);\n break;\n default:\n this.visit(binExpr.left);\n this.emit(tokenStr);\n this.visit(binExpr.right);\n break;\n }\n break;\n case ts.SyntaxKind.PrefixUnaryExpression:\n let prefixUnary = node;\n let operator = ts.tokenToString(prefixUnary.operator);\n this.emit(operator);\n\n if (prefixUnary.operator === ts.SyntaxKind.TildeToken) {\n this.visitAndWrapAsInt(prefixUnary.operand);\n } else {\n this.visit(prefixUnary.operand);\n }\n break;\n case ts.SyntaxKind.PostfixUnaryExpression:\n let postfixUnary = node;\n this.visit(postfixUnary.operand);\n this.emit(ts.tokenToString(postfixUnary.operator));\n break;\n case ts.SyntaxKind.ConditionalExpression:\n let conditional = node;\n this.visit(conditional.condition);\n this.emit('?');\n this.visit(conditional.whenTrue);\n this.emit(':');\n this.visit(conditional.whenFalse);\n break;\n case ts.SyntaxKind.DeleteExpression:\n this.emit('/*delete*/');\n // this.reportError(node, 'delete operator is unsupported');\n break;\n case ts.SyntaxKind.VoidExpression:\n this.emit('/*void*/');\n // this.reportError(node, 'void operator is unsupported');\n break;\n case ts.SyntaxKind.TypeOfExpression:\n this.emit('/*typeof*/');\n this.visit((node).expression);\n // this.reportError(node, 'typeof operator is unsupported');\n break;\n\n case ts.SyntaxKind.ParenthesizedExpression:\n let parenExpr = node;\n this.emit('(');\n this.visit(parenExpr.expression);\n this.emit(')');\n break;\n\n case ts.SyntaxKind.PropertyAccessExpression:\n let propAccess = node;\n if (propAccess.name.text === 'stack' &&\n this.hasAncestor(propAccess, ts.SyntaxKind.CatchClause)) {\n // Handle `e.stack` accesses in catch clauses by mangling to `e_stack`.\n // FIXME: Use type checker/FacadeConverter to make sure this is actually Error.stack.\n this.visit(propAccess.expression);\n this.emitNoSpace('_stack');\n } else {\n if (this.fc.handlePropertyAccess(propAccess)) break;\n this.visit(propAccess.expression);\n this.emit('.');\n this.visit(propAccess.name);\n }\n break;\n case ts.SyntaxKind.ElementAccessExpression:\n let elemAccess = node;\n this.visit(elemAccess.expression);\n this.emit('[');\n this.visit(elemAccess.argumentExpression);\n this.emit(']');\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n visitAndWrapAsInt(n: ts.Expression) {\n let lhsIsHexLit = n.kind === ts.SyntaxKind.NumericLiteral;\n if (lhsIsHexLit) {\n this.visit(n);\n return;\n }\n this.emit('(');\n this.visit(n);\n this.emit('as int)');\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/facade_converter.js b/build/lib/facade_converter.js new file mode 100644 index 0000000..cf46309 --- /dev/null +++ b/build/lib/facade_converter.js @@ -0,0 +1,871 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var path = require('path'); +var ts = require('typescript'); +var base = require('./base'); +var FACADE_DEBUG = false; +var DEFAULT_LIB_MARKER = '__ts2dart_default_lib'; +var PROVIDER_IMPORT_MARKER = '__ts2dart_has_provider_import'; +var TS2DART_PROVIDER_COMMENT = '@ts2dart_Provider'; +function merge() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } + var returnObject = {}; + for (var _a = 0, args_1 = args; _a < args_1.length; _a++) { + var arg = args_1[_a]; + for (var _b = 0, _c = Object.getOwnPropertyNames(arg); _b < _c.length; _b++) { + var key = _c[_b]; + returnObject[key] = arg[key]; + } + } + return returnObject; +} +var FacadeConverter = (function (_super) { + __extends(FacadeConverter, _super); + function FacadeConverter(transpiler) { + var _this = this; + _super.call(this, transpiler); + this.candidateProperties = {}; + this.candidateTypes = {}; + this.genericMethodDeclDepth = 0; + this.stdlibTypeReplacements = { + 'Date': 'DateTime', + 'Array': 'List', + 'XMLHttpRequest': 'HttpRequest', + 'Uint8Array': 'Uint8List', + 'ArrayBuffer': 'ByteBuffer', + 'Promise': 'Future', + 'undefined': 'null', + 'replace': 'replaceFirst', + 'require': 'HttpRequest.getString', + 'then': 'then', + 'Object': 'Map', + 'parseFloat': 'double.parse', + 'parseInt': 'int.parse', + 'Math': 'Math', + // Dart has two different incompatible DOM APIs + // https://github.com/angular/angular/issues/2770 + 'Node': 'dynamic', + 'Text': 'dynamic', + 'Element': 'dynamic', + 'Event': 'dynamic', + 'HTMLElement': 'dynamic', + 'HTMLAnchorElement': 'dynamic', + 'HTMLStyleElement': 'dynamic', + 'HTMLInputElement': 'dynamic', + 'HTMLDocument': 'dynamic', + 'History': 'dynamic', + 'Location': 'dynamic' + }; + this.tsToDartTypeNames = (_a = {}, + _a[DEFAULT_LIB_MARKER] = this.stdlibTypeReplacements, + _a['angular2/src/facade/lang'] = { 'Date': 'DateTime' }, + _a['rxjs/Observable'] = { 'Observable': 'Stream' }, + _a['es6-promise/es6-promise'] = { 'Promise': 'Future' }, + _a['es6-shim/es6-shim'] = { 'Promise': 'Future' }, + _a + ); + this.es6Promises = { + 'Promise.catch': function (c, context) { + _this.visit(context); + _this.emit('.catchError('); + _this.visitList(c.arguments); + _this.emit(')'); + }, + 'Promise.then': function (c, context) { + // then() in Dart doesn't support 2 arguments. + _this.visit(context); + _this.emit('.then('); + _this.visit(c.arguments[0]); + _this.emit(')'); + if (c.arguments.length > 1) { + _this.emit('.catchError('); + _this.visit(c.arguments[1]); + _this.emit(')'); + } + }, + 'Promise': function (c, context) { + if (c.kind !== ts.SyntaxKind.NewExpression) + return true; + _this.assert(c, c.arguments.length === 1, 'Promise construction must take 2 arguments.'); + _this.assert(c, c.arguments[0].kind === ts.SyntaxKind.ArrowFunction || + c.arguments[0].kind === ts.SyntaxKind.FunctionExpression, 'Promise argument must be a function expression (or arrow function).'); + var callback; + if (c.arguments[0].kind === ts.SyntaxKind.ArrowFunction) { + callback = c.arguments[0]; + } + else if (c.arguments[0].kind === ts.SyntaxKind.FunctionExpression) { + callback = c.arguments[0]; + } + _this.assert(c, callback.parameters.length > 0 && callback.parameters.length < 3, 'Promise executor must take 1 or 2 arguments (resolve and reject).'); + var completerVarName = _this.uniqueId('completer'); + _this.assert(c, callback.parameters[0].name.kind === ts.SyntaxKind.Identifier, 'First argument of the Promise executor is not a straight parameter.'); + var resolveParameterIdent = (callback.parameters[0].name); + _this.emit('(() {'); // Create a new scope. + _this.emit("Completer " + completerVarName + " = new Completer();"); + _this.emit('var'); + _this.emit(resolveParameterIdent.text); + _this.emit("= " + completerVarName + ".complete;"); + if (callback.parameters.length === 2) { + _this.assert(c, callback.parameters[1].name.kind === ts.SyntaxKind.Identifier, 'First argument of the Promise executor is not a straight parameter.'); + var rejectParameterIdent = (callback.parameters[1].name); + _this.emit('var'); + _this.emit(rejectParameterIdent.text); + _this.emit("= " + completerVarName + ".completeError;"); + } + _this.emit('(()'); + _this.visit(callback.body); + _this.emit(')();'); + _this.emit("return " + completerVarName + ".future;"); + _this.emit('})()'); + } + }; + this.es6Collections = { + 'Map.set': function (c, context) { + _this.visit(context); + _this.emit('['); + _this.visit(c.arguments[0]); + _this.emit(']'); + _this.emit('='); + _this.visit(c.arguments[1]); + }, + 'Map.get': function (c, context) { + _this.visit(context); + _this.emit('['); + _this.visit(c.arguments[0]); + _this.emit(']'); + }, + 'Map.has': function (c, context) { + _this.visit(context); + _this.emitMethodCall('containsKey', c.arguments); + }, + 'Map.delete': function (c, context) { + // JS Map.delete(k) returns whether k was present in the map, + // convert to: + // (Map.containsKey(k) && (Map.remove(k) !== null || true)) + // (Map.remove(k) !== null || true) is required to always returns true + // when Map.containsKey(k) + _this.emit('('); + _this.visit(context); + _this.emitMethodCall('containsKey', c.arguments); + _this.emit('&& ('); + _this.visit(context); + _this.emitMethodCall('remove', c.arguments); + _this.emit('!= null || true ) )'); + }, + 'Map.forEach': function (c, context) { + var cb; + var params; + switch (c.arguments[0].kind) { + case ts.SyntaxKind.FunctionExpression: + cb = (c.arguments[0]); + params = cb.parameters; + if (params.length !== 2) { + _this.reportError(c, 'Map.forEach callback requires exactly two arguments'); + return; + } + _this.visit(context); + _this.emit('. forEach ( ('); + _this.visit(params[1]); + _this.emit(','); + _this.visit(params[0]); + _this.emit(')'); + _this.visit(cb.body); + _this.emit(')'); + break; + case ts.SyntaxKind.ArrowFunction: + cb = (c.arguments[0]); + params = cb.parameters; + if (params.length !== 2) { + _this.reportError(c, 'Map.forEach callback requires exactly two arguments'); + return; + } + _this.visit(context); + _this.emit('. forEach ( ('); + _this.visit(params[1]); + _this.emit(','); + _this.visit(params[0]); + _this.emit(')'); + if (cb.body.kind !== ts.SyntaxKind.Block) { + _this.emit('=>'); + } + _this.visit(cb.body); + _this.emit(')'); + break; + default: + _this.visit(context); + _this.emit('. forEach ( ( k , v ) => ('); + _this.visit(c.arguments[0]); + _this.emit(') ( v , k ) )'); + break; + } + }, + 'Array.find': function (c, context) { + _this.visit(context); + _this.emit('. firstWhere ('); + _this.visit(c.arguments[0]); + _this.emit(', orElse : ( ) => null )'); + } + }; + this.stdlibHandlers = merge(this.es6Promises, this.es6Collections, { + 'Array.push': function (c, context) { + _this.visit(context); + _this.emitMethodCall('add', c.arguments); + }, + 'Array.pop': function (c, context) { + _this.visit(context); + _this.emitMethodCall('removeLast'); + }, + 'Array.shift': function (c, context) { + _this.visit(context); + _this.emit('. removeAt ( 0 )'); + }, + 'Array.unshift': function (c, context) { + _this.emit('('); + _this.visit(context); + if (c.arguments.length === 1) { + _this.emit('.. insert ( 0,'); + _this.visit(c.arguments[0]); + _this.emit(') ) . length'); + } + else { + _this.emit('.. insertAll ( 0, ['); + _this.visitList(c.arguments); + _this.emit(']) ) . length'); + } + }, + 'Array.map': function (c, context) { + _this.visit(context); + _this.emitMethodCall('map', c.arguments); + _this.emitMethodCall('toList'); + }, + 'Array.filter': function (c, context) { + _this.visit(context); + _this.emitMethodCall('where', c.arguments); + _this.emitMethodCall('toList'); + }, + 'Array.some': function (c, context) { + _this.visit(context); + _this.emitMethodCall('any', c.arguments); + }, + 'Array.slice': function (c, context) { + _this.emitCall('ListWrapper.slice', [context].concat(c.arguments)); + }, + 'Array.splice': function (c, context) { + _this.emitCall('ListWrapper.splice', [context].concat(c.arguments)); + }, + 'Array.concat': function (c, context) { + _this.emit('( new List . from ('); + _this.visit(context); + _this.emit(')'); + c.arguments.forEach(function (arg) { + if (!_this.isNamedDefaultLibType(arg, 'Array')) { + _this.reportError(arg, 'Array.concat only takes Array arguments'); + } + _this.emit('.. addAll ('); + _this.visit(arg); + _this.emit(')'); + }); + _this.emit(')'); + }, + 'Array.join': function (c, context) { + _this.visit(context); + if (c.arguments.length) { + _this.emitMethodCall('join', c.arguments); + } + else { + _this.emit('. join ( "," )'); + } + }, + 'Array.reduce': function (c, context) { + _this.visit(context); + if (c.arguments.length >= 2) { + _this.emitMethodCall('fold', [c.arguments[1], c.arguments[0]]); + } + else { + _this.emit('. fold ( null ,'); + _this.visit(c.arguments[0]); + _this.emit(')'); + } + }, + 'ArrayConstructor.isArray': function (c, context) { + _this.emit('( ('); + _this.visitList(c.arguments); // Should only be 1. + _this.emit(')'); + _this.emit('is List'); + _this.emit(')'); + }, + 'Console.log': function (c, context) { + _this.emit('print('); + if (c.arguments.length === 1) { + _this.visit(c.arguments[0]); + } + else { + _this.emit('['); + _this.visitList(c.arguments); + _this.emit('].join(" ")'); + } + _this.emit(')'); + }, + 'RegExp.exec': function (c, context) { + if (context.kind !== ts.SyntaxKind.RegularExpressionLiteral) { + // Fail if the exec call isn't made directly on a regexp literal. + // Multiple exec calls on the same global regexp have side effects + // (each return the next match), which we can't reproduce with a simple + // Dart RegExp (users should switch to some facade / wrapper instead). + _this.reportError(c, 'exec is only supported on regexp literals, ' + + 'to avoid side-effect of multiple calls on global regexps.'); + } + if (c.parent.kind === ts.SyntaxKind.ElementAccessExpression) { + // The result of the exec call is used for immediate indexed access: + // this use-case can be accommodated by RegExp.firstMatch, which returns + // a Match instance with operator[] which returns groups (special index + // 0 returns the full text of the match). + _this.visit(context); + _this.emitMethodCall('firstMatch', c.arguments); + } + else { + // In the general case, we want to return a List. To transform a Match + // into a List of its groups, we alias it in a local closure that we + // call with the Match value. We are then able to use the group method + // to generate a List large enough to hold groupCount groups + the + // full text of the match at special group index 0. + _this.emit('((match) => new List.generate(1 + match.groupCount, match.group))('); + _this.visit(context); + _this.emitMethodCall('firstMatch', c.arguments); + _this.emit(')'); + } + }, + 'RegExp.test': function (c, context) { + _this.visit(context); + _this.emitMethodCall('hasMatch', c.arguments); + }, + 'String.substr': function (c, context) { + _this.reportError(c, 'substr is unsupported, use substring (but beware of the different semantics!)'); + _this.visit(context); + _this.emitMethodCall('substr', c.arguments); + } + }); + this.callHandlerReplaceNew = (_b = {}, + _b[DEFAULT_LIB_MARKER] = { 'Promise': true }, + _b + ); + this.callHandlers = (_c = {}, + _c[DEFAULT_LIB_MARKER] = this.stdlibHandlers, + _c['angular2/manual_typings/globals'] = this.es6Collections, + _c['angular2/src/facade/collection'] = { + 'Map': function (c, context) { + // The actual Map constructor is special cased for const calls. + if (!_this.isInsideConstExpr(c)) + return true; + if (c.arguments.length) { + _this.reportError(c, 'Arguments on a Map constructor in a const are unsupported'); + } + if (c.typeArguments) { + _this.emit('<'); + _this.visitList(c.typeArguments); + _this.emit('>'); + } + _this.emit('{ }'); + return false; + } + }, + _c['angular2/src/core/di/forward_ref'] = { + 'forwardRef': function (c, context) { + // The special function forwardRef translates to an unwrapped value in Dart. + var callback = c.arguments[0]; + if (callback.kind !== ts.SyntaxKind.ArrowFunction) { + _this.reportError(c, 'forwardRef takes only arrow functions'); + return; + } + _this.visit(callback.body); + } + }, + _c['angular2/src/facade/lang'] = { + 'CONST_EXPR': function (c, context) { + // `const` keyword is emitted in the array literal handling, as it needs to be transitive. + _this.visitList(c.arguments); + }, + 'normalizeBlank': function (c, context) { + // normalizeBlank is a noop in Dart, so erase it. + _this.visitList(c.arguments); + } + }, + _c + ); + this.es6CollectionsProp = { + 'Map.size': function (p) { + _this.visit(p.expression); + _this.emit('.'); + _this.emit('length'); + } + }; + this.es6PromisesProp = { + 'PromiseConstructor.resolve': function (p) { + _this.emit('new '); + _this.visit(p.expression); + _this.emit('.value'); + }, + 'PromiseConstructor.reject': function (p) { + _this.emit('new '); + _this.visit(p.expression); + _this.emit('.error'); + } + }; + this.propertyHandlers = (_d = {}, + _d[DEFAULT_LIB_MARKER] = merge(this.es6CollectionsProp, this.es6PromisesProp), + _d + ); + this.extractPropertyNames(this.callHandlers, this.candidateProperties); + this.extractPropertyNames(this.propertyHandlers, this.candidateProperties); + this.extractPropertyNames(this.tsToDartTypeNames, this.candidateTypes); + var _a, _b, _c, _d; + } + FacadeConverter.prototype.initializeTypeBasedConversion = function (tc, opts, host) { + this.tc = tc; + this.defaultLibLocation = ts.getDefaultLibFilePath(opts).replace(/\.d\.ts$/, ''); + this.resolveModuleNames(opts, host, this.callHandlers); + this.resolveModuleNames(opts, host, this.propertyHandlers); + this.resolveModuleNames(opts, host, this.tsToDartTypeNames); + this.resolveModuleNames(opts, host, this.callHandlerReplaceNew); + }; + FacadeConverter.prototype.extractPropertyNames = function (m, candidates) { + for (var _i = 0, _a = Object.keys(m); _i < _a.length; _i++) { + var fileName = _a[_i]; + var file = m[fileName]; + Object.keys(file) + .map(function (propName) { return propName.substring(propName.lastIndexOf('.') + 1); }) + .forEach(function (propName) { return candidates[propName] = true; }); + } + }; + FacadeConverter.prototype.resolveModuleNames = function (opts, host, m) { + for (var _i = 0, _a = Object.keys(m); _i < _a.length; _i++) { + var mn = _a[_i]; + var actual = void 0; + var absolute = void 0; + if (mn === DEFAULT_LIB_MARKER) { + actual = this.defaultLibLocation; + } + else { + var resolved = ts.resolveModuleName(mn, '', opts, host); + if (!resolved.resolvedModule) + continue; + actual = resolved.resolvedModule.resolvedFileName.replace(/(\.d)?\.ts$/, ''); + // TypeScript's resolution returns relative paths here, but uses absolute ones in + // SourceFile.fileName later. Make sure to hit both use cases. + absolute = path.resolve(actual); + } + if (FACADE_DEBUG) + console.log('Resolved module', mn, '->', actual); + m[actual] = m[mn]; + if (absolute) + m[absolute] = m[mn]; + } + }; + /** + * To avoid strongly referencing the Provider class (which could bloat binary size), Angular 2 + * write providers as object literals. However the Dart transformers don't recognize this, so + * ts2dart translates the special syntax `/* @ts2dart_Provider * / {provide: Class, param1: ...}` + * into `const Provider(Class, param1: ...)`. + */ + FacadeConverter.prototype.maybeHandleProvider = function (ole) { + var _this = this; + if (!this.hasMarkerComment(ole, TS2DART_PROVIDER_COMMENT)) + return false; + var classParam; + var remaining = ole.properties.filter(function (e) { + if (e.kind !== ts.SyntaxKind.PropertyAssignment) { + _this.reportError(e, TS2DART_PROVIDER_COMMENT + ' elements must be property assignments'); + } + if ('provide' === base.ident(e.name)) { + classParam = e.initializer; + return false; + } + return true; // include below. + }); + if (!classParam) { + this.reportError(ole, 'missing provide: element'); + return false; + } + this.emit('const Provider('); + this.visit(classParam); + if (remaining.length > 0) { + this.emit(','); + for (var i = 0; i < remaining.length; i++) { + var e = remaining[i]; + if (e.kind !== ts.SyntaxKind.PropertyAssignment) + this.visit(e.name); + this.emit(base.ident(e.name)); + this.emit(':'); + this.visit(e.initializer); + if ((i + 1) < remaining.length) + this.emit(','); + } + this.emit(')'); + } + return true; + }; + FacadeConverter.prototype.maybeHandleCall = function (c) { + if (!this.tc) + return false; + var _a = this.getCallInformation(c), context = _a.context, symbol = _a.symbol; + if (!symbol) { + // getCallInformation returns a symbol if we understand this call. + return false; + } + var handler = this.getHandler(c, symbol, this.callHandlers); + return handler && !handler(c, context); + }; + FacadeConverter.prototype.handlePropertyAccess = function (pa) { + if (!this.tc) + return; + var ident = pa.name.text; + if (!this.candidateProperties.hasOwnProperty(ident)) + return false; + var symbol = this.tc.getSymbolAtLocation(pa.name); + if (!symbol) { + if (!this.stdlibTypeReplacements[ident]) { + this.reportMissingType(pa, ident); + } + return false; + } + var handler = this.getHandler(pa, symbol, this.propertyHandlers); + return handler && !handler(pa); + }; + /** + * Searches for type references that require extra imports and emits the imports as necessary. + */ + FacadeConverter.prototype.emitExtraImports = function (sourceFile) { + var libraries = { + 'XMLHttpRequest': 'dart:html', + 'KeyboardEvent': 'dart:html', + 'Uint8Array': 'dart:typed_arrays', + 'ArrayBuffer': 'dart:typed_arrays', + 'Promise': 'dart:async', + 'HttpRequest.getString': 'dart:html' + }; + var emitted = {}; + this.emitImports(sourceFile, libraries, emitted, sourceFile); + }; + FacadeConverter.prototype.emitImports = function (n, libraries, emitted, sourceFile) { + var _this = this; + if (n.kind === ts.SyntaxKind.TypeReference) { + var type = base.ident(n.typeName); + if (libraries.hasOwnProperty(type)) { + var toEmit = libraries[type]; + if (!emitted[toEmit]) { + this.emit("import '" + toEmit + "';"); + emitted[toEmit] = true; + } + } + } + // Support for importing "Provider" in case /* @ts2dart_Provider */ comments are present. + if (n.kind === ts.SyntaxKind.ImportDeclaration) { + // See if there is already code importing 'Provider' from angular2/core. + var id = n; + if (id.moduleSpecifier.text === 'angular2/core') { + if (id.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { + var ni = id.importClause.namedBindings; + for (var _i = 0, _a = ni.elements; _i < _a.length; _i++) { + var nb = _a[_i]; + if (base.ident(nb.name) === 'Provider') { + emitted[PROVIDER_IMPORT_MARKER] = true; + break; + } + } + } + } + } + if (!emitted[PROVIDER_IMPORT_MARKER] && this.hasMarkerComment(n, TS2DART_PROVIDER_COMMENT)) { + // if 'Provider' has not been imported yet, and there's a @ts2dart_Provider, add it. + this.emit("import \"package:angular2/core.dart\" show Provider;"); + emitted[PROVIDER_IMPORT_MARKER] = true; + } + n.getChildren(sourceFile) + .forEach(function (child) { return _this.emitImports(child, libraries, emitted, sourceFile); }); + }; + FacadeConverter.prototype.pushTypeParameterNames = function (n) { + if (!n.typeParameters) + return; + this.genericMethodDeclDepth++; + }; + FacadeConverter.prototype.popTypeParameterNames = function (n) { + if (!n.typeParameters) + return; + this.genericMethodDeclDepth--; + }; + FacadeConverter.prototype.resolvePropertyTypes = function (tn) { + var res = {}; + if (!tn || !this.tc) + return res; + var t = this.tc.getTypeAtLocation(tn); + for (var _i = 0, _a = this.tc.getPropertiesOfType(t); _i < _a.length; _i++) { + var sym = _a[_i]; + var decl = sym.valueDeclaration || (sym.declarations && sym.declarations[0]); + if (decl.kind !== ts.SyntaxKind.PropertyDeclaration && + decl.kind !== ts.SyntaxKind.PropertySignature) { + var msg = this.tc.getFullyQualifiedName(sym) + + ' used for named parameter definition must be a property'; + this.reportError(decl, msg); + continue; + } + res[sym.name] = decl; + } + return res; + }; + /** + * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate + * generic methods in Dart. ts2dart has to hack around this and keep track of which type names + * in the current scope are actually DDC type parameters and need to be emitted in comments. + * + * TODO(martinprobst): Remove this once the DDC hack has made it into Dart proper. + */ + FacadeConverter.prototype.isGenericMethodTypeParameterName = function (name) { + // Avoid checking this unless needed. + if (this.genericMethodDeclDepth === 0 || !this.tc) + return false; + // Check if the type of the name is a TypeParameter. + var t = this.tc.getTypeAtLocation(name); + if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) + return false; + // Check if the symbol we're looking at is the type parameter. + var symbol = this.tc.getSymbolAtLocation(name); + if (symbol !== t.symbol) + return false; + // Check that the Type Parameter has been declared by a function declaration. + return symbol.declarations.some( + // Constructors are handled separately. + function (d) { return d.parent.kind === ts.SyntaxKind.FunctionDeclaration || + d.parent.kind === ts.SyntaxKind.MethodDeclaration || + d.parent.kind === ts.SyntaxKind.MethodSignature; }); + }; + FacadeConverter.prototype.visitTypeName = function (typeName) { + if (typeName.kind !== ts.SyntaxKind.Identifier) { + this.visit(typeName); + return; + } + var ident = base.ident(typeName); + if (this.isGenericMethodTypeParameterName(typeName)) { + // DDC generic methods hack - all names that are type parameters to generic methods have to be + // emitted in comments. + this.emit('dynamic/*='); + this.emit(ident); + this.emit('*/'); + return; + } + if (this.candidateTypes.hasOwnProperty(ident) && this.tc) { + var symbol = this.tc.getSymbolAtLocation(typeName); + if (!symbol) { + if (!this.stdlibTypeReplacements[ident]) { + this.reportMissingType(typeName, ident); + } + else { + this.emit(this.stdlibTypeReplacements[ident]); + if (ident == 'require') { + this.emitBefore('import \'dart:html\';', 'import'); + } + else if (ident == 'Math') { + this.emitBefore('import \'dart:math\' as Math;', 'import'); + } + } + return; + } + if (this.stdlibTypeReplacements[ident]) { + this.emit(this.stdlibTypeReplacements[ident]); + return; + } + var fileAndName = this.getFileAndName(typeName, symbol); + if (fileAndName) { + var fileSubs = this.tsToDartTypeNames[fileAndName.fileName]; + if (fileSubs && fileSubs.hasOwnProperty(fileAndName.qname)) { + this.emit(fileSubs[fileAndName.qname]); + return; + } + } + } + this.emit(ident); + }; + FacadeConverter.prototype.shouldEmitNew = function (c) { + if (!this.tc) + return true; + var ci = this.getCallInformation(c); + var symbol = ci.symbol; + // getCallInformation returns a symbol if we understand this call. + if (!symbol) + return true; + var loc = this.getFileAndName(c, symbol); + if (!loc) + return true; + var fileName = loc.fileName, qname = loc.qname; + var fileSubs = this.callHandlerReplaceNew[fileName]; + if (!fileSubs) + return true; + return !fileSubs[qname]; + }; + FacadeConverter.prototype.getCallInformation = function (c) { + var symbol; + var context; + var ident; + var expr = c.expression; + if (expr.kind === ts.SyntaxKind.Identifier) { + // Function call. + ident = base.ident(expr); + if (!this.candidateProperties.hasOwnProperty(ident)) + return {}; + symbol = this.tc.getSymbolAtLocation(expr); + if (!symbol) { + this.reportMissingType(c, ident); + return {}; + } + context = null; + } + else if (expr.kind === ts.SyntaxKind.PropertyAccessExpression) { + // Method call. + var pa = expr; + ident = base.ident(pa.name); + if (!this.candidateProperties.hasOwnProperty(ident)) + return {}; + symbol = this.tc.getSymbolAtLocation(pa); + // Error will be reported by PropertyAccess handling below. + if (!symbol) + return {}; + context = pa.expression; + } + return { context: context, symbol: symbol }; + }; + FacadeConverter.prototype.getHandler = function (n, symbol, m) { + var loc = this.getFileAndName(n, symbol); + if (!loc) + return null; + var fileName = loc.fileName, qname = loc.qname; + var fileSubs = m[fileName]; + if (!fileSubs) + return null; + return fileSubs[qname]; + }; + FacadeConverter.prototype.getFileAndName = function (n, originalSymbol) { + var symbol = originalSymbol; + while (symbol.flags & ts.SymbolFlags.Alias) + symbol = this.tc.getAliasedSymbol(symbol); + var decl = symbol.valueDeclaration; + if (!decl) { + // In the case of a pure declaration with no assignment, there is no value declared. + // Just grab the first declaration, hoping it is declared once. + if (!symbol.declarations || symbol.declarations.length === 0) { + this.reportError(n, 'no declarations for symbol ' + originalSymbol.name); + return null; + } + decl = symbol.declarations[0]; + } + var canonicalFileName = decl.getSourceFile().fileName.replace(/(\.d)?\.ts$/, ''); + var qname = this.tc.getFullyQualifiedName(symbol); + // Some Qualified Names include their file name. Might be a bug in TypeScript, + // for the time being just special case. + if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) { + qname = symbol.getName(); + } + if (FACADE_DEBUG) + console.error('cfn:', canonicalFileName, 'qn:', qname); + return { fileName: canonicalFileName, qname: qname }; + }; + FacadeConverter.prototype.isNamedDefaultLibType = function (node, qname) { + var symbol = this.tc.getTypeAtLocation(node).getSymbol(); + if (!symbol) + return false; + var actual = this.getFileAndName(node, symbol); + return actual.fileName === this.defaultLibLocation && qname === actual.qname; + }; + FacadeConverter.prototype.reportMissingType = function (n, ident) { + this.reportError(n, ("Untyped property access to \"" + ident + "\" which could be ") + + "a special ts2dart builtin. " + + "Please add type declarations to disambiguate."); + }; + FacadeConverter.prototype.isInsideConstExpr = function (node) { + while (node.parent) { + if (node.parent.kind === ts.SyntaxKind.Parameter && + node.parent.initializer === node) { + // initializers of parameters must be const in Dart. + return true; + } + if (this.isConstExpr(node)) + return true; + node = node.parent; + if (FacadeConverter.DECLARATIONS[node.kind]) { + // Stop walking upwards when hitting a declaration - @ts2dart_const should only propagate + // to the immediate declaration it applies to (but should be transitive in expressions). + return false; + } + } + return false; + }; + FacadeConverter.prototype.isConstClass = function (decl) { + var _this = this; + return this.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST') || + decl.members.some(function (m) { + if (m.kind !== ts.SyntaxKind.Constructor) + return false; + return _this.hasAnnotation(m.decorators, 'CONST'); + }); + }; + /** + * isConstExpr returns true if the passed in expression itself is a const expression. const + * expressions are marked by the special comment @ts2dart_const (expr), or by the special + * function call CONST_EXPR. + */ + FacadeConverter.prototype.isConstExpr = function (node) { + if (!node) + return false; + if (this.hasConstComment(node)) { + return true; + } + return node.kind === ts.SyntaxKind.CallExpression && + base.ident(node.expression) === 'CONST_EXPR'; + }; + FacadeConverter.prototype.hasConstComment = function (node) { return this.hasMarkerComment(node, '@ts2dart_const'); }; + FacadeConverter.prototype.hasMarkerComment = function (node, markerText) { + var text = node.getFullText(); + var comments = ts.getLeadingCommentRanges(text, 0); + if (!comments) + return false; + for (var _i = 0, comments_1 = comments; _i < comments_1.length; _i++) { + var c = comments_1[_i]; + var commentText = text.substring(c.pos, c.end); + if (commentText.indexOf(markerText) !== -1) { + return true; + } + } + return false; + }; + FacadeConverter.prototype.emitMethodCall = function (name, args) { + this.emit('.'); + this.emitCall(name, args); + }; + FacadeConverter.prototype.emitCall = function (name, args) { + this.emit(name); + this.emit('('); + if (args) + this.visitList(args); + this.emit(')'); + }; + FacadeConverter.DECLARATIONS = (_a = {}, + _a[ts.SyntaxKind.ClassDeclaration] = true, + _a[ts.SyntaxKind.FunctionDeclaration] = true, + _a[ts.SyntaxKind.InterfaceDeclaration] = true, + _a[ts.SyntaxKind.MethodDeclaration] = true, + _a[ts.SyntaxKind.PropertyDeclaration] = true, + _a[ts.SyntaxKind.PropertyDeclaration] = true, + _a[ts.SyntaxKind.VariableDeclaration] = true, + _a + ); + return FacadeConverter; + var _a; +}(base.TranspilerBase)); +exports.FacadeConverter = FacadeConverter; + +//# sourceMappingURL=facade_converter.js.map diff --git a/build/lib/facade_converter.js.map b/build/lib/facade_converter.js.map new file mode 100644 index 0000000..e60aa39 --- /dev/null +++ b/build/lib/facade_converter.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["facade_converter.ts"],"names":[],"mappings":"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","file":"facade_converter.js","sourcesContent":["import * as path from 'path';\nimport * as ts from 'typescript';\n\nimport * as base from './base';\nimport {Transpiler} from './main';\n\ntype CallHandler = (c: ts.CallExpression, context: ts.Expression) => void;\ntype PropertyHandler = (c: ts.PropertyAccessExpression) => void;\ntype Set = {\n [s: string]: boolean\n};\n\nconst FACADE_DEBUG = false;\n\nconst DEFAULT_LIB_MARKER = '__ts2dart_default_lib';\nconst PROVIDER_IMPORT_MARKER = '__ts2dart_has_provider_import';\nconst TS2DART_PROVIDER_COMMENT = '@ts2dart_Provider';\n\nfunction merge(...args: {[key: string]: any}[]): {[key: string]: any} {\n let returnObject: {[key: string]: any} = {};\n for (let arg of args) {\n for (let key of Object.getOwnPropertyNames(arg)) {\n returnObject[key] = arg[key];\n }\n }\n return returnObject;\n}\n\nexport class FacadeConverter extends base.TranspilerBase {\n private tc: ts.TypeChecker;\n private defaultLibLocation: string;\n private candidateProperties: {[propertyName: string]: boolean} = {};\n private candidateTypes: {[typeName: string]: boolean} = {};\n private genericMethodDeclDepth = 0;\n\n constructor(transpiler: Transpiler) {\n super(transpiler);\n\n this.extractPropertyNames(this.callHandlers, this.candidateProperties);\n this.extractPropertyNames(this.propertyHandlers, this.candidateProperties);\n this.extractPropertyNames(this.tsToDartTypeNames, this.candidateTypes);\n }\n\n initializeTypeBasedConversion(\n tc: ts.TypeChecker, opts: ts.CompilerOptions, host: ts.CompilerHost) {\n this.tc = tc;\n this.defaultLibLocation = ts.getDefaultLibFilePath(opts).replace(/\\.d\\.ts$/, '');\n this.resolveModuleNames(opts, host, this.callHandlers);\n this.resolveModuleNames(opts, host, this.propertyHandlers);\n this.resolveModuleNames(opts, host, this.tsToDartTypeNames);\n this.resolveModuleNames(opts, host, this.callHandlerReplaceNew);\n }\n\n private extractPropertyNames(m: ts.Map>, candidates: {[k: string]: boolean}) {\n for (let fileName of Object.keys(m)) {\n const file = m[fileName];\n Object.keys(file)\n .map((propName) => propName.substring(propName.lastIndexOf('.') + 1))\n .forEach((propName) => candidates[propName] = true);\n }\n }\n\n private resolveModuleNames(\n opts: ts.CompilerOptions, host: ts.CompilerHost, m: ts.Map>) {\n for (let mn of Object.keys(m)) {\n let actual: string;\n let absolute: string;\n if (mn === DEFAULT_LIB_MARKER) {\n actual = this.defaultLibLocation;\n } else {\n let resolved = ts.resolveModuleName(mn, '', opts, host);\n if (!resolved.resolvedModule) continue;\n actual = resolved.resolvedModule.resolvedFileName.replace(/(\\.d)?\\.ts$/, '');\n // TypeScript's resolution returns relative paths here, but uses absolute ones in\n // SourceFile.fileName later. Make sure to hit both use cases.\n absolute = path.resolve(actual);\n }\n if (FACADE_DEBUG) console.log('Resolved module', mn, '->', actual);\n m[actual] = m[mn];\n if (absolute) m[absolute] = m[mn];\n }\n }\n\n /**\n * To avoid strongly referencing the Provider class (which could bloat binary size), Angular 2\n * write providers as object literals. However the Dart transformers don't recognize this, so\n * ts2dart translates the special syntax `/* @ts2dart_Provider * / {provide: Class, param1: ...}`\n * into `const Provider(Class, param1: ...)`.\n */\n maybeHandleProvider(ole: ts.ObjectLiteralExpression): boolean {\n if (!this.hasMarkerComment(ole, TS2DART_PROVIDER_COMMENT)) return false;\n let classParam: ts.Expression;\n let remaining = ole.properties.filter((e) => {\n if (e.kind !== ts.SyntaxKind.PropertyAssignment) {\n this.reportError(e, TS2DART_PROVIDER_COMMENT + ' elements must be property assignments');\n }\n if ('provide' === base.ident(e.name)) {\n classParam = (e as ts.PropertyAssignment).initializer;\n return false;\n }\n return true; // include below.\n });\n\n if (!classParam) {\n this.reportError(ole, 'missing provide: element');\n return false;\n }\n\n this.emit('const Provider(');\n this.visit(classParam);\n if (remaining.length > 0) {\n this.emit(',');\n for (let i = 0; i < remaining.length; i++) {\n let e = remaining[i];\n if (e.kind !== ts.SyntaxKind.PropertyAssignment) this.visit(e.name);\n this.emit(base.ident(e.name));\n this.emit(':');\n this.visit((e as ts.PropertyAssignment).initializer);\n if ((i + 1) < remaining.length) this.emit(',');\n }\n this.emit(')');\n }\n return true;\n }\n\n maybeHandleCall(c: ts.CallExpression): boolean {\n if (!this.tc) return false;\n let {context, symbol} = this.getCallInformation(c);\n if (!symbol) {\n // getCallInformation returns a symbol if we understand this call.\n return false;\n }\n let handler = this.getHandler(c, symbol, this.callHandlers);\n return handler && !handler(c, context);\n }\n\n handlePropertyAccess(pa: ts.PropertyAccessExpression): boolean {\n if (!this.tc) return;\n let ident = pa.name.text;\n if (!this.candidateProperties.hasOwnProperty(ident)) return false;\n let symbol = this.tc.getSymbolAtLocation(pa.name);\n if (!symbol) {\n if (!this.stdlibTypeReplacements[ident]) {\n this.reportMissingType(pa, ident);\n }\n return false;\n }\n\n let handler = this.getHandler(pa, symbol, this.propertyHandlers);\n return handler && !handler(pa);\n }\n\n /**\n * Searches for type references that require extra imports and emits the imports as necessary.\n */\n emitExtraImports(sourceFile: ts.SourceFile) {\n let libraries = >{\n 'XMLHttpRequest': 'dart:html',\n 'KeyboardEvent': 'dart:html',\n 'Uint8Array': 'dart:typed_arrays',\n 'ArrayBuffer': 'dart:typed_arrays',\n 'Promise': 'dart:async',\n 'HttpRequest.getString': 'dart:html',\n };\n let emitted: Set = {};\n this.emitImports(sourceFile, libraries, emitted, sourceFile);\n }\n\n private emitImports(\n n: ts.Node, libraries: ts.Map, emitted: Set, sourceFile: ts.SourceFile): void {\n if (n.kind === ts.SyntaxKind.TypeReference) {\n let type = base.ident((n).typeName);\n if (libraries.hasOwnProperty(type)) {\n let toEmit = libraries[type];\n if (!emitted[toEmit]) {\n this.emit(`import '${toEmit}';`);\n emitted[toEmit] = true;\n }\n }\n }\n\n // Support for importing \"Provider\" in case /* @ts2dart_Provider */ comments are present.\n if (n.kind === ts.SyntaxKind.ImportDeclaration) {\n // See if there is already code importing 'Provider' from angular2/core.\n let id = n as ts.ImportDeclaration;\n if ((id.moduleSpecifier as ts.StringLiteral).text === 'angular2/core') {\n if (id.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) {\n let ni = id.importClause.namedBindings as ts.NamedImports;\n for (let nb of ni.elements) {\n if (base.ident(nb.name) === 'Provider') {\n emitted[PROVIDER_IMPORT_MARKER] = true;\n break;\n }\n }\n }\n }\n }\n\n if (!emitted[PROVIDER_IMPORT_MARKER] && this.hasMarkerComment(n, TS2DART_PROVIDER_COMMENT)) {\n // if 'Provider' has not been imported yet, and there's a @ts2dart_Provider, add it.\n this.emit(`import \"package:angular2/core.dart\" show Provider;`);\n emitted[PROVIDER_IMPORT_MARKER] = true;\n }\n\n n.getChildren(sourceFile)\n .forEach((child: ts.Node) => this.emitImports(child, libraries, emitted, sourceFile));\n }\n\n pushTypeParameterNames(n: ts.FunctionLikeDeclaration) {\n if (!n.typeParameters) return;\n this.genericMethodDeclDepth++;\n }\n\n popTypeParameterNames(n: ts.FunctionLikeDeclaration) {\n if (!n.typeParameters) return;\n this.genericMethodDeclDepth--;\n }\n\n resolvePropertyTypes(tn: ts.TypeNode): ts.Map {\n let res: ts.Map = {};\n if (!tn || !this.tc) return res;\n\n let t = this.tc.getTypeAtLocation(tn);\n for (let sym of this.tc.getPropertiesOfType(t)) {\n let decl = sym.valueDeclaration || (sym.declarations && sym.declarations[0]);\n if (decl.kind !== ts.SyntaxKind.PropertyDeclaration &&\n decl.kind !== ts.SyntaxKind.PropertySignature) {\n let msg = this.tc.getFullyQualifiedName(sym) +\n ' used for named parameter definition must be a property';\n this.reportError(decl, msg);\n continue;\n }\n res[sym.name] = decl;\n }\n return res;\n }\n\n /**\n * The Dart Development Compiler (DDC) has a syntax extension that uses comments to emulate\n * generic methods in Dart. ts2dart has to hack around this and keep track of which type names\n * in the current scope are actually DDC type parameters and need to be emitted in comments.\n *\n * TODO(martinprobst): Remove this once the DDC hack has made it into Dart proper.\n */\n private isGenericMethodTypeParameterName(name: ts.EntityName): boolean {\n // Avoid checking this unless needed.\n if (this.genericMethodDeclDepth === 0 || !this.tc) return false;\n // Check if the type of the name is a TypeParameter.\n let t = this.tc.getTypeAtLocation(name);\n if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false;\n\n // Check if the symbol we're looking at is the type parameter.\n let symbol = this.tc.getSymbolAtLocation(name);\n if (symbol !== t.symbol) return false;\n\n // Check that the Type Parameter has been declared by a function declaration.\n return symbol.declarations.some(\n // Constructors are handled separately.\n d => d.parent.kind === ts.SyntaxKind.FunctionDeclaration ||\n d.parent.kind === ts.SyntaxKind.MethodDeclaration ||\n d.parent.kind === ts.SyntaxKind.MethodSignature);\n }\n\n visitTypeName(typeName: ts.EntityName) {\n if (typeName.kind !== ts.SyntaxKind.Identifier) {\n this.visit(typeName);\n return;\n }\n let ident = base.ident(typeName);\n if (this.isGenericMethodTypeParameterName(typeName)) {\n // DDC generic methods hack - all names that are type parameters to generic methods have to be\n // emitted in comments.\n this.emit('dynamic/*=');\n this.emit(ident);\n this.emit('*/');\n return;\n }\n\n if (this.candidateTypes.hasOwnProperty(ident) && this.tc) {\n let symbol = this.tc.getSymbolAtLocation(typeName);\n if (!symbol) {\n if (!this.stdlibTypeReplacements[ident]) {\n this.reportMissingType(typeName, ident);\n } else {\n this.emit(this.stdlibTypeReplacements[ident]);\n if (ident == 'require') {\n this.emitBefore('import \\'dart:html\\';', 'import');\n } else if (ident == 'Math') {\n this.emitBefore('import \\'dart:math\\' as Math;', 'import');\n }\n }\n return;\n }\n if (this.stdlibTypeReplacements[ident]) {\n this.emit(this.stdlibTypeReplacements[ident]);\n return;\n }\n let fileAndName = this.getFileAndName(typeName, symbol);\n if (fileAndName) {\n let fileSubs = this.tsToDartTypeNames[fileAndName.fileName];\n if (fileSubs && fileSubs.hasOwnProperty(fileAndName.qname)) {\n this.emit(fileSubs[fileAndName.qname]);\n return;\n }\n }\n }\n this.emit(ident);\n }\n\n shouldEmitNew(c: ts.CallExpression): boolean {\n if (!this.tc) return true;\n\n let ci = this.getCallInformation(c);\n let symbol = ci.symbol;\n // getCallInformation returns a symbol if we understand this call.\n if (!symbol) return true;\n\n let loc = this.getFileAndName(c, symbol);\n if (!loc) return true;\n let {fileName, qname} = loc;\n let fileSubs = this.callHandlerReplaceNew[fileName];\n if (!fileSubs) return true;\n return !fileSubs[qname];\n }\n\n private getCallInformation(c: ts.CallExpression): {context?: ts.Expression, symbol?: ts.Symbol} {\n let symbol: ts.Symbol;\n let context: ts.Expression;\n let ident: string;\n let expr = c.expression;\n\n if (expr.kind === ts.SyntaxKind.Identifier) {\n // Function call.\n ident = base.ident(expr);\n if (!this.candidateProperties.hasOwnProperty(ident)) return {};\n symbol = this.tc.getSymbolAtLocation(expr);\n\n if (!symbol) {\n this.reportMissingType(c, ident);\n return {};\n }\n\n context = null;\n } else if (expr.kind === ts.SyntaxKind.PropertyAccessExpression) {\n // Method call.\n let pa = expr;\n ident = base.ident(pa.name);\n if (!this.candidateProperties.hasOwnProperty(ident)) return {};\n\n symbol = this.tc.getSymbolAtLocation(pa);\n\n // Error will be reported by PropertyAccess handling below.\n if (!symbol) return {};\n\n context = pa.expression;\n }\n return {context, symbol};\n }\n\n private getHandler(n: ts.Node, symbol: ts.Symbol, m: ts.Map>): T {\n let loc = this.getFileAndName(n, symbol);\n if (!loc) return null;\n let {fileName, qname} = loc;\n let fileSubs = m[fileName];\n if (!fileSubs) return null;\n return fileSubs[qname];\n }\n\n private getFileAndName(n: ts.Node, originalSymbol: ts.Symbol): {fileName: string, qname: string} {\n let symbol = originalSymbol;\n while (symbol.flags & ts.SymbolFlags.Alias) symbol = this.tc.getAliasedSymbol(symbol);\n let decl = symbol.valueDeclaration;\n if (!decl) {\n // In the case of a pure declaration with no assignment, there is no value declared.\n // Just grab the first declaration, hoping it is declared once.\n if (!symbol.declarations || symbol.declarations.length === 0) {\n this.reportError(n, 'no declarations for symbol ' + originalSymbol.name);\n return null;\n }\n decl = symbol.declarations[0];\n }\n\n const canonicalFileName = decl.getSourceFile().fileName.replace(/(\\.d)?\\.ts$/, '');\n\n let qname = this.tc.getFullyQualifiedName(symbol);\n // Some Qualified Names include their file name. Might be a bug in TypeScript,\n // for the time being just special case.\n if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.SymbolFlags.Variable)) {\n qname = symbol.getName();\n }\n if (FACADE_DEBUG) console.error('cfn:', canonicalFileName, 'qn:', qname);\n return {fileName: canonicalFileName, qname};\n }\n\n private isNamedDefaultLibType(node: ts.Node, qname: string): boolean {\n let symbol = this.tc.getTypeAtLocation(node).getSymbol();\n if (!symbol) return false;\n let actual = this.getFileAndName(node, symbol);\n return actual.fileName === this.defaultLibLocation && qname === actual.qname;\n }\n\n private reportMissingType(n: ts.Node, ident: string) {\n this.reportError(\n n, `Untyped property access to \"${ident}\" which could be ` +\n `a special ts2dart builtin. ` +\n `Please add type declarations to disambiguate.`);\n }\n\n private static DECLARATIONS: {[k: number]: boolean} = {\n [ts.SyntaxKind.ClassDeclaration]: true,\n [ts.SyntaxKind.FunctionDeclaration]: true,\n [ts.SyntaxKind.InterfaceDeclaration]: true,\n [ts.SyntaxKind.MethodDeclaration]: true,\n [ts.SyntaxKind.PropertyDeclaration]: true,\n [ts.SyntaxKind.PropertyDeclaration]: true,\n [ts.SyntaxKind.VariableDeclaration]: true,\n };\n\n isInsideConstExpr(node: ts.Node): boolean {\n while (node.parent) {\n if (node.parent.kind === ts.SyntaxKind.Parameter &&\n (node.parent as ts.ParameterDeclaration).initializer === node) {\n // initializers of parameters must be const in Dart.\n return true;\n }\n if (this.isConstExpr(node)) return true;\n node = node.parent;\n if (FacadeConverter.DECLARATIONS[node.kind]) {\n // Stop walking upwards when hitting a declaration - @ts2dart_const should only propagate\n // to the immediate declaration it applies to (but should be transitive in expressions).\n return false;\n }\n }\n return false;\n }\n\n isConstClass(decl: base.ClassLike) {\n return this.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST') ||\n (>decl.members).some((m) => {\n if (m.kind !== ts.SyntaxKind.Constructor) return false;\n return this.hasAnnotation(m.decorators, 'CONST');\n });\n }\n\n /**\n * isConstExpr returns true if the passed in expression itself is a const expression. const\n * expressions are marked by the special comment @ts2dart_const (expr), or by the special\n * function call CONST_EXPR.\n */\n isConstExpr(node: ts.Node): boolean {\n if (!node) return false;\n\n if (this.hasConstComment(node)) {\n return true;\n }\n\n return node.kind === ts.SyntaxKind.CallExpression &&\n base.ident((node).expression) === 'CONST_EXPR';\n }\n\n hasConstComment(node: ts.Node): boolean { return this.hasMarkerComment(node, '@ts2dart_const'); }\n\n private hasMarkerComment(node: ts.Node, markerText: string): boolean {\n let text = node.getFullText();\n let comments = ts.getLeadingCommentRanges(text, 0);\n if (!comments) return false;\n for (let c of comments) {\n let commentText = text.substring(c.pos, c.end);\n if (commentText.indexOf(markerText) !== -1) {\n return true;\n }\n }\n return false;\n }\n\n private emitMethodCall(name: string, args?: ts.Expression[]) {\n this.emit('.');\n this.emitCall(name, args);\n }\n\n private emitCall(name: string, args?: ts.Expression[]) {\n this.emit(name);\n this.emit('(');\n if (args) this.visitList(args);\n this.emit(')');\n }\n\n private stdlibTypeReplacements: ts.Map = {\n 'Date': 'DateTime',\n 'Array': 'List',\n 'XMLHttpRequest': 'HttpRequest',\n 'Uint8Array': 'Uint8List',\n 'ArrayBuffer': 'ByteBuffer',\n 'Promise': 'Future',\n 'undefined': 'null',\n 'replace': 'replaceFirst',\n 'require': 'HttpRequest.getString',\n 'then': 'then',\n 'Object': 'Map',\n 'parseFloat': 'double.parse',\n 'parseInt': 'int.parse',\n 'Math': 'Math',\n\n // Dart has two different incompatible DOM APIs\n // https://github.com/angular/angular/issues/2770\n 'Node': 'dynamic',\n 'Text': 'dynamic',\n 'Element': 'dynamic',\n 'Event': 'dynamic',\n 'HTMLElement': 'dynamic',\n 'HTMLAnchorElement': 'dynamic',\n 'HTMLStyleElement': 'dynamic',\n 'HTMLInputElement': 'dynamic',\n 'HTMLDocument': 'dynamic',\n 'History': 'dynamic',\n 'Location': 'dynamic',\n };\n\n private tsToDartTypeNames: ts.Map> = {\n [DEFAULT_LIB_MARKER]: this.stdlibTypeReplacements,\n 'angular2/src/facade/lang': {'Date': 'DateTime'},\n\n 'rxjs/Observable': {'Observable': 'Stream'},\n 'es6-promise/es6-promise': {'Promise': 'Future'},\n 'es6-shim/es6-shim': {'Promise': 'Future'},\n };\n\n private es6Promises: ts.Map = {\n 'Promise.catch': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emit('.catchError(');\n this.visitList(c.arguments);\n this.emit(')');\n },\n 'Promise.then': (c: ts.CallExpression, context: ts.Expression) => {\n // then() in Dart doesn't support 2 arguments.\n this.visit(context);\n this.emit('.then(');\n this.visit(c.arguments[0]);\n this.emit(')');\n if (c.arguments.length > 1) {\n this.emit('.catchError(');\n this.visit(c.arguments[1]);\n this.emit(')');\n }\n },\n 'Promise': (c: ts.CallExpression, context: ts.Expression) => {\n if (c.kind !== ts.SyntaxKind.NewExpression) return true;\n this.assert(c, c.arguments.length === 1, 'Promise construction must take 2 arguments.');\n this.assert(\n c, c.arguments[0].kind === ts.SyntaxKind.ArrowFunction ||\n c.arguments[0].kind === ts.SyntaxKind.FunctionExpression,\n 'Promise argument must be a function expression (or arrow function).');\n let callback: ts.FunctionLikeDeclaration;\n if (c.arguments[0].kind === ts.SyntaxKind.ArrowFunction) {\n callback = (c.arguments[0]);\n } else if (c.arguments[0].kind === ts.SyntaxKind.FunctionExpression) {\n callback = (c.arguments[0]);\n }\n this.assert(\n c, callback.parameters.length > 0 && callback.parameters.length < 3,\n 'Promise executor must take 1 or 2 arguments (resolve and reject).');\n\n const completerVarName = this.uniqueId('completer');\n this.assert(\n c, callback.parameters[0].name.kind === ts.SyntaxKind.Identifier,\n 'First argument of the Promise executor is not a straight parameter.');\n let resolveParameterIdent = (callback.parameters[0].name);\n\n this.emit('(() {'); // Create a new scope.\n this.emit(`Completer ${completerVarName} = new Completer();`);\n this.emit('var');\n this.emit(resolveParameterIdent.text);\n this.emit(`= ${completerVarName}.complete;`);\n\n if (callback.parameters.length === 2) {\n this.assert(\n c, callback.parameters[1].name.kind === ts.SyntaxKind.Identifier,\n 'First argument of the Promise executor is not a straight parameter.');\n let rejectParameterIdent = (callback.parameters[1].name);\n this.emit('var');\n this.emit(rejectParameterIdent.text);\n this.emit(`= ${completerVarName}.completeError;`);\n }\n this.emit('(()');\n this.visit(callback.body);\n this.emit(')();');\n this.emit(`return ${completerVarName}.future;`);\n this.emit('})()');\n },\n };\n\n private es6Collections: ts.Map = {\n 'Map.set': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emit('[');\n this.visit(c.arguments[0]);\n this.emit(']');\n this.emit('=');\n this.visit(c.arguments[1]);\n },\n 'Map.get': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emit('[');\n this.visit(c.arguments[0]);\n this.emit(']');\n },\n 'Map.has': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('containsKey', c.arguments);\n },\n 'Map.delete': (c: ts.CallExpression, context: ts.Expression) => {\n // JS Map.delete(k) returns whether k was present in the map,\n // convert to:\n // (Map.containsKey(k) && (Map.remove(k) !== null || true))\n // (Map.remove(k) !== null || true) is required to always returns true\n // when Map.containsKey(k)\n this.emit('(');\n this.visit(context);\n this.emitMethodCall('containsKey', c.arguments);\n this.emit('&& (');\n this.visit(context);\n this.emitMethodCall('remove', c.arguments);\n this.emit('!= null || true ) )');\n },\n 'Map.forEach': (c: ts.CallExpression, context: ts.Expression) => {\n let cb: any;\n let params: any;\n\n switch (c.arguments[0].kind) {\n case ts.SyntaxKind.FunctionExpression:\n cb = (c.arguments[0]);\n params = cb.parameters;\n if (params.length !== 2) {\n this.reportError(c, 'Map.forEach callback requires exactly two arguments');\n return;\n }\n this.visit(context);\n this.emit('. forEach ( (');\n this.visit(params[1]);\n this.emit(',');\n this.visit(params[0]);\n this.emit(')');\n this.visit(cb.body);\n this.emit(')');\n break;\n\n case ts.SyntaxKind.ArrowFunction:\n cb = (c.arguments[0]);\n params = cb.parameters;\n if (params.length !== 2) {\n this.reportError(c, 'Map.forEach callback requires exactly two arguments');\n return;\n }\n this.visit(context);\n this.emit('. forEach ( (');\n this.visit(params[1]);\n this.emit(',');\n this.visit(params[0]);\n this.emit(')');\n if (cb.body.kind !== ts.SyntaxKind.Block) {\n this.emit('=>');\n }\n this.visit(cb.body);\n this.emit(')');\n break;\n\n default:\n this.visit(context);\n this.emit('. forEach ( ( k , v ) => (');\n this.visit(c.arguments[0]);\n this.emit(') ( v , k ) )');\n break;\n }\n },\n 'Array.find': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emit('. firstWhere (');\n this.visit(c.arguments[0]);\n this.emit(', orElse : ( ) => null )');\n },\n };\n\n private stdlibHandlers: ts.Map = merge(this.es6Promises, this.es6Collections, {\n 'Array.push': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('add', c.arguments);\n },\n 'Array.pop': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('removeLast');\n },\n 'Array.shift': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emit('. removeAt ( 0 )');\n },\n 'Array.unshift': (c: ts.CallExpression, context: ts.Expression) => {\n this.emit('(');\n this.visit(context);\n if (c.arguments.length === 1) {\n this.emit('.. insert ( 0,');\n this.visit(c.arguments[0]);\n this.emit(') ) . length');\n } else {\n this.emit('.. insertAll ( 0, [');\n this.visitList(c.arguments);\n this.emit(']) ) . length');\n }\n },\n 'Array.map': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('map', c.arguments);\n this.emitMethodCall('toList');\n },\n 'Array.filter': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('where', c.arguments);\n this.emitMethodCall('toList');\n },\n 'Array.some': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('any', c.arguments);\n },\n 'Array.slice': (c: ts.CallExpression, context: ts.Expression) => {\n this.emitCall('ListWrapper.slice', [context, ...c.arguments]);\n },\n 'Array.splice': (c: ts.CallExpression, context: ts.Expression) => {\n this.emitCall('ListWrapper.splice', [context, ...c.arguments]);\n },\n 'Array.concat': (c: ts.CallExpression, context: ts.Expression) => {\n this.emit('( new List . from (');\n this.visit(context);\n this.emit(')');\n c.arguments.forEach(arg => {\n if (!this.isNamedDefaultLibType(arg, 'Array')) {\n this.reportError(arg, 'Array.concat only takes Array arguments');\n }\n this.emit('.. addAll (');\n this.visit(arg);\n this.emit(')');\n });\n this.emit(')');\n },\n 'Array.join': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n if (c.arguments.length) {\n this.emitMethodCall('join', c.arguments);\n } else {\n this.emit('. join ( \",\" )');\n }\n },\n 'Array.reduce': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n\n if (c.arguments.length >= 2) {\n this.emitMethodCall('fold', [c.arguments[1], c.arguments[0]]);\n } else {\n this.emit('. fold ( null ,');\n this.visit(c.arguments[0]);\n this.emit(')');\n }\n },\n 'ArrayConstructor.isArray': (c: ts.CallExpression, context: ts.Expression) => {\n this.emit('( (');\n this.visitList(c.arguments); // Should only be 1.\n this.emit(')');\n this.emit('is List');\n this.emit(')');\n },\n 'Console.log': (c: ts.CallExpression, context: ts.Expression) => {\n this.emit('print(');\n if (c.arguments.length === 1) {\n this.visit(c.arguments[0]);\n } else {\n this.emit('[');\n this.visitList(c.arguments);\n this.emit('].join(\" \")');\n }\n this.emit(')');\n },\n 'RegExp.exec': (c: ts.CallExpression, context: ts.Expression) => {\n if (context.kind !== ts.SyntaxKind.RegularExpressionLiteral) {\n // Fail if the exec call isn't made directly on a regexp literal.\n // Multiple exec calls on the same global regexp have side effects\n // (each return the next match), which we can't reproduce with a simple\n // Dart RegExp (users should switch to some facade / wrapper instead).\n this.reportError(\n c, 'exec is only supported on regexp literals, ' +\n 'to avoid side-effect of multiple calls on global regexps.');\n }\n if (c.parent.kind === ts.SyntaxKind.ElementAccessExpression) {\n // The result of the exec call is used for immediate indexed access:\n // this use-case can be accommodated by RegExp.firstMatch, which returns\n // a Match instance with operator[] which returns groups (special index\n // 0 returns the full text of the match).\n this.visit(context);\n this.emitMethodCall('firstMatch', c.arguments);\n } else {\n // In the general case, we want to return a List. To transform a Match\n // into a List of its groups, we alias it in a local closure that we\n // call with the Match value. We are then able to use the group method\n // to generate a List large enough to hold groupCount groups + the\n // full text of the match at special group index 0.\n this.emit('((match) => new List.generate(1 + match.groupCount, match.group))(');\n this.visit(context);\n this.emitMethodCall('firstMatch', c.arguments);\n this.emit(')');\n }\n },\n 'RegExp.test': (c: ts.CallExpression, context: ts.Expression) => {\n this.visit(context);\n this.emitMethodCall('hasMatch', c.arguments);\n },\n 'String.substr': (c: ts.CallExpression, context: ts.Expression) => {\n this.reportError(\n c, 'substr is unsupported, use substring (but beware of the different semantics!)');\n this.visit(context);\n this.emitMethodCall('substr', c.arguments);\n },\n });\n\n private callHandlerReplaceNew: ts.Map> = {\n [DEFAULT_LIB_MARKER]: {'Promise': true},\n };\n\n private callHandlers: ts.Map> = {\n [DEFAULT_LIB_MARKER]: this.stdlibHandlers,\n 'angular2/manual_typings/globals': this.es6Collections,\n 'angular2/src/facade/collection': {\n 'Map': (c: ts.CallExpression, context: ts.Expression): boolean => {\n // The actual Map constructor is special cased for const calls.\n if (!this.isInsideConstExpr(c)) return true;\n if (c.arguments.length) {\n this.reportError(c, 'Arguments on a Map constructor in a const are unsupported');\n }\n if (c.typeArguments) {\n this.emit('<');\n this.visitList(c.typeArguments);\n this.emit('>');\n }\n this.emit('{ }');\n return false;\n },\n },\n 'angular2/src/core/di/forward_ref': {\n 'forwardRef': (c: ts.CallExpression, context: ts.Expression) => {\n // The special function forwardRef translates to an unwrapped value in Dart.\n const callback = c.arguments[0];\n if (callback.kind !== ts.SyntaxKind.ArrowFunction) {\n this.reportError(c, 'forwardRef takes only arrow functions');\n return;\n }\n this.visit(callback.body);\n },\n },\n 'angular2/src/facade/lang': {\n 'CONST_EXPR': (c: ts.CallExpression, context: ts.Expression) => {\n // `const` keyword is emitted in the array literal handling, as it needs to be transitive.\n this.visitList(c.arguments);\n },\n 'normalizeBlank': (c: ts.CallExpression, context: ts.Expression) => {\n // normalizeBlank is a noop in Dart, so erase it.\n this.visitList(c.arguments);\n },\n },\n };\n\n private es6CollectionsProp: ts.Map = {\n 'Map.size': (p: ts.PropertyAccessExpression) => {\n this.visit(p.expression);\n this.emit('.');\n this.emit('length');\n },\n };\n private es6PromisesProp: ts.Map = {\n 'PromiseConstructor.resolve': (p: ts.PropertyAccessExpression) => {\n this.emit('new ');\n this.visit(p.expression);\n this.emit('.value');\n },\n 'PromiseConstructor.reject': (p: ts.PropertyAccessExpression) => {\n this.emit('new ');\n this.visit(p.expression);\n this.emit('.error');\n },\n };\n\n private propertyHandlers: ts.Map> = {\n [DEFAULT_LIB_MARKER]: merge(this.es6CollectionsProp, this.es6PromisesProp),\n };\n}\n"]} \ No newline at end of file diff --git a/build/lib/literal.js b/build/lib/literal.js new file mode 100644 index 0000000..fcb553a --- /dev/null +++ b/build/lib/literal.js @@ -0,0 +1,180 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var LiteralTranspiler = (function (_super) { + __extends(LiteralTranspiler, _super); + function LiteralTranspiler(tr, fc) { + _super.call(this, tr); + this.fc = fc; + } + LiteralTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + // Literals. + case ts.SyntaxKind.NumericLiteral: + var nLit = node; + this.emit(nLit.getText()); + break; + case ts.SyntaxKind.StringLiteral: + var sLit = node; + var text = JSON.stringify(sLit.text); + // Escape dollar sign since dart will interpolate in double quoted literal + text = text.replace(/\$/, '\\$'); + this.emit(text); + break; + case ts.SyntaxKind.NoSubstitutionTemplateLiteral: + this.emit("'''" + this.escapeTextForTemplateString(node) + "'''"); + break; + case ts.SyntaxKind.TemplateMiddle: + this.emitNoSpace(this.escapeTextForTemplateString(node)); + break; + case ts.SyntaxKind.TemplateExpression: + var tmpl = node; + if (tmpl.head) + this.visit(tmpl.head); + if (tmpl.templateSpans) + this.visitEach(tmpl.templateSpans); + break; + case ts.SyntaxKind.TemplateHead: + this.emit("'''" + this.escapeTextForTemplateString(node)); // highlighting bug:' + break; + case ts.SyntaxKind.TemplateTail: + this.emitNoSpace(this.escapeTextForTemplateString(node)); + this.emitNoSpace("'''"); + break; + case ts.SyntaxKind.TemplateSpan: + var span = node; + if (span.expression) { + // Do not emit extra whitespace inside the string template + this.emitNoSpace('${'); + this.visit(span.expression); + this.emitNoSpace('}'); + } + if (span.literal) + this.visit(span.literal); + break; + case ts.SyntaxKind.ArrayLiteralExpression: + if (this.shouldBeConst(node)) + this.emit('const'); + var ale = node; + this.handleReifiedArray(ale); + this.emit('['); + this.visitList(ale.elements); + this.emit(']'); + break; + case ts.SyntaxKind.ObjectLiteralExpression: + var ole = node; + if (this.fc.maybeHandleProvider(ole)) + return true; + if (this.shouldBeConst(node)) + this.emit('const'); + this.handleReifiedMap(ole); + this.emit('{'); + this.visitList(ole.properties); + this.emit('}'); + break; + case ts.SyntaxKind.PropertyAssignment: + var propAssign = node; + if (propAssign.name.kind === ts.SyntaxKind.Identifier) { + // Dart identifiers in Map literals need quoting. + this.emitNoSpace(' \''); + this.emitNoSpace(propAssign.name.text); + this.emitNoSpace('\''); + } + else { + this.visit(propAssign.name); + } + this.emit(':'); + this.visit(propAssign.initializer); + break; + case ts.SyntaxKind.ShorthandPropertyAssignment: + var shorthand = node; + this.emitNoSpace(' \''); + this.emitNoSpace(shorthand.name.text); + this.emitNoSpace('\''); + this.emit(':'); + this.visit(shorthand.name); + break; + case ts.SyntaxKind.TrueKeyword: + this.emit('true'); + break; + case ts.SyntaxKind.FalseKeyword: + this.emit('false'); + break; + case ts.SyntaxKind.NullKeyword: + this.emit('null'); + break; + case ts.SyntaxKind.RegularExpressionLiteral: + this.emit('new RegExp ('); + this.emit('r\''); + var regExp = node.text; + var slashIdx = regExp.lastIndexOf('/'); + var flags = regExp.substring(slashIdx + 1); + regExp = regExp.substring(1, slashIdx); // cut off /.../ chars. + regExp = regExp.replace(/'/g, '\' + "\'" + r\''); // handle nested quotes by concatenation. + this.emitNoSpace(regExp); + this.emitNoSpace('\''); + if (flags.indexOf('g') === -1) { + // Dart RegExps are always global, so JS regexps must use 'g' so that semantics match. + this.reportError(node, 'Regular Expressions must use the //g flag'); + } + if (flags.indexOf('m') !== -1) { + this.emit(', multiLine: true'); + } + if (flags.indexOf('i') !== -1) { + this.emit(', caseSensitive: false'); + } + this.emit(')'); + break; + case ts.SyntaxKind.ThisKeyword: + this.emit('this'); + break; + default: + return false; + } + return true; + }; + LiteralTranspiler.prototype.shouldBeConst = function (n) { + return this.hasAncestor(n, ts.SyntaxKind.Decorator) || this.fc.isInsideConstExpr(n); + }; + LiteralTranspiler.prototype.escapeTextForTemplateString = function (n) { + return n.text.replace(/\\/g, '\\\\').replace(/([$'])/g, '\\$1'); + }; + LiteralTranspiler.prototype.handleReifiedArray = function (node) { + if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) + return; + var ta = node.parent; + if (ta.type.kind !== ts.SyntaxKind.ArrayType) + return; + this.emit('<'); + this.visit(ta.type.elementType); + this.emit('>'); + return true; + }; + LiteralTranspiler.prototype.handleReifiedMap = function (node) { + if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) + return; + var ta = node.parent; + if (ta.type.kind !== ts.SyntaxKind.TypeLiteral) + return; + var it = this.maybeDestructureIndexType(ta.type); + if (!it) { + this.reportError(node, 'expected {[k]: v} type on object literal'); + return; + } + this.emit('<'); + this.visit(it[0]); + this.emit(','); + this.visit(it[1]); + this.emit('>'); + }; + return LiteralTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = LiteralTranspiler; + +//# sourceMappingURL=literal.js.map diff --git a/build/lib/literal.js.map b/build/lib/literal.js.map new file mode 100644 index 0000000..657012e --- /dev/null +++ b/build/lib/literal.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["literal.ts"],"names":[],"mappings":"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","file":"literal.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class LiteralTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n // Literals.\n case ts.SyntaxKind.NumericLiteral:\n let nLit = node;\n this.emit(nLit.getText());\n break;\n case ts.SyntaxKind.StringLiteral:\n let sLit = node;\n let text = JSON.stringify(sLit.text);\n // Escape dollar sign since dart will interpolate in double quoted literal\n text = text.replace(/\\$/, '\\\\$');\n this.emit(text);\n break;\n case ts.SyntaxKind.NoSubstitutionTemplateLiteral:\n this.emit(`'''${this.escapeTextForTemplateString(node)}'''`);\n break;\n case ts.SyntaxKind.TemplateMiddle:\n this.emitNoSpace(this.escapeTextForTemplateString(node));\n break;\n case ts.SyntaxKind.TemplateExpression:\n let tmpl = node;\n if (tmpl.head) this.visit(tmpl.head);\n if (tmpl.templateSpans) this.visitEach(tmpl.templateSpans);\n break;\n case ts.SyntaxKind.TemplateHead:\n this.emit(`'''${this.escapeTextForTemplateString(node)}`); // highlighting bug:'\n break;\n case ts.SyntaxKind.TemplateTail:\n this.emitNoSpace(this.escapeTextForTemplateString(node));\n this.emitNoSpace(`'''`);\n break;\n case ts.SyntaxKind.TemplateSpan:\n let span = node;\n if (span.expression) {\n // Do not emit extra whitespace inside the string template\n this.emitNoSpace('${');\n this.visit(span.expression);\n this.emitNoSpace('}');\n }\n if (span.literal) this.visit(span.literal);\n break;\n case ts.SyntaxKind.ArrayLiteralExpression:\n if (this.shouldBeConst(node)) this.emit('const');\n let ale = node;\n this.handleReifiedArray(ale);\n this.emit('[');\n this.visitList(ale.elements);\n this.emit(']');\n break;\n case ts.SyntaxKind.ObjectLiteralExpression:\n let ole = node;\n if (this.fc.maybeHandleProvider(ole)) return true;\n if (this.shouldBeConst(node)) this.emit('const');\n this.handleReifiedMap(ole);\n this.emit('{');\n this.visitList(ole.properties);\n this.emit('}');\n break;\n case ts.SyntaxKind.PropertyAssignment:\n let propAssign = node;\n if (propAssign.name.kind === ts.SyntaxKind.Identifier) {\n // Dart identifiers in Map literals need quoting.\n this.emitNoSpace(' \\'');\n this.emitNoSpace((propAssign.name).text);\n this.emitNoSpace('\\'');\n } else {\n this.visit(propAssign.name);\n }\n this.emit(':');\n this.visit(propAssign.initializer);\n break;\n case ts.SyntaxKind.ShorthandPropertyAssignment:\n let shorthand = node;\n this.emitNoSpace(' \\'');\n this.emitNoSpace(shorthand.name.text);\n this.emitNoSpace('\\'');\n this.emit(':');\n this.visit(shorthand.name);\n break;\n\n case ts.SyntaxKind.TrueKeyword:\n this.emit('true');\n break;\n case ts.SyntaxKind.FalseKeyword:\n this.emit('false');\n break;\n case ts.SyntaxKind.NullKeyword:\n this.emit('null');\n break;\n case ts.SyntaxKind.RegularExpressionLiteral:\n this.emit('new RegExp (');\n this.emit('r\\'');\n let regExp = (node).text;\n let slashIdx = regExp.lastIndexOf('/');\n let flags = regExp.substring(slashIdx + 1);\n regExp = regExp.substring(1, slashIdx); // cut off /.../ chars.\n regExp = regExp.replace(/'/g, '\\' + \"\\'\" + r\\''); // handle nested quotes by concatenation.\n this.emitNoSpace(regExp);\n this.emitNoSpace('\\'');\n if (flags.indexOf('g') === -1) {\n // Dart RegExps are always global, so JS regexps must use 'g' so that semantics match.\n this.reportError(node, 'Regular Expressions must use the //g flag');\n }\n if (flags.indexOf('m') !== -1) {\n this.emit(', multiLine: true');\n }\n if (flags.indexOf('i') !== -1) {\n this.emit(', caseSensitive: false');\n }\n this.emit(')');\n break;\n case ts.SyntaxKind.ThisKeyword:\n this.emit('this');\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n private shouldBeConst(n: ts.Node): boolean {\n return this.hasAncestor(n, ts.SyntaxKind.Decorator) || this.fc.isInsideConstExpr(n);\n }\n\n private escapeTextForTemplateString(n: ts.Node): string {\n return (n).text.replace(/\\\\/g, '\\\\\\\\').replace(/([$'])/g, '\\\\$1');\n }\n\n private handleReifiedArray(node: ts.ArrayLiteralExpression) {\n if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return;\n let ta = node.parent;\n if (ta.type.kind !== ts.SyntaxKind.ArrayType) return;\n this.emit('<');\n this.visit((ta.type).elementType);\n this.emit('>');\n return true;\n }\n\n\n private handleReifiedMap(node: ts.ObjectLiteralExpression) {\n if (node.parent.kind !== ts.SyntaxKind.TypeAssertionExpression) return;\n let ta = node.parent;\n if (ta.type.kind !== ts.SyntaxKind.TypeLiteral) return;\n let it = this.maybeDestructureIndexType(ta.type);\n if (!it) {\n this.reportError(node, 'expected {[k]: v} type on object literal');\n return;\n }\n this.emit('<');\n this.visit(it[0]);\n this.emit(',');\n this.visit(it[1]);\n this.emit('>');\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/main.js b/build/lib/main.js new file mode 100755 index 0000000..f92778c --- /dev/null +++ b/build/lib/main.js @@ -0,0 +1,391 @@ +#! /usr/bin/env node +"use strict"; +require('source-map-support').install(); +var source_map_1 = require('source-map'); +var fs = require('fs'); +var path = require('path'); +var ts = require('typescript'); +var mkdirp_1 = require('./mkdirp'); +var call_1 = require('./call'); +var declaration_1 = require('./declaration'); +var expression_1 = require('./expression'); +var module_1 = require('./module'); +var statement_1 = require('./statement'); +var type_1 = require('./type'); +var literal_1 = require('./literal'); +var facade_converter_1 = require('./facade_converter'); +var dartStyle = require('dart-style'); +exports.COMPILER_OPTIONS = { + allowNonTsExtensions: true, + experimentalDecorators: true, + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES6 +}; +var Transpiler = (function () { + function Transpiler(options) { + if (options === void 0) { options = {}; } + this.options = options; + // Comments attach to all following AST nodes before the next 'physical' token. Track the earliest + // offset to avoid printing comments multiple times. + this.lastCommentIdx = -1; + this.errors = []; + // TODO: Remove the angular2 default when angular uses typingsRoot. + this.fc = new facade_converter_1.FacadeConverter(this); + this.transpilers = [ + new call_1["default"](this, this.fc), + new declaration_1["default"](this, this.fc, options.enforceUnderscoreConventions), + new expression_1["default"](this, this.fc), + new literal_1["default"](this, this.fc), + new module_1["default"](this, this.fc, options.generateLibraryName), + new statement_1["default"](this), + new type_1["default"](this, this.fc), + ]; + } + /** + * Transpiles the given files to Dart. + * @param fileNames The input files. + * @param destination Location to write files to. Creates files next to their sources if absent. + */ + Transpiler.prototype.transpile = function (fileNames, destination) { + var _this = this; + if (this.options.basePath) { + this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath)); + } + fileNames = fileNames.map(function (f) { return _this.normalizeSlashes(path.resolve(f)); }); + var host; + var compilerOpts; + if (this.options.tsconfig) { + var _a = ts.readConfigFile(this.options.tsconfig, function (f) { return fs.readFileSync(f, 'utf-8'); }), config = _a.config, error = _a.error; + if (error) + throw new Error(ts.flattenDiagnosticMessageText(error.messageText, '\n')); + var _b = ts.convertCompilerOptionsFromJson(config.compilerOptions, path.dirname(this.options.tsconfig)), options = _b.options, errors = _b.errors; + if (errors && errors.length) { + throw new Error(errors.map(function (d) { return _this.diagnosticToString(d); }).join('\n')); + } + host = ts.createCompilerHost(options, /*setParentNodes*/ true); + compilerOpts = options; + if (compilerOpts.rootDir != null && this.options.basePath == null) { + // Use the tsconfig's rootDir if basePath is not set. + this.options.basePath = compilerOpts.rootDir; + } + if (compilerOpts.outDir != null && destination == null) { + destination = compilerOpts.outDir; + } + } + else { + host = this.createCompilerHost(); + compilerOpts = this.getCompilerOptions(); + } + if (this.options.basePath) + this.options.basePath = path.resolve(this.options.basePath); + if (this.options.basePath && destination === undefined) { + throw new Error('Must have a destination path when a basePath is specified ' + this.options.basePath); + } + var destinationRoot = destination || this.options.basePath || ''; + var program = ts.createProgram(fileNames, compilerOpts, host); + if (this.options.translateBuiltins) { + this.fc.initializeTypeBasedConversion(program.getTypeChecker(), compilerOpts, host); + } + // Only write files that were explicitly passed in. + var fileSet = {}; + fileNames.forEach(function (f) { return fileSet[f] = true; }); + this.errors = []; + program.getSourceFiles() + .filter(function (sourceFile) { return fileSet[sourceFile.fileName]; }) + .filter(function (sourceFile) { return !sourceFile.fileName.match(/\.d\.ts$/); }) + .forEach(function (f) { + var dartCode = _this.translate(f); + var outputFile = _this.getOutputPath(f.fileName, destinationRoot) + .replace(/([A-Z])/g, function ($1) { return "_" + $1.toLowerCase(); }); + if (outputFile.charAt(0) == '_') + outputFile = outputFile.substring(1); + mkdirp_1["default"](path.dirname(outputFile)); + console.log(dartCode); + fs.writeFileSync(outputFile, dartCode); + }); + this.checkForErrors(program); + }; + Transpiler.prototype.translateProgram = function (program, host) { + var _this = this; + if (this.options.translateBuiltins) { + this.fc.initializeTypeBasedConversion(program.getTypeChecker(), program.getCompilerOptions(), host); + } + var paths = {}; + this.errors = []; + program.getSourceFiles() + .filter(function (sourceFile) { + return (!sourceFile.fileName.match(/\.d\.ts$/) && !!sourceFile.fileName.match(/\.[jt]s$/)); + }) + .forEach(function (f) { return paths[f.fileName] = _this.translate(f); }); + this.checkForErrors(program); + return paths; + }; + Transpiler.prototype.getCompilerOptions = function () { + var opts = {}; + for (var _i = 0, _a = Object.keys(exports.COMPILER_OPTIONS); _i < _a.length; _i++) { + var k = _a[_i]; + opts[k] = exports.COMPILER_OPTIONS[k]; + } + opts.rootDir = this.options.basePath; + return opts; + }; + Transpiler.prototype.createCompilerHost = function () { + var defaultLibFileName = ts.getDefaultLibFileName(exports.COMPILER_OPTIONS); + defaultLibFileName = this.normalizeSlashes(defaultLibFileName); + var compilerHost = { + getSourceFile: function (sourceName, languageVersion) { + var sourcePath = sourceName; + if (sourceName === defaultLibFileName) { + sourcePath = ts.getDefaultLibFilePath(exports.COMPILER_OPTIONS); + } + if (!fs.existsSync(sourcePath)) + return undefined; + var contents = fs.readFileSync(sourcePath, 'UTF-8'); + return ts.createSourceFile(sourceName, contents, exports.COMPILER_OPTIONS.target, true); + }, + writeFile: function (name, text, writeByteOrderMark) { fs.writeFile(name, text); }, + fileExists: function (filename) { return fs.existsSync(filename); }, + readFile: function (filename) { return fs.readFileSync(filename, 'utf-8'); }, + getDefaultLibFileName: function () { return defaultLibFileName; }, + useCaseSensitiveFileNames: function () { return true; }, + getCanonicalFileName: function (filename) { return filename; }, + getCurrentDirectory: function () { return ''; }, + getNewLine: function () { return '\n'; } + }; + compilerHost.resolveModuleNames = getModuleResolver(compilerHost); + return compilerHost; + }; + // Visible for testing. + Transpiler.prototype.getOutputPath = function (filePath, destinationRoot) { + var relative = this.getRelativeFileName(filePath); + var dartFile = relative.replace(/.(js|es6|ts)$/, '.dart'); + return this.normalizeSlashes(path.join(destinationRoot, dartFile)); + }; + Transpiler.prototype.translate = function (sourceFile) { + this.currentFile = sourceFile; + this.output = new Output(sourceFile, this.getRelativeFileName(sourceFile.fileName), this.options.generateSourceMap); + this.lastCommentIdx = -1; + this.visit(sourceFile); + var result = this.output.getResult(); + return this.formatCode(result, sourceFile); + }; + Transpiler.prototype.formatCode = function (code, context) { + var result = dartStyle.formatCode(code); + if (result.error) { + this.reportError(context, result.error); + } + return result.code; + }; + Transpiler.prototype.checkForErrors = function (program) { + var _this = this; + var errors = this.errors; + var diagnostics = program.getGlobalDiagnostics().concat(program.getSyntacticDiagnostics()); + if ((errors.length || diagnostics.length) && this.options.translateBuiltins) { + // Only report semantic diagnostics if ts2dart failed; this code is not a generic compiler, so + // only yields TS errors if they could be the cause of ts2dart issues. + // This greatly speeds up tests and execution. + diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); + } + var diagnosticErrs = diagnostics.map(function (d) { return _this.diagnosticToString(d); }); + if (diagnosticErrs.length) + errors = errors.concat(diagnosticErrs); + if (errors.length) { + var e = new Error(errors.join('\n')); + e.name = 'TS2DartError'; + throw e; + } + }; + Transpiler.prototype.diagnosticToString = function (diagnostic) { + var msg = ''; + if (diagnostic.file) { + var pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + var fn = this.getRelativeFileName(diagnostic.file.fileName); + msg += " " + fn + ":" + (pos.line + 1) + ":" + (pos.character + 1); + } + msg += ': '; + msg += ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + return msg; + }; + /** + * Returns `filePath`, relativized to the program's `basePath`. + * @param filePath path to relativize. + */ + Transpiler.prototype.getRelativeFileName = function (filePath) { + var base = this.options.basePath || ''; + if (filePath[0] === '/' && filePath.indexOf(base) !== 0 && !filePath.match(/\.d\.ts$/)) { + throw new Error("Files must be located under base, got " + filePath + " vs " + base); + } + var rel = path.relative(base, filePath); + if (rel.indexOf('../') === 0) { + // filePath is outside of rel, just use it directly. + rel = filePath; + } + return this.normalizeSlashes(rel); + }; + Transpiler.prototype.emit = function (s) { this.output.emit(s); }; + Transpiler.prototype.emitBefore = function (s, search) { this.output.emitBefore(s, search); }; + Transpiler.prototype.emitNoSpace = function (s) { this.output.emitNoSpace(s); }; + Transpiler.prototype.reportError = function (n, message) { + var file = n.getSourceFile() || this.currentFile; + var fileName = this.getRelativeFileName(file.fileName); + var start = n.getStart(file); + var pos = file.getLineAndCharacterOfPosition(start); + // Line and character are 0-based. + var fullMessage = fileName + ":" + (pos.line + 1) + ":" + (pos.character + 1) + ": " + message; + if (this.options.failFast) + throw new Error(fullMessage); + this.errors.push(fullMessage); + }; + Transpiler.prototype.visit = function (node) { + var _this = this; + this.output.addSourceMapping(node); + try { + var comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart()); + if (comments) { + comments.forEach(function (c) { + if (c.pos <= _this.lastCommentIdx) + return; + _this.lastCommentIdx = c.pos; + var text = _this.currentFile.text.substring(c.pos, c.end); + _this.emitNoSpace('\n'); + _this.emit(_this.translateComment(text)); + if (c.hasTrailingNewLine) + _this.emitNoSpace('\n'); + }); + } + for (var i = 0; i < this.transpilers.length; i++) { + if (this.transpilers[i].visitNode(node)) + return; + } + this.reportError(node, "Unsupported node type " + ts.SyntaxKind[node.kind] + ": " + node.getFullText()); + } + catch (e) { + this.reportError(node, 'ts2dart crashed ' + e.stack); + } + }; + Transpiler.prototype.normalizeSlashes = function (path) { return path.replace(/\\/g, '/'); }; + Transpiler.prototype.translateComment = function (comment) { + comment = comment.replace(/\{@link ([^\}]+)\}/g, '[$1]'); + // Remove the following tags and following comments till end of line. + comment = comment.replace(/@param.*$/gm, ''); + comment = comment.replace(/@throws.*$/gm, ''); + comment = comment.replace(/@return.*$/gm, ''); + // Remove the following tags. + comment = comment.replace(/@module/g, ''); + comment = comment.replace(/@description/g, ''); + comment = comment.replace(/@deprecated/g, ''); + return comment; + }; + return Transpiler; +}()); +exports.Transpiler = Transpiler; +function getModuleResolver(compilerHost) { + return function (moduleNames, containingFile) { + var res = []; + for (var _i = 0, moduleNames_1 = moduleNames; _i < moduleNames_1.length; _i++) { + var mod = moduleNames_1[_i]; + var lookupRes = ts.nodeModuleNameResolver(mod, containingFile, exports.COMPILER_OPTIONS, compilerHost); + if (lookupRes.resolvedModule) { + res.push(lookupRes.resolvedModule); + continue; + } + lookupRes = ts.classicNameResolver(mod, containingFile, exports.COMPILER_OPTIONS, compilerHost); + if (lookupRes.resolvedModule) { + res.push(lookupRes.resolvedModule); + continue; + } + res.push(undefined); + } + return res; + }; +} +exports.getModuleResolver = getModuleResolver; +var Output = (function () { + function Output(currentFile, relativeFileName, generateSourceMap) { + this.currentFile = currentFile; + this.relativeFileName = relativeFileName; + this.result = ''; + this.column = 1; + this.line = 1; + if (generateSourceMap) { + this.sourceMap = new source_map_1.SourceMapGenerator({ file: relativeFileName + '.dart' }); + this.sourceMap.setSourceContent(relativeFileName, this.currentFile.text); + } + } + Output.prototype.emit = function (str) { + this.emitNoSpace(' '); + this.emitNoSpace(str); + }; + Output.prototype.emitBefore = function (str, search) { + var idx = this.result.indexOf(search); + if (idx < 0) + return; + str = str + ' '; + this.result = this.result.substring(0, idx) + str + this.result.substring(idx); + for (var i = 0; i < str.length; i++) { + if (str[i] === '\n') { + this.line++; + this.column = 0; + } + else { + this.column++; + } + } + }; + Output.prototype.emitNoSpace = function (str) { + this.result += str; + for (var i = 0; i < str.length; i++) { + if (str[i] === '\n') { + this.line++; + this.column = 0; + } + else { + this.column++; + } + } + }; + Output.prototype.getResult = function () { return this.result + this.generateSourceMapComment(); }; + Output.prototype.addSourceMapping = function (n) { + if (!this.generateSourceMap) + return; // source maps disabled. + var file = n.getSourceFile() || this.currentFile; + var start = n.getStart(file); + var pos = file.getLineAndCharacterOfPosition(start); + var mapping = { + original: { line: pos.line + 1, column: pos.character }, + generated: { line: this.line, column: this.column }, + source: this.relativeFileName + }; + this.sourceMap.addMapping(mapping); + }; + Output.prototype.generateSourceMapComment = function () { + if (!this.sourceMap) + return ''; + var base64map = new Buffer(JSON.stringify(this.sourceMap)).toString('base64'); + return '\n\n//# sourceMappingURL=data:application/json;base64,' + base64map; + }; + return Output; +}()); +function showHelp() { + console.log("\nUsage: ts2dart [input-files] [arguments]\n\n --help show this dialog\n \n --failFast Fail on the first error, do not collect multiple. Allows easier debugging \n as stack traces lead directly to the offending line\n \n --generateLibraryName Whether to generate 'library a.b.c;' names from relative file paths.\n \n --generateSourceMap Whether to generate source maps.\n \n --tsconfig A tsconfig.json to use to configure TypeScript compilation.\n \n --basePath A base path to relativize absolute file paths against. This\n is useful for library name generation (see above) and nicer\n file names in error messages.\n \n --translateBuiltins Translate calls to builtins, i.e. seemlessly convert from ` Array` to ` List`,\n and convert the corresponding methods. Requires type checking.\n \n --enforceUnderscoreConventions Enforce conventions of public/private keyword and underscore prefix\n"); + process.exit(0); +} +// CLI entry point +if (require.main === module) { + var args = require('minimist')(process.argv.slice(2), { base: 'string' }); + if (args.help) + showHelp(); + try { + var transpiler = new Transpiler(args); + console.error('Transpiling', args._, 'to', args.destination); + transpiler.transpile(args._, args.destination); + } + catch (e) { + if (e.name !== 'TS2DartError') + throw e; + console.error(e.message); + process.exit(1); + } +} + +//# sourceMappingURL=main.js.map diff --git a/build/lib/main.js.map b/build/lib/main.js.map new file mode 100644 index 0000000..4af5659 --- /dev/null +++ b/build/lib/main.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["main.ts"],"names":[],"mappings":"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","file":"main.js","sourcesContent":["#! /usr/bin/env node\n\nrequire('source-map-support').install();\nimport {SourceMapGenerator} from 'source-map';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nimport {TranspilerBase} from './base';\nimport mkdirP from './mkdirp';\nimport CallTranspiler from './call';\nimport DeclarationTranspiler from './declaration';\nimport ExpressionTranspiler from './expression';\nimport ModuleTranspiler from './module';\nimport StatementTranspiler from './statement';\nimport TypeTranspiler from './type';\nimport LiteralTranspiler from './literal';\nimport {FacadeConverter} from './facade_converter';\nimport * as dartStyle from 'dart-style';\n\nexport interface TranspilerOptions {\n /**\n * Fail on the first error, do not collect multiple. Allows easier debugging as stack traces lead\n * directly to the offending line.\n */\n failFast?: boolean;\n /** Whether to generate 'library a.b.c;' names from relative file paths. */\n generateLibraryName?: boolean;\n /** Whether to generate source maps. */\n generateSourceMap?: boolean;\n /** A tsconfig.json to use to configure TypeScript compilation. */\n tsconfig?: string;\n /**\n * A base path to relativize absolute file paths against. This is useful for library name\n * generation (see above) and nicer file names in error messages.\n */\n basePath?: string;\n /**\n * Translate calls to builtins, i.e. seemlessly convert from `Array` to `List`, and convert the\n * corresponding methods. Requires type checking.\n */\n translateBuiltins?: boolean;\n /**\n * Enforce conventions of public/private keyword and underscore prefix\n */\n enforceUnderscoreConventions?: boolean;\n}\n\nexport const COMPILER_OPTIONS: ts.CompilerOptions = {\n allowNonTsExtensions: true,\n experimentalDecorators: true,\n module: ts.ModuleKind.CommonJS,\n target: ts.ScriptTarget.ES6,\n};\n\nexport class Transpiler {\n private output: Output;\n private currentFile: ts.SourceFile;\n\n // Comments attach to all following AST nodes before the next 'physical' token. Track the earliest\n // offset to avoid printing comments multiple times.\n private lastCommentIdx: number = -1;\n private errors: string[] = [];\n\n private transpilers: TranspilerBase[];\n private fc: FacadeConverter;\n\n constructor(private options: TranspilerOptions = {}) {\n // TODO: Remove the angular2 default when angular uses typingsRoot.\n this.fc = new FacadeConverter(this);\n this.transpilers = [\n new CallTranspiler(this, this.fc), // Has to come before StatementTranspiler!\n new DeclarationTranspiler(this, this.fc, options.enforceUnderscoreConventions),\n new ExpressionTranspiler(this, this.fc),\n new LiteralTranspiler(this, this.fc),\n new ModuleTranspiler(this, this.fc, options.generateLibraryName),\n new StatementTranspiler(this),\n new TypeTranspiler(this, this.fc),\n ];\n }\n\n /**\n * Transpiles the given files to Dart.\n * @param fileNames The input files.\n * @param destination Location to write files to. Creates files next to their sources if absent.\n */\n transpile(fileNames: string[], destination?: string): void {\n if (this.options.basePath) {\n this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath));\n }\n fileNames = fileNames.map((f) => this.normalizeSlashes(path.resolve(f)));\n\n let host: ts.CompilerHost;\n let compilerOpts: ts.CompilerOptions;\n if (this.options.tsconfig) {\n let {config, error} =\n ts.readConfigFile(this.options.tsconfig, (f) => fs.readFileSync(f, 'utf-8'));\n if (error) throw new Error(ts.flattenDiagnosticMessageText(error.messageText, '\\n'));\n let {options, errors} = ts.convertCompilerOptionsFromJson(\n config.compilerOptions, path.dirname(this.options.tsconfig));\n if (errors && errors.length) {\n throw new Error(errors.map((d) => this.diagnosticToString(d)).join('\\n'));\n }\n host = ts.createCompilerHost(options, /*setParentNodes*/ true);\n compilerOpts = options;\n if (compilerOpts.rootDir != null && this.options.basePath == null) {\n // Use the tsconfig's rootDir if basePath is not set.\n this.options.basePath = compilerOpts.rootDir;\n }\n if (compilerOpts.outDir != null && destination == null) {\n destination = compilerOpts.outDir;\n }\n } else {\n host = this.createCompilerHost();\n compilerOpts = this.getCompilerOptions();\n }\n if (this.options.basePath) this.options.basePath = path.resolve(this.options.basePath);\n\n if (this.options.basePath && destination === undefined) {\n throw new Error(\n 'Must have a destination path when a basePath is specified ' + this.options.basePath);\n }\n let destinationRoot = destination || this.options.basePath || '';\n let program = ts.createProgram(fileNames, compilerOpts, host);\n if (this.options.translateBuiltins) {\n this.fc.initializeTypeBasedConversion(program.getTypeChecker(), compilerOpts, host);\n }\n\n // Only write files that were explicitly passed in.\n let fileSet: {[s: string]: boolean} = {};\n fileNames.forEach((f) => fileSet[f] = true);\n this.errors = [];\n\n program.getSourceFiles()\n .filter((sourceFile) => fileSet[sourceFile.fileName])\n // Do not generate output for .d.ts files.\n .filter((sourceFile: ts.SourceFile) => !sourceFile.fileName.match(/\\.d\\.ts$/))\n .forEach((f: ts.SourceFile) => {\n let dartCode = this.translate(f);\n let outputFile = this.getOutputPath(f.fileName, destinationRoot)\n .replace(/([A-Z])/g, function($1){return \"_\"+$1.toLowerCase();});\n if (outputFile.charAt(0) == '_')\n outputFile = outputFile.substring(1);\n mkdirP(path.dirname(outputFile));\n console.log(dartCode);\n fs.writeFileSync(outputFile, dartCode);\n });\n this.checkForErrors(program);\n }\n\n translateProgram(program: ts.Program, host: ts.CompilerHost): {[path: string]: string} {\n if (this.options.translateBuiltins) {\n this.fc.initializeTypeBasedConversion(\n program.getTypeChecker(), program.getCompilerOptions(), host);\n }\n let paths: {[path: string]: string} = {};\n this.errors = [];\n program.getSourceFiles()\n .filter(\n (sourceFile: ts.SourceFile) =>\n (!sourceFile.fileName.match(/\\.d\\.ts$/) && !!sourceFile.fileName.match(/\\.[jt]s$/)))\n .forEach((f) => paths[f.fileName] = this.translate(f));\n this.checkForErrors(program);\n return paths;\n }\n\n private getCompilerOptions() {\n let opts: ts.CompilerOptions = {};\n for (let k of Object.keys(COMPILER_OPTIONS)) opts[k] = COMPILER_OPTIONS[k];\n opts.rootDir = this.options.basePath;\n return opts;\n }\n\n private createCompilerHost(): ts.CompilerHost {\n let defaultLibFileName = ts.getDefaultLibFileName(COMPILER_OPTIONS);\n defaultLibFileName = this.normalizeSlashes(defaultLibFileName);\n let compilerHost: ts.CompilerHost = {\n getSourceFile: (sourceName, languageVersion) => {\n let sourcePath = sourceName;\n if (sourceName === defaultLibFileName) {\n sourcePath = ts.getDefaultLibFilePath(COMPILER_OPTIONS);\n }\n if (!fs.existsSync(sourcePath)) return undefined;\n let contents = fs.readFileSync(sourcePath, 'UTF-8');\n return ts.createSourceFile(sourceName, contents, COMPILER_OPTIONS.target, true);\n },\n writeFile(name, text, writeByteOrderMark) { fs.writeFile(name, text); },\n fileExists: (filename) => fs.existsSync(filename),\n readFile: (filename) => fs.readFileSync(filename, 'utf-8'),\n getDefaultLibFileName: () => defaultLibFileName,\n useCaseSensitiveFileNames: () => true,\n getCanonicalFileName: (filename) => filename,\n getCurrentDirectory: () => '',\n getNewLine: () => '\\n',\n };\n compilerHost.resolveModuleNames = getModuleResolver(compilerHost);\n return compilerHost;\n }\n\n // Visible for testing.\n getOutputPath(filePath: string, destinationRoot: string): string {\n let relative = this.getRelativeFileName(filePath);\n let dartFile = relative.replace(/.(js|es6|ts)$/, '.dart');\n return this.normalizeSlashes(path.join(destinationRoot, dartFile));\n }\n\n private translate(sourceFile: ts.SourceFile): string {\n this.currentFile = sourceFile;\n this.output = new Output(\n sourceFile, this.getRelativeFileName(sourceFile.fileName), this.options.generateSourceMap);\n this.lastCommentIdx = -1;\n this.visit(sourceFile);\n let result = this.output.getResult();\n return this.formatCode(result, sourceFile);\n }\n\n private formatCode(code: string, context: ts.Node) {\n let result = dartStyle.formatCode(code);\n if (result.error) {\n this.reportError(context, result.error);\n }\n return result.code;\n }\n\n private checkForErrors(program: ts.Program) {\n let errors = this.errors;\n\n let diagnostics = program.getGlobalDiagnostics().concat(program.getSyntacticDiagnostics());\n\n if ((errors.length || diagnostics.length) && this.options.translateBuiltins) {\n // Only report semantic diagnostics if ts2dart failed; this code is not a generic compiler, so\n // only yields TS errors if they could be the cause of ts2dart issues.\n // This greatly speeds up tests and execution.\n diagnostics = diagnostics.concat(program.getSemanticDiagnostics());\n }\n\n let diagnosticErrs = diagnostics.map((d) => this.diagnosticToString(d));\n if (diagnosticErrs.length) errors = errors.concat(diagnosticErrs);\n\n if (errors.length) {\n let e = new Error(errors.join('\\n'));\n e.name = 'TS2DartError';\n throw e;\n }\n }\n\n private diagnosticToString(diagnostic: ts.Diagnostic): string {\n let msg = '';\n if (diagnostic.file) {\n let pos = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n let fn = this.getRelativeFileName(diagnostic.file.fileName);\n msg += ` ${fn}:${pos.line + 1}:${pos.character + 1}`;\n }\n msg += ': ';\n msg += ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n');\n return msg;\n }\n\n /**\n * Returns `filePath`, relativized to the program's `basePath`.\n * @param filePath path to relativize.\n */\n getRelativeFileName(filePath: string) {\n let base = this.options.basePath || '';\n if (filePath[0] === '/' && filePath.indexOf(base) !== 0 && !filePath.match(/\\.d\\.ts$/)) {\n throw new Error(`Files must be located under base, got ${filePath} vs ${base}`);\n }\n let rel = path.relative(base, filePath);\n if (rel.indexOf('../') === 0) {\n // filePath is outside of rel, just use it directly.\n rel = filePath;\n }\n return this.normalizeSlashes(rel);\n }\n\n emit(s: string) { this.output.emit(s); }\n emitBefore(s: string, search: string) { this.output.emitBefore(s, search); }\n emitNoSpace(s: string) { this.output.emitNoSpace(s); }\n\n reportError(n: ts.Node, message: string) {\n let file = n.getSourceFile() || this.currentFile;\n let fileName = this.getRelativeFileName(file.fileName);\n let start = n.getStart(file);\n let pos = file.getLineAndCharacterOfPosition(start);\n // Line and character are 0-based.\n let fullMessage = `${fileName}:${pos.line + 1}:${pos.character + 1}: ${message}`;\n if (this.options.failFast) throw new Error(fullMessage);\n this.errors.push(fullMessage);\n }\n\n visit(node: ts.Node) {\n this.output.addSourceMapping(node);\n try {\n let comments = ts.getLeadingCommentRanges(this.currentFile.text, node.getFullStart());\n if (comments) {\n comments.forEach((c) => {\n if (c.pos <= this.lastCommentIdx) return;\n this.lastCommentIdx = c.pos;\n let text = this.currentFile.text.substring(c.pos, c.end);\n this.emitNoSpace('\\n');\n this.emit(this.translateComment(text));\n if (c.hasTrailingNewLine) this.emitNoSpace('\\n');\n });\n }\n\n for (let i = 0; i < this.transpilers.length; i++) {\n if (this.transpilers[i].visitNode(node)) return;\n }\n this.reportError(\n node, `Unsupported node type ${(ts).SyntaxKind[node.kind]}: ${node.getFullText()}`);\n } catch (e) {\n this.reportError(node, 'ts2dart crashed ' + e.stack);\n }\n }\n\n private normalizeSlashes(path: string) { return path.replace(/\\\\/g, '/'); }\n\n private translateComment(comment: string): string {\n comment = comment.replace(/\\{@link ([^\\}]+)\\}/g, '[$1]');\n\n // Remove the following tags and following comments till end of line.\n comment = comment.replace(/@param.*$/gm, '');\n comment = comment.replace(/@throws.*$/gm, '');\n comment = comment.replace(/@return.*$/gm, '');\n\n // Remove the following tags.\n comment = comment.replace(/@module/g, '');\n comment = comment.replace(/@description/g, '');\n comment = comment.replace(/@deprecated/g, '');\n\n return comment;\n }\n}\n\nexport function getModuleResolver(compilerHost: ts.CompilerHost) {\n return (moduleNames: string[], containingFile: string): ts.ResolvedModule[] => {\n let res: ts.ResolvedModule[] = [];\n for (let mod of moduleNames) {\n let lookupRes =\n ts.nodeModuleNameResolver(mod, containingFile, COMPILER_OPTIONS, compilerHost);\n if (lookupRes.resolvedModule) {\n res.push(lookupRes.resolvedModule);\n continue;\n }\n lookupRes = ts.classicNameResolver(mod, containingFile, COMPILER_OPTIONS, compilerHost);\n if (lookupRes.resolvedModule) {\n res.push(lookupRes.resolvedModule);\n continue;\n }\n res.push(undefined);\n }\n return res;\n };\n}\n\nclass Output {\n private result: string = '';\n private column: number = 1;\n private line: number = 1;\n\n // Position information.\n private generateSourceMap: boolean;\n private sourceMap: SourceMapGenerator;\n\n constructor(\n private currentFile: ts.SourceFile, private relativeFileName: string,\n generateSourceMap: boolean) {\n if (generateSourceMap) {\n this.sourceMap = new SourceMapGenerator({file: relativeFileName + '.dart'});\n this.sourceMap.setSourceContent(relativeFileName, this.currentFile.text);\n }\n }\n\n emit(str: string) {\n this.emitNoSpace(' ');\n this.emitNoSpace(str);\n }\n\n emitBefore(str: string, search: string) {\n const idx:number = this.result.indexOf(search);\n if (idx < 0) return;\n str = str + ' ';\n this.result = this.result.substring(0, idx) + str + this.result.substring(idx);\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\n') {\n this.line++;\n this.column = 0;\n } else {\n this.column++;\n }\n }\n }\n\n emitNoSpace(str: string) {\n this.result += str;\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\n') {\n this.line++;\n this.column = 0;\n } else {\n this.column++;\n }\n }\n }\n\n getResult(): string { return this.result + this.generateSourceMapComment(); }\n\n addSourceMapping(n: ts.Node) {\n if (!this.generateSourceMap) return; // source maps disabled.\n let file = n.getSourceFile() || this.currentFile;\n let start = n.getStart(file);\n let pos = file.getLineAndCharacterOfPosition(start);\n\n let mapping: SourceMap.Mapping = {\n original: {line: pos.line + 1, column: pos.character},\n generated: {line: this.line, column: this.column},\n source: this.relativeFileName,\n };\n\n this.sourceMap.addMapping(mapping);\n }\n\n private generateSourceMapComment() {\n if (!this.sourceMap) return '';\n let base64map = new Buffer(JSON.stringify(this.sourceMap)).toString('base64');\n return '\\n\\n//# sourceMappingURL=data:application/json;base64,' + base64map;\n }\n}\n\nfunction showHelp() {\n console.log(`\nUsage: ts2dart [input-files] [arguments]\n\n --help show this dialog\n \n --failFast Fail on the first error, do not collect multiple. Allows easier debugging \n as stack traces lead directly to the offending line\n \n --generateLibraryName Whether to generate 'library a.b.c;' names from relative file paths.\n \n --generateSourceMap Whether to generate source maps.\n \n --tsconfig A tsconfig.json to use to configure TypeScript compilation.\n \n --basePath A base path to relativize absolute file paths against. This\n is useful for library name generation (see above) and nicer\n file names in error messages.\n \n --translateBuiltins Translate calls to builtins, i.e. seemlessly convert from \\` Array\\` to \\` List\\`,\n and convert the corresponding methods. Requires type checking.\n \n --enforceUnderscoreConventions Enforce conventions of public/private keyword and underscore prefix\n`);\n process.exit(0);\n}\n\n// CLI entry point\nif (require.main === module) {\n let args = require('minimist')(process.argv.slice(2), {base: 'string'});\n if (args.help) showHelp();\n try {\n let transpiler = new Transpiler(args);\n console.error('Transpiling', args._, 'to', args.destination);\n transpiler.transpile(args._, args.destination);\n } catch (e) {\n if (e.name !== 'TS2DartError') throw e;\n console.error(e.message);\n process.exit(1);\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/mkdirp.js b/build/lib/mkdirp.js new file mode 100644 index 0000000..c6691c5 --- /dev/null +++ b/build/lib/mkdirp.js @@ -0,0 +1,20 @@ +"use strict"; +var fs = require('fs'); +var path = require('path'); +function mkdirP(p) { + // Convert input path to absolute and then relative so that we always have relative path in the + // end. This can be made simpler when path.isAbsolute is available in node v0.12. + p = path.resolve(p); + p = path.relative('', p); + var pathToCreate = ''; + p.split(path.sep).forEach(function (dirName) { + pathToCreate = path.join(pathToCreate, dirName); + if (!fs.existsSync(pathToCreate)) { + fs.mkdirSync(pathToCreate); + } + }); +} +exports.__esModule = true; +exports["default"] = mkdirP; + +//# sourceMappingURL=mkdirp.js.map diff --git a/build/lib/mkdirp.js.map b/build/lib/mkdirp.js.map new file mode 100644 index 0000000..ecffb81 --- /dev/null +++ b/build/lib/mkdirp.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["mkdirp.ts"],"names":[],"mappings":";AAAA,IAAY,EAAE,WAAM,IAAI,CAAC,CAAA;AACzB,IAAY,IAAI,WAAM,MAAM,CAAC,CAAA;AAE7B,gBAA+B,CAAS;IACtC,+FAA+F;IAC/F,iFAAiF;IACjF,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAEzB,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAA,OAAO;QAC/B,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAChD,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACjC,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAbD;2BAaC,CAAA","file":"mkdirp.js","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nexport default function mkdirP(p: string) {\n // Convert input path to absolute and then relative so that we always have relative path in the\n // end. This can be made simpler when path.isAbsolute is available in node v0.12.\n p = path.resolve(p);\n p = path.relative('', p);\n\n let pathToCreate = '';\n p.split(path.sep).forEach(dirName => {\n pathToCreate = path.join(pathToCreate, dirName);\n if (!fs.existsSync(pathToCreate)) {\n fs.mkdirSync(pathToCreate);\n }\n });\n}\n"]} \ No newline at end of file diff --git a/build/lib/module.js b/build/lib/module.js new file mode 100644 index 0000000..a149d01 --- /dev/null +++ b/build/lib/module.js @@ -0,0 +1,176 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var ModuleTranspiler = (function (_super) { + __extends(ModuleTranspiler, _super); + function ModuleTranspiler(tr, fc, generateLibraryName) { + _super.call(this, tr); + this.fc = fc; + this.generateLibraryName = generateLibraryName; + } + ModuleTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.SourceFile: + var sf = node; + if (this.generateLibraryName) { + this.emit('library'); + this.emit(this.getLibraryName(sf.fileName)); + this.emit(';'); + } + this.fc.emitExtraImports(sf); + ts.forEachChild(sf, this.visit.bind(this)); + break; + case ts.SyntaxKind.EndOfFileToken: + ts.forEachChild(node, this.visit.bind(this)); + break; + case ts.SyntaxKind.ImportDeclaration: + var importDecl = node; + if (importDecl.importClause) { + if (this.isEmptyImport(importDecl)) + return true; + this.emit('import'); + this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier); + this.visit(importDecl.importClause); + } + else { + this.reportError(importDecl, 'bare import is unsupported'); + } + this.emit(';'); + break; + case ts.SyntaxKind.ImportClause: + var importClause = node; + if (importClause.name) + this.fc.visitTypeName(importClause.name); + if (importClause.namedBindings) { + this.visit(importClause.namedBindings); + } + break; + case ts.SyntaxKind.NamespaceImport: + var nsImport = node; + this.emit('as'); + this.fc.visitTypeName(nsImport.name); + break; + case ts.SyntaxKind.NamedImports: + this.emit('show'); + var used = this.filterImports(node.elements); + if (used.length === 0) { + this.reportError(node, 'internal error, used imports must not be empty'); + } + this.visitList(used); + break; + case ts.SyntaxKind.NamedExports: + var exportElements = node.elements; + this.emit('show'); + if (exportElements.length === 0) + this.reportError(node, 'empty export list'); + this.visitList(node.elements); + break; + case ts.SyntaxKind.ImportSpecifier: + case ts.SyntaxKind.ExportSpecifier: + var spec = node; + if (spec.propertyName) { + this.reportError(spec.propertyName, 'import/export renames are unsupported in Dart'); + } + this.fc.visitTypeName(spec.name); + break; + case ts.SyntaxKind.ExportDeclaration: + var exportDecl = node; + this.emit('export'); + if (exportDecl.moduleSpecifier) { + this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); + } + else { + this.reportError(node, 're-exports must have a module URL (export x from "./y").'); + } + if (exportDecl.exportClause) + this.visit(exportDecl.exportClause); + this.emit(';'); + break; + case ts.SyntaxKind.ImportEqualsDeclaration: + var importEqDecl = node; + this.emit('import'); + this.visit(importEqDecl.moduleReference); + this.emit('as'); + this.fc.visitTypeName(importEqDecl.name); + this.emit(';'); + break; + case ts.SyntaxKind.ExternalModuleReference: + this.visitExternalModuleReferenceExpr(node.expression); + break; + default: + return false; + } + return true; + }; + ModuleTranspiler.isIgnoredImport = function (e) { + // TODO: unify with facade_converter.ts + var name = base.ident(e.name); + switch (name) { + case 'CONST': + case 'CONST_EXPR': + case 'normalizeBlank': + case 'forwardRef': + case 'ABSTRACT': + case 'IMPLEMENTS': + return true; + default: + return false; + } + }; + ModuleTranspiler.prototype.visitExternalModuleReferenceExpr = function (expr) { + // TODO: what if this isn't a string literal? + var moduleName = expr; + var text = moduleName.text; + if (text.match(/^\.\//)) { + // Strip './' to be more Dart-idiomatic. + text = text.substring(2).replace(/([A-Z])/g, function ($1) { return "_" + $1.toLowerCase(); }).substring(1); + } + else if (!text.match(/^\.\.\//)) { + // Replace '@angular' with 'angular2' for Dart. + text = text.replace(/^@keikai\//, 'keikai/'); + // Unprefixed/absolute imports are package imports. + text = 'package:' + text; + } + this.emit(JSON.stringify(text + '.dart')); + }; + ModuleTranspiler.prototype.isEmptyImport = function (n) { + var bindings = n.importClause.namedBindings; + if (bindings.kind !== ts.SyntaxKind.NamedImports) + return false; + var elements = bindings.elements; + // An import list being empty *after* filtering is ok, but if it's empty in the code itself, + // it's nonsensical code, so probably a programming error. + if (elements.length === 0) + this.reportError(n, 'empty import list'); + return elements.every(ModuleTranspiler.isIgnoredImport); + }; + ModuleTranspiler.prototype.filterImports = function (ns) { + return ns.filter(function (e) { return !ModuleTranspiler.isIgnoredImport(e); }); + }; + ModuleTranspiler.prototype.getLibraryName = function (fileName) { + fileName = this.getRelativeFileName(fileName); + var parts = fileName.split('/'); + return parts.filter(function (p) { return p.length > 0; }) + .map(function (p) { return p.replace(/^@/, ''); }) + .map(function (p) { return p.replace(/[^\w.]/g, '_'); }) + .map(function (p) { return p.replace(/\.[jt]s$/g, ''); }) + .map(function (p) { return ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p; }) + .join('.'); + }; + // For the Dart keyword list see + // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords + ModuleTranspiler.DART_RESERVED_WORDS = ('assert break case catch class const continue default do else enum extends false final ' + + 'finally for if in is new null rethrow return super switch this throw true try let void ' + + 'while with') + .split(/ /); + return ModuleTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = ModuleTranspiler; + +//# sourceMappingURL=module.js.map diff --git a/build/lib/module.js.map b/build/lib/module.js.map new file mode 100644 index 0000000..c58752a --- /dev/null +++ b/build/lib/module.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["module.ts"],"names":[],"mappings":"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","file":"module.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class ModuleTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibraryName: boolean) {\n super(tr);\n }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.SourceFile:\n let sf = node;\n if (this.generateLibraryName) {\n this.emit('library');\n this.emit(this.getLibraryName(sf.fileName));\n this.emit(';');\n }\n this.fc.emitExtraImports(sf);\n ts.forEachChild(sf, this.visit.bind(this));\n break;\n case ts.SyntaxKind.EndOfFileToken:\n ts.forEachChild(node, this.visit.bind(this));\n break;\n case ts.SyntaxKind.ImportDeclaration:\n let importDecl = node;\n if (importDecl.importClause) {\n if (this.isEmptyImport(importDecl)) return true;\n this.emit('import');\n this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier);\n this.visit(importDecl.importClause);\n } else {\n this.reportError(importDecl, 'bare import is unsupported');\n }\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportClause:\n let importClause = node;\n if (importClause.name) this.fc.visitTypeName(importClause.name);\n if (importClause.namedBindings) {\n this.visit(importClause.namedBindings);\n }\n break;\n case ts.SyntaxKind.NamespaceImport:\n let nsImport = node;\n this.emit('as');\n this.fc.visitTypeName(nsImport.name);\n break;\n case ts.SyntaxKind.NamedImports:\n this.emit('show');\n let used = this.filterImports((node).elements);\n if (used.length === 0) {\n this.reportError(node, 'internal error, used imports must not be empty');\n }\n this.visitList(used);\n break;\n case ts.SyntaxKind.NamedExports:\n let exportElements = (node).elements;\n this.emit('show');\n if (exportElements.length === 0) this.reportError(node, 'empty export list');\n this.visitList((node).elements);\n break;\n case ts.SyntaxKind.ImportSpecifier:\n case ts.SyntaxKind.ExportSpecifier:\n let spec = node;\n if (spec.propertyName) {\n this.reportError(spec.propertyName, 'import/export renames are unsupported in Dart');\n }\n this.fc.visitTypeName(spec.name);\n break;\n case ts.SyntaxKind.ExportDeclaration:\n let exportDecl = node;\n this.emit('export');\n if (exportDecl.moduleSpecifier) {\n this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier);\n } else {\n this.reportError(node, 're-exports must have a module URL (export x from \"./y\").');\n }\n if (exportDecl.exportClause) this.visit(exportDecl.exportClause);\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportEqualsDeclaration:\n let importEqDecl = node;\n this.emit('import');\n this.visit(importEqDecl.moduleReference);\n this.emit('as');\n this.fc.visitTypeName(importEqDecl.name);\n this.emit(';');\n break;\n case ts.SyntaxKind.ExternalModuleReference:\n this.visitExternalModuleReferenceExpr((node).expression);\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n private static isIgnoredImport(e: ts.ImportSpecifier) {\n // TODO: unify with facade_converter.ts\n let name = base.ident(e.name);\n switch (name) {\n case 'CONST':\n case 'CONST_EXPR':\n case 'normalizeBlank':\n case 'forwardRef':\n case 'ABSTRACT':\n case 'IMPLEMENTS':\n return true;\n default:\n return false;\n }\n }\n\n private visitExternalModuleReferenceExpr(expr: ts.Expression) {\n // TODO: what if this isn't a string literal?\n let moduleName = expr;\n let text = moduleName.text;\n if (text.match(/^\\.\\//)) {\n // Strip './' to be more Dart-idiomatic.\n text = text.substring(2).replace(/([A-Z])/g, function($1){return \"_\"+$1.toLowerCase();}).substring(1);\n } else if (!text.match(/^\\.\\.\\//)) {\n // Replace '@angular' with 'angular2' for Dart.\n text = text.replace(/^@keikai\\//, 'keikai/');\n // Unprefixed/absolute imports are package imports.\n text = 'package:' + text;\n }\n this.emit(JSON.stringify(text + '.dart'));\n }\n\n private isEmptyImport(n: ts.ImportDeclaration): boolean {\n let bindings = n.importClause.namedBindings;\n if (bindings.kind !== ts.SyntaxKind.NamedImports) return false;\n let elements = (bindings).elements;\n // An import list being empty *after* filtering is ok, but if it's empty in the code itself,\n // it's nonsensical code, so probably a programming error.\n if (elements.length === 0) this.reportError(n, 'empty import list');\n return elements.every(ModuleTranspiler.isIgnoredImport);\n }\n\n private filterImports(ns: ts.ImportOrExportSpecifier[]) {\n return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e));\n }\n\n // For the Dart keyword list see\n // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords\n private static DART_RESERVED_WORDS =\n ('assert break case catch class const continue default do else enum extends false final ' +\n 'finally for if in is new null rethrow return super switch this throw true try let void ' +\n 'while with')\n .split(/ /);\n\n getLibraryName(fileName: string) {\n fileName = this.getRelativeFileName(fileName);\n let parts = fileName.split('/');\n return parts.filter((p) => p.length > 0)\n .map((p) => p.replace(/^@/, ''))\n .map((p) => p.replace(/[^\\w.]/g, '_'))\n .map((p) => p.replace(/\\.[jt]s$/g, ''))\n .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p)\n .join('.');\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/statement.js b/build/lib/statement.js new file mode 100644 index 0000000..ac39b67 --- /dev/null +++ b/build/lib/statement.js @@ -0,0 +1,186 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var StatementTranspiler = (function (_super) { + __extends(StatementTranspiler, _super); + function StatementTranspiler(tr) { + _super.call(this, tr); + } + StatementTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.EmptyStatement: + this.emit(';'); + break; + case ts.SyntaxKind.ReturnStatement: + var retStmt = node; + this.emit('return'); + if (retStmt.expression) + this.visit(retStmt.expression); + this.emit(';'); + break; + case ts.SyntaxKind.BreakStatement: + case ts.SyntaxKind.ContinueStatement: + var breakContinue = node; + this.emit(breakContinue.kind === ts.SyntaxKind.BreakStatement ? 'break' : 'continue'); + if (breakContinue.label) + this.visit(breakContinue.label); + this.emit(';'); + break; + case ts.SyntaxKind.VariableStatement: + var variableStmt = node; + this.visit(variableStmt.declarationList); + this.emit(';'); + break; + case ts.SyntaxKind.ExpressionStatement: + var expr = node; + this.visit(expr.expression); + this.emit(';'); + break; + case ts.SyntaxKind.SwitchStatement: + var switchStmt = node; + this.emit('switch ('); + this.visit(switchStmt.expression); + this.emit(')'); + this.visit(switchStmt.caseBlock); + break; + case ts.SyntaxKind.CaseBlock: + this.emit('{'); + this.visitEach(node.clauses); + this.emit('}'); + break; + case ts.SyntaxKind.CaseClause: + var caseClause = node; + this.emit('case'); + this.visit(caseClause.expression); + this.emit(':'); + this.visitEach(caseClause.statements); + break; + case ts.SyntaxKind.DefaultClause: + this.emit('default :'); + this.visitEach(node.statements); + break; + case ts.SyntaxKind.IfStatement: + var ifStmt = node; + this.emit('if ('); + this.visit(ifStmt.expression); + this.emit(')'); + this.visit(ifStmt.thenStatement); + if (ifStmt.elseStatement) { + this.emit('else'); + this.visit(ifStmt.elseStatement); + } + break; + case ts.SyntaxKind.ForStatement: + var forStmt = node; + this.emit('for ('); + if (forStmt.initializer) + this.visit(forStmt.initializer); + this.emit(';'); + if (forStmt.condition) + this.visit(forStmt.condition); + this.emit(';'); + if (forStmt.incrementor) + this.visit(forStmt.incrementor); + this.emit(')'); + this.visit(forStmt.statement); + break; + case ts.SyntaxKind.ForInStatement: + // TODO(martinprobst): Dart's for-in loops actually have different semantics, they are more + // like for-of loops, iterating over collections. + var forInStmt = node; + this.emit('for ('); + if (forInStmt.initializer) + this.visit(forInStmt.initializer); + this.emit('in'); + this.visit(forInStmt.expression); + this.emit(')'); + this.visit(forInStmt.statement); + break; + case ts.SyntaxKind.ForOfStatement: + var forOfStmt = node; + this.emit('for ('); + if (forOfStmt.initializer) + this.visit(forOfStmt.initializer); + this.emit('in'); + this.visit(forOfStmt.expression); + this.emit(')'); + this.visit(forOfStmt.statement); + break; + case ts.SyntaxKind.WhileStatement: + var whileStmt = node; + this.emit('while ('); + this.visit(whileStmt.expression); + this.emit(')'); + this.visit(whileStmt.statement); + break; + case ts.SyntaxKind.DoStatement: + var doStmt = node; + this.emit('do'); + this.visit(doStmt.statement); + this.emit('while ('); + this.visit(doStmt.expression); + this.emit(') ;'); + break; + case ts.SyntaxKind.ThrowStatement: + var throwStmt = node; + var surroundingCatchClause = this.getAncestor(throwStmt, ts.SyntaxKind.CatchClause); + if (surroundingCatchClause) { + var ref = surroundingCatchClause.variableDeclaration; + if (ref.getText() === throwStmt.expression.getText()) { + this.emit('rethrow'); + this.emit(';'); + break; + } + } + this.emit('throw'); + this.visit(throwStmt.expression); + this.emit(';'); + break; + case ts.SyntaxKind.TryStatement: + var tryStmt = node; + this.emit('try'); + this.visit(tryStmt.tryBlock); + if (tryStmt.catchClause) { + this.visit(tryStmt.catchClause); + } + if (tryStmt.finallyBlock) { + this.emit('finally'); + this.visit(tryStmt.finallyBlock); + } + break; + case ts.SyntaxKind.CatchClause: + var ctch = node; + if (ctch.variableDeclaration.type) { + this.emit('on'); + this.visit(ctch.variableDeclaration.type); + } + this.emit('catch'); + this.emit('('); + this.visit(ctch.variableDeclaration.name); + this.emit(','); + this.visit(ctch.variableDeclaration.name); + this.emitNoSpace('_stack'); + this.emit(')'); + this.visit(ctch.block); + break; + case ts.SyntaxKind.Block: + this.emit('{'); + this.visitEach(node.statements); + this.emit('}'); + break; + default: + return false; + } + return true; + }; + return StatementTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = StatementTranspiler; + +//# sourceMappingURL=statement.js.map diff --git a/build/lib/statement.js.map b/build/lib/statement.js.map new file mode 100644 index 0000000..ef131e1 --- /dev/null +++ b/build/lib/statement.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["statement.ts"],"names":[],"mappings":"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","file":"statement.js","sourcesContent":["import * as ts from 'typescript';\nimport * as base from './base';\nimport {Transpiler} from './main';\n\ntype ClassLike = ts.ClassDeclaration | ts.InterfaceDeclaration;\n\nexport default class StatementTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler) { super(tr); }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.EmptyStatement:\n this.emit(';');\n break;\n case ts.SyntaxKind.ReturnStatement:\n let retStmt = node;\n this.emit('return');\n if (retStmt.expression) this.visit(retStmt.expression);\n this.emit(';');\n break;\n case ts.SyntaxKind.BreakStatement:\n case ts.SyntaxKind.ContinueStatement:\n let breakContinue = node;\n this.emit(breakContinue.kind === ts.SyntaxKind.BreakStatement ? 'break' : 'continue');\n if (breakContinue.label) this.visit(breakContinue.label);\n this.emit(';');\n break;\n case ts.SyntaxKind.VariableStatement:\n let variableStmt = node;\n this.visit(variableStmt.declarationList);\n this.emit(';');\n break;\n case ts.SyntaxKind.ExpressionStatement:\n let expr = node;\n this.visit(expr.expression);\n this.emit(';');\n break;\n case ts.SyntaxKind.SwitchStatement:\n let switchStmt = node;\n this.emit('switch (');\n this.visit(switchStmt.expression);\n this.emit(')');\n this.visit(switchStmt.caseBlock);\n break;\n case ts.SyntaxKind.CaseBlock:\n this.emit('{');\n this.visitEach((node).clauses);\n this.emit('}');\n break;\n case ts.SyntaxKind.CaseClause:\n let caseClause = node;\n this.emit('case');\n this.visit(caseClause.expression);\n this.emit(':');\n this.visitEach(caseClause.statements);\n break;\n case ts.SyntaxKind.DefaultClause:\n this.emit('default :');\n this.visitEach((node).statements);\n break;\n case ts.SyntaxKind.IfStatement:\n let ifStmt = node;\n this.emit('if (');\n this.visit(ifStmt.expression);\n this.emit(')');\n this.visit(ifStmt.thenStatement);\n if (ifStmt.elseStatement) {\n this.emit('else');\n this.visit(ifStmt.elseStatement);\n }\n break;\n case ts.SyntaxKind.ForStatement:\n let forStmt = node;\n this.emit('for (');\n if (forStmt.initializer) this.visit(forStmt.initializer);\n this.emit(';');\n if (forStmt.condition) this.visit(forStmt.condition);\n this.emit(';');\n if (forStmt.incrementor) this.visit(forStmt.incrementor);\n this.emit(')');\n this.visit(forStmt.statement);\n break;\n case ts.SyntaxKind.ForInStatement:\n // TODO(martinprobst): Dart's for-in loops actually have different semantics, they are more\n // like for-of loops, iterating over collections.\n let forInStmt = node;\n this.emit('for (');\n if (forInStmt.initializer) this.visit(forInStmt.initializer);\n this.emit('in');\n this.visit(forInStmt.expression);\n this.emit(')');\n this.visit(forInStmt.statement);\n break;\n case ts.SyntaxKind.ForOfStatement:\n let forOfStmt = node;\n this.emit('for (');\n if (forOfStmt.initializer) this.visit(forOfStmt.initializer);\n this.emit('in');\n this.visit(forOfStmt.expression);\n this.emit(')');\n this.visit(forOfStmt.statement);\n break;\n case ts.SyntaxKind.WhileStatement:\n let whileStmt = node;\n this.emit('while (');\n this.visit(whileStmt.expression);\n this.emit(')');\n this.visit(whileStmt.statement);\n break;\n case ts.SyntaxKind.DoStatement:\n let doStmt = node;\n this.emit('do');\n this.visit(doStmt.statement);\n this.emit('while (');\n this.visit(doStmt.expression);\n this.emit(') ;');\n break;\n\n case ts.SyntaxKind.ThrowStatement:\n let throwStmt = node;\n let surroundingCatchClause = this.getAncestor(throwStmt, ts.SyntaxKind.CatchClause);\n if (surroundingCatchClause) {\n let ref = (surroundingCatchClause).variableDeclaration;\n if (ref.getText() === throwStmt.expression.getText()) {\n this.emit('rethrow');\n this.emit(';');\n break;\n }\n }\n\n this.emit('throw');\n this.visit(throwStmt.expression);\n this.emit(';');\n break;\n case ts.SyntaxKind.TryStatement:\n let tryStmt = node;\n this.emit('try');\n this.visit(tryStmt.tryBlock);\n if (tryStmt.catchClause) {\n this.visit(tryStmt.catchClause);\n }\n if (tryStmt.finallyBlock) {\n this.emit('finally');\n this.visit(tryStmt.finallyBlock);\n }\n break;\n case ts.SyntaxKind.CatchClause:\n let ctch = node;\n if (ctch.variableDeclaration.type) {\n this.emit('on');\n this.visit(ctch.variableDeclaration.type);\n }\n this.emit('catch');\n this.emit('(');\n this.visit(ctch.variableDeclaration.name);\n this.emit(',');\n this.visit(ctch.variableDeclaration.name);\n this.emitNoSpace('_stack');\n this.emit(')');\n this.visit(ctch.block);\n break;\n\n case ts.SyntaxKind.Block:\n this.emit('{');\n this.visitEach((node).statements);\n this.emit('}');\n break;\n default:\n return false;\n }\n return true;\n }\n}\n"]} \ No newline at end of file diff --git a/build/lib/type.js b/build/lib/type.js new file mode 100644 index 0000000..a9da773 --- /dev/null +++ b/build/lib/type.js @@ -0,0 +1,119 @@ +"use strict"; +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var ts = require('typescript'); +var base = require('./base'); +var TypeTranspiler = (function (_super) { + __extends(TypeTranspiler, _super); + function TypeTranspiler(tr, fc) { + _super.call(this, tr); + this.fc = fc; + } + TypeTranspiler.prototype.visitNode = function (node) { + switch (node.kind) { + case ts.SyntaxKind.TypeLiteral: + var indexType = this.maybeDestructureIndexType(node); + if (indexType) { + // This is effectively a Map. + this.emit('Map <'); + this.visit(indexType[0]); + this.emit(','); + this.visit(indexType[1]); + this.emit('>'); + } + else { + // Dart doesn't support other type literals. + this.emit('dynamic'); + } + break; + case ts.SyntaxKind.UnionType: + this.emit('dynamic /*'); + this.visitList(node.types, '|'); + this.emit('*/'); + break; + case ts.SyntaxKind.TypeReference: + var typeRef = node; + this.fc.visitTypeName(typeRef.typeName); + this.maybeVisitTypeArguments(typeRef); + break; + case ts.SyntaxKind.TypeAssertionExpression: + var typeAssertExpr = node; + if (this.isReifiedTypeLiteral(typeAssertExpr)) { + this.visit(typeAssertExpr.expression); + break; // type is handled by the container literal itself. + } + this.emit('('); + this.visit(typeAssertExpr.expression); + this.emit('as'); + this.visit(typeAssertExpr.type); + this.emit(')'); + break; + case ts.SyntaxKind.TypeParameter: + var typeParam = node; + this.visit(typeParam.name); + if (typeParam.constraint) { + this.emit('extends'); + this.visit(typeParam.constraint); + } + break; + case ts.SyntaxKind.ArrayType: + this.emit('List'); + this.emit('<'); + this.visit(node.elementType); + this.emit('>'); + break; + case ts.SyntaxKind.FunctionType: + this.emit('dynamic /*'); + this.emit(node.getText()); + this.emit('*/'); + break; + case ts.SyntaxKind.QualifiedName: + var first = node; + this.visit(first.left); + this.emit('.'); + this.visit(first.right); + break; + case ts.SyntaxKind.Identifier: + var ident = node; + this.fc.visitTypeName(ident); + break; + case ts.SyntaxKind.NumberKeyword: + this.emit('num'); + break; + case ts.SyntaxKind.StringKeyword: + this.emit('String'); + break; + case ts.SyntaxKind.VoidKeyword: + this.emit('void'); + break; + case ts.SyntaxKind.BooleanKeyword: + this.emit('bool'); + break; + case ts.SyntaxKind.AnyKeyword: + this.emit('dynamic'); + break; + default: + return false; + } + return true; + }; + TypeTranspiler.prototype.isReifiedTypeLiteral = function (node) { + if (node.expression.kind === ts.SyntaxKind.ArrayLiteralExpression && + node.type.kind === ts.SyntaxKind.ArrayType) { + return true; + } + else if (node.expression.kind === ts.SyntaxKind.ObjectLiteralExpression && + node.type.kind === ts.SyntaxKind.TypeLiteral) { + return true; + } + return false; + }; + return TypeTranspiler; +}(base.TranspilerBase)); +exports.__esModule = true; +exports["default"] = TypeTranspiler; + +//# sourceMappingURL=type.js.map diff --git a/build/lib/type.js.map b/build/lib/type.js.map new file mode 100644 index 0000000..7f3fe25 --- /dev/null +++ b/build/lib/type.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["type.ts"],"names":[],"mappings":"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","file":"type.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class TypeTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.TypeLiteral:\n let indexType = this.maybeDestructureIndexType(node);\n if (indexType) {\n // This is effectively a Map.\n this.emit('Map <');\n this.visit(indexType[0]);\n this.emit(',');\n this.visit(indexType[1]);\n this.emit('>');\n } else {\n // Dart doesn't support other type literals.\n this.emit('dynamic');\n }\n break;\n case ts.SyntaxKind.UnionType:\n this.emit('dynamic /*');\n this.visitList((node).types, '|');\n this.emit('*/');\n break;\n case ts.SyntaxKind.TypeReference:\n let typeRef = node;\n this.fc.visitTypeName(typeRef.typeName);\n this.maybeVisitTypeArguments(typeRef);\n break;\n case ts.SyntaxKind.TypeAssertionExpression:\n let typeAssertExpr = node;\n if (this.isReifiedTypeLiteral(typeAssertExpr)) {\n this.visit(typeAssertExpr.expression);\n break; // type is handled by the container literal itself.\n }\n this.emit('(');\n this.visit(typeAssertExpr.expression);\n this.emit('as');\n this.visit(typeAssertExpr.type);\n this.emit(')');\n break;\n case ts.SyntaxKind.TypeParameter:\n let typeParam = node;\n this.visit(typeParam.name);\n if (typeParam.constraint) {\n this.emit('extends');\n this.visit(typeParam.constraint);\n }\n break;\n case ts.SyntaxKind.ArrayType:\n this.emit('List');\n this.emit('<');\n this.visit((node).elementType);\n this.emit('>');\n break;\n case ts.SyntaxKind.FunctionType:\n this.emit('dynamic /*');\n this.emit(node.getText());\n this.emit('*/');\n break;\n case ts.SyntaxKind.QualifiedName:\n let first = node;\n this.visit(first.left);\n this.emit('.');\n this.visit(first.right);\n break;\n case ts.SyntaxKind.Identifier:\n let ident = node;\n this.fc.visitTypeName(ident);\n break;\n case ts.SyntaxKind.NumberKeyword:\n this.emit('num');\n break;\n case ts.SyntaxKind.StringKeyword:\n this.emit('String');\n break;\n case ts.SyntaxKind.VoidKeyword:\n this.emit('void');\n break;\n case ts.SyntaxKind.BooleanKeyword:\n this.emit('bool');\n break;\n case ts.SyntaxKind.AnyKeyword:\n this.emit('dynamic');\n break;\n default:\n return false;\n }\n return true;\n }\n\n isReifiedTypeLiteral(node: ts.TypeAssertion): boolean {\n if (node.expression.kind === ts.SyntaxKind.ArrayLiteralExpression &&\n node.type.kind === ts.SyntaxKind.ArrayType) {\n return true;\n } else if (\n node.expression.kind === ts.SyntaxKind.ObjectLiteralExpression &&\n node.type.kind === ts.SyntaxKind.TypeLiteral) {\n return true;\n }\n return false;\n }\n}\n"]} \ No newline at end of file From 65073d207fe1bbe749c255f9eaab937f613d8f02 Mon Sep 17 00:00:00 2001 From: Jumper Chen Date: Wed, 30 Nov 2016 10:53:35 +0800 Subject: [PATCH 108/108] fix import syntax. --- build/lib/module.js | 9 +++++++-- build/lib/module.js.map | 2 +- lib/module.ts | 9 +++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/build/lib/module.js b/build/lib/module.js index a149d01..5c0b967 100644 --- a/build/lib/module.js +++ b/build/lib/module.js @@ -128,7 +128,11 @@ var ModuleTranspiler = (function (_super) { var text = moduleName.text; if (text.match(/^\.\//)) { // Strip './' to be more Dart-idiomatic. - text = text.substring(2).replace(/([A-Z])/g, function ($1) { return "_" + $1.toLowerCase(); }).substring(1); + text = text.substring(2).replace(/([A-Z])/g, function ($1) { return "_" + $1.toLowerCase(); }); + if (text.charAt(0) == '_') { + text = text.substring(1); + } + text = text.replace(/\/_/g, '\/'); } else if (!text.match(/^\.\.\//)) { // Replace '@angular' with 'angular2' for Dart. @@ -136,7 +140,8 @@ var ModuleTranspiler = (function (_super) { // Unprefixed/absolute imports are package imports. text = 'package:' + text; } - this.emit(JSON.stringify(text + '.dart')); + text = JSON.stringify(text + '.dart'); + this.emit("'" + (text.substring(1, text.length - 1)) + "'"); }; ModuleTranspiler.prototype.isEmptyImport = function (n) { var bindings = n.importClause.namedBindings; diff --git a/build/lib/module.js.map b/build/lib/module.js.map index c58752a..b602536 100644 --- a/build/lib/module.js.map +++ b/build/lib/module.js.map @@ -1 +1 @@ -{"version":3,"sources":["module.ts"],"names":[],"mappings":"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","file":"module.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class ModuleTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibraryName: boolean) {\n super(tr);\n }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.SourceFile:\n let sf = node;\n if (this.generateLibraryName) {\n this.emit('library');\n this.emit(this.getLibraryName(sf.fileName));\n this.emit(';');\n }\n this.fc.emitExtraImports(sf);\n ts.forEachChild(sf, this.visit.bind(this));\n break;\n case ts.SyntaxKind.EndOfFileToken:\n ts.forEachChild(node, this.visit.bind(this));\n break;\n case ts.SyntaxKind.ImportDeclaration:\n let importDecl = node;\n if (importDecl.importClause) {\n if (this.isEmptyImport(importDecl)) return true;\n this.emit('import');\n this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier);\n this.visit(importDecl.importClause);\n } else {\n this.reportError(importDecl, 'bare import is unsupported');\n }\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportClause:\n let importClause = node;\n if (importClause.name) this.fc.visitTypeName(importClause.name);\n if (importClause.namedBindings) {\n this.visit(importClause.namedBindings);\n }\n break;\n case ts.SyntaxKind.NamespaceImport:\n let nsImport = node;\n this.emit('as');\n this.fc.visitTypeName(nsImport.name);\n break;\n case ts.SyntaxKind.NamedImports:\n this.emit('show');\n let used = this.filterImports((node).elements);\n if (used.length === 0) {\n this.reportError(node, 'internal error, used imports must not be empty');\n }\n this.visitList(used);\n break;\n case ts.SyntaxKind.NamedExports:\n let exportElements = (node).elements;\n this.emit('show');\n if (exportElements.length === 0) this.reportError(node, 'empty export list');\n this.visitList((node).elements);\n break;\n case ts.SyntaxKind.ImportSpecifier:\n case ts.SyntaxKind.ExportSpecifier:\n let spec = node;\n if (spec.propertyName) {\n this.reportError(spec.propertyName, 'import/export renames are unsupported in Dart');\n }\n this.fc.visitTypeName(spec.name);\n break;\n case ts.SyntaxKind.ExportDeclaration:\n let exportDecl = node;\n this.emit('export');\n if (exportDecl.moduleSpecifier) {\n this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier);\n } else {\n this.reportError(node, 're-exports must have a module URL (export x from \"./y\").');\n }\n if (exportDecl.exportClause) this.visit(exportDecl.exportClause);\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportEqualsDeclaration:\n let importEqDecl = node;\n this.emit('import');\n this.visit(importEqDecl.moduleReference);\n this.emit('as');\n this.fc.visitTypeName(importEqDecl.name);\n this.emit(';');\n break;\n case ts.SyntaxKind.ExternalModuleReference:\n this.visitExternalModuleReferenceExpr((node).expression);\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n private static isIgnoredImport(e: ts.ImportSpecifier) {\n // TODO: unify with facade_converter.ts\n let name = base.ident(e.name);\n switch (name) {\n case 'CONST':\n case 'CONST_EXPR':\n case 'normalizeBlank':\n case 'forwardRef':\n case 'ABSTRACT':\n case 'IMPLEMENTS':\n return true;\n default:\n return false;\n }\n }\n\n private visitExternalModuleReferenceExpr(expr: ts.Expression) {\n // TODO: what if this isn't a string literal?\n let moduleName = expr;\n let text = moduleName.text;\n if (text.match(/^\\.\\//)) {\n // Strip './' to be more Dart-idiomatic.\n text = text.substring(2).replace(/([A-Z])/g, function($1){return \"_\"+$1.toLowerCase();}).substring(1);\n } else if (!text.match(/^\\.\\.\\//)) {\n // Replace '@angular' with 'angular2' for Dart.\n text = text.replace(/^@keikai\\//, 'keikai/');\n // Unprefixed/absolute imports are package imports.\n text = 'package:' + text;\n }\n this.emit(JSON.stringify(text + '.dart'));\n }\n\n private isEmptyImport(n: ts.ImportDeclaration): boolean {\n let bindings = n.importClause.namedBindings;\n if (bindings.kind !== ts.SyntaxKind.NamedImports) return false;\n let elements = (bindings).elements;\n // An import list being empty *after* filtering is ok, but if it's empty in the code itself,\n // it's nonsensical code, so probably a programming error.\n if (elements.length === 0) this.reportError(n, 'empty import list');\n return elements.every(ModuleTranspiler.isIgnoredImport);\n }\n\n private filterImports(ns: ts.ImportOrExportSpecifier[]) {\n return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e));\n }\n\n // For the Dart keyword list see\n // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords\n private static DART_RESERVED_WORDS =\n ('assert break case catch class const continue default do else enum extends false final ' +\n 'finally for if in is new null rethrow return super switch this throw true try let void ' +\n 'while with')\n .split(/ /);\n\n getLibraryName(fileName: string) {\n fileName = this.getRelativeFileName(fileName);\n let parts = fileName.split('/');\n return parts.filter((p) => p.length > 0)\n .map((p) => p.replace(/^@/, ''))\n .map((p) => p.replace(/[^\\w.]/g, '_'))\n .map((p) => p.replace(/\\.[jt]s$/g, ''))\n .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p)\n .join('.');\n }\n}\n"]} \ No newline at end of file +{"version":3,"sources":["module.ts"],"names":[],"mappings":"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","file":"module.js","sourcesContent":["import * as ts from 'typescript';\n\nimport * as base from './base';\nimport {FacadeConverter} from './facade_converter';\nimport {Transpiler} from './main';\n\nexport default class ModuleTranspiler extends base.TranspilerBase {\n constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibraryName: boolean) {\n super(tr);\n }\n\n visitNode(node: ts.Node): boolean {\n switch (node.kind) {\n case ts.SyntaxKind.SourceFile:\n let sf = node;\n if (this.generateLibraryName) {\n this.emit('library');\n this.emit(this.getLibraryName(sf.fileName));\n this.emit(';');\n }\n this.fc.emitExtraImports(sf);\n ts.forEachChild(sf, this.visit.bind(this));\n break;\n case ts.SyntaxKind.EndOfFileToken:\n ts.forEachChild(node, this.visit.bind(this));\n break;\n case ts.SyntaxKind.ImportDeclaration:\n let importDecl = node;\n if (importDecl.importClause) {\n if (this.isEmptyImport(importDecl)) return true;\n this.emit('import');\n this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier);\n this.visit(importDecl.importClause);\n } else {\n this.reportError(importDecl, 'bare import is unsupported');\n }\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportClause:\n let importClause = node;\n if (importClause.name) this.fc.visitTypeName(importClause.name);\n if (importClause.namedBindings) {\n this.visit(importClause.namedBindings);\n }\n break;\n case ts.SyntaxKind.NamespaceImport:\n let nsImport = node;\n this.emit('as');\n this.fc.visitTypeName(nsImport.name);\n break;\n case ts.SyntaxKind.NamedImports:\n this.emit('show');\n let used = this.filterImports((node).elements);\n if (used.length === 0) {\n this.reportError(node, 'internal error, used imports must not be empty');\n }\n this.visitList(used);\n break;\n case ts.SyntaxKind.NamedExports:\n let exportElements = (node).elements;\n this.emit('show');\n if (exportElements.length === 0) this.reportError(node, 'empty export list');\n this.visitList((node).elements);\n break;\n case ts.SyntaxKind.ImportSpecifier:\n case ts.SyntaxKind.ExportSpecifier:\n let spec = node;\n if (spec.propertyName) {\n this.reportError(spec.propertyName, 'import/export renames are unsupported in Dart');\n }\n this.fc.visitTypeName(spec.name);\n break;\n case ts.SyntaxKind.ExportDeclaration:\n let exportDecl = node;\n this.emit('export');\n if (exportDecl.moduleSpecifier) {\n this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier);\n } else {\n this.reportError(node, 're-exports must have a module URL (export x from \"./y\").');\n }\n if (exportDecl.exportClause) this.visit(exportDecl.exportClause);\n this.emit(';');\n break;\n case ts.SyntaxKind.ImportEqualsDeclaration:\n let importEqDecl = node;\n this.emit('import');\n this.visit(importEqDecl.moduleReference);\n this.emit('as');\n this.fc.visitTypeName(importEqDecl.name);\n this.emit(';');\n break;\n case ts.SyntaxKind.ExternalModuleReference:\n this.visitExternalModuleReferenceExpr((node).expression);\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n private static isIgnoredImport(e: ts.ImportSpecifier) {\n // TODO: unify with facade_converter.ts\n let name = base.ident(e.name);\n switch (name) {\n case 'CONST':\n case 'CONST_EXPR':\n case 'normalizeBlank':\n case 'forwardRef':\n case 'ABSTRACT':\n case 'IMPLEMENTS':\n return true;\n default:\n return false;\n }\n }\n\n private visitExternalModuleReferenceExpr(expr: ts.Expression) {\n // TODO: what if this isn't a string literal?\n let moduleName = expr;\n let text = moduleName.text;\n if (text.match(/^\\.\\//)) {\n // Strip './' to be more Dart-idiomatic.\n text = text.substring(2).replace(/([A-Z])/g, function($1){return \"_\"+$1.toLowerCase();});\n if (text.charAt(0) == '_') {\n text = text.substring(1);\n }\n text = text.replace(/\\/_/g, '\\/');\n } else if (!text.match(/^\\.\\.\\//)) {\n // Replace '@angular' with 'angular2' for Dart.\n text = text.replace(/^@keikai\\//, 'keikai/');\n // Unprefixed/absolute imports are package imports.\n text = 'package:' + text;\n }\n text = JSON.stringify(text + '.dart');\n this.emit(\"'\" + (text.substring(1, text.length - 1)) + \"'\");\n }\n\n private isEmptyImport(n: ts.ImportDeclaration): boolean {\n let bindings = n.importClause.namedBindings;\n if (bindings.kind !== ts.SyntaxKind.NamedImports) return false;\n let elements = (bindings).elements;\n // An import list being empty *after* filtering is ok, but if it's empty in the code itself,\n // it's nonsensical code, so probably a programming error.\n if (elements.length === 0) this.reportError(n, 'empty import list');\n return elements.every(ModuleTranspiler.isIgnoredImport);\n }\n\n private filterImports(ns: ts.ImportOrExportSpecifier[]) {\n return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e));\n }\n\n // For the Dart keyword list see\n // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords\n private static DART_RESERVED_WORDS =\n ('assert break case catch class const continue default do else enum extends false final ' +\n 'finally for if in is new null rethrow return super switch this throw true try let void ' +\n 'while with')\n .split(/ /);\n\n getLibraryName(fileName: string) {\n fileName = this.getRelativeFileName(fileName);\n let parts = fileName.split('/');\n return parts.filter((p) => p.length > 0)\n .map((p) => p.replace(/^@/, ''))\n .map((p) => p.replace(/[^\\w.]/g, '_'))\n .map((p) => p.replace(/\\.[jt]s$/g, ''))\n .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p)\n .join('.');\n }\n}\n"]} \ No newline at end of file diff --git a/lib/module.ts b/lib/module.ts index f046aa5..0718aeb 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -121,14 +121,19 @@ export default class ModuleTranspiler extends base.TranspilerBase { let text = moduleName.text; if (text.match(/^\.\//)) { // Strip './' to be more Dart-idiomatic. - text = text.substring(2).replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}).substring(1); + text = text.substring(2).replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}); + if (text.charAt(0) == '_') { + text = text.substring(1); + } + text = text.replace(/\/_/g, '\/'); } else if (!text.match(/^\.\.\//)) { // Replace '@angular' with 'angular2' for Dart. text = text.replace(/^@keikai\//, 'keikai/'); // Unprefixed/absolute imports are package imports. text = 'package:' + text; } - this.emit(JSON.stringify(text + '.dart')); + text = JSON.stringify(text + '.dart'); + this.emit("'" + (text.substring(1, text.length - 1)) + "'"); } private isEmptyImport(n: ts.ImportDeclaration): boolean {