| Index: test/facade_converter_test.ts
|
| diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts
|
| index e779fead7090611588a49252103b70ff07abfc45..ad635fdd8f90ff595abe6d8a3a8272e57b4cc4d1 100644
|
| --- a/test/facade_converter_test.ts
|
| +++ b/test/facade_converter_test.ts
|
| @@ -1,7 +1,7 @@
|
| /// <reference path="../typings/mocha/mocha.d.ts"/>
|
| import * as fs from 'fs';
|
| -import {expectTranslate, FAKE_MAIN, translateSource} from './test_support';
|
| -import chai = require('chai');
|
| +
|
| +import {expectTranslate, FAKE_MAIN} from './test_support';
|
|
|
| let es6RuntimeDeclarations = `
|
| interface Iterable<T> {}
|
| @@ -28,20 +28,8 @@ let es6RuntimeDeclarations = `
|
| 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<T>(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': `
|
| - export {Observable} from 'rxjs/Observable';`,
|
| - 'angular2/src/facade/collection.ts': `
|
| - export declare var Map;`,
|
| - 'angular2/src/facade/lang.d.ts': `
|
| - interface List<T> extends Array<T> {}
|
| - export declare function CONST_EXPR<T>(x: T): T;
|
| - export declare var normalizeBlank: (x: Object) => any;`,
|
| 'other/file.ts': `
|
| export class X {
|
| map(x: number): string { return String(x); }
|
| @@ -64,399 +52,76 @@ function expectWithTypes(str: string) {
|
| return expectTranslate(getSources(str), COMPILE_OPTS);
|
| }
|
|
|
| -function expectErroneousWithType(str: string) {
|
| - return chai.expect(() => translateSource(getSources(str), COMPILE_OPTS));
|
| -}
|
| -
|
| describe('type based translation', () => {
|
| describe('Dart type substitution', () => {
|
| it('finds registered substitutions', () => {
|
| - expectWithTypes(
|
| - 'import {Observable} from "angular2/src/facade/async"; var o: Observable<Date>;')
|
| - .to.equal(`import "package:angular2/src/facade/async.dart" show Stream;
|
| + expectWithTypes('const n: Node;').to.equal(`import "dart:html";
|
|
|
| -Stream<DateTime> o;`);
|
| - expectWithTypes('var p: Promise<void> = x;').to.equal(`import "dart:async";
|
| +@JS()
|
| +external Node get n;`);
|
| + expectWithTypes('const xhr: XMLHttpRequest;').to.equal(`import "dart:html";
|
|
|
| -Future p = x;`);
|
| - expectWithTypes('var y: Promise;').to.equal(`import "dart:async";
|
| +@JS()
|
| +external HttpRequest get xhr;`);
|
| + expectWithTypes('const intArray: Uint8Array;').to.equal(`import "dart:typed_data";
|
|
|
| -Future y;`);
|
| - expectWithTypes('var n: Node;').to.equal('dynamic n;');
|
| - expectWithTypes('var xhr: XMLHttpRequest;').to.equal(`import "dart:html";
|
| +@JS()
|
| +external Uint8List get intArray;`);
|
| + expectWithTypes('const buff: ArrayBuffer;').to.equal(`import "dart:typed_data";
|
|
|
| -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;`);
|
| +@JS()
|
| +external ByteBuffer get buff;`);
|
| });
|
|
|
| - 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"; var y = x instanceof Promise;')
|
| - .to.equal(`import "package:other/file.dart" show Promise;
|
| -
|
| -var y = x is Promise;`);
|
| + it('allows undeclared types', () => {
|
| + expectWithTypes('const t: Thing;').to.equal(`@JS()
|
| +external Thing get t;`);
|
| });
|
| -
|
| - it('does not substitute all identifiers',
|
| - () => { expectWithTypes('let Promise = 1;').to.equal(`var Promise = 1;`); });
|
| });
|
|
|
| - describe('collection façade', () => {
|
| - it('translates array operations to dartisms', () => {
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.push(1); x.pop(); }')
|
| - .to.equal(`f() {
|
| - List<num> x = [];
|
| - x.add(1);
|
| - x.removeLast();
|
| -}`);
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.map((e) => e); }')
|
| - .to.equal(`f() {
|
| - List<num> x = [];
|
| - x.map((e) => e).toList();
|
| -}`);
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.filter((e) => true); }')
|
| - .to.equal(`f() {
|
| - List<num> x = [];
|
| - x.where((e) => true).toList();
|
| -}`);
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.unshift(1, 2, 3); x.shift(); }')
|
| - .to.equal(`f() {
|
| - List<num> x = [];
|
| - (x..insertAll(0, [1, 2, 3])).length;
|
| - x.removeAt(0);
|
| -}`);
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.unshift(1); }').to.equal(`f() {
|
| - List<num> x = [];
|
| - (x..insert(0, 1)).length;
|
| -}`);
|
| - expectWithTypes('function f() { var x: Array<number> = []; x.concat([1], x).length; }')
|
| - .to.equal(`f() {
|
| - List<num> x = [];
|
| - (new List.from(x)..addAll([1])..addAll(x)).length;
|
| -}`);
|
| - expectWithTypes('var x: Array<number> = []; var y: Array<number> = x.slice(0);')
|
| - .to.equal(`List<num> x = [];
|
| -List<num> y = ListWrapper.slice(x, 0);`);
|
| - expectWithTypes('var x: Array<number> = []; var y: Array<number> = x.splice(0,1);')
|
| - .to.equal(`List<num> x = [];
|
| -List<num> y = ListWrapper.splice(x, 0, 1);`);
|
| - expectWithTypes('var x: Array<number> = []; var y: string = x.join("-");')
|
| - .to.equal(`List<num> x = [];
|
| -String y = x.join("-");`);
|
| - expectWithTypes('var x: Array<number> = []; var y: string = x.join();')
|
| - .to.equal(`List<num> x = [];
|
| -String y = x.join(",");`);
|
| - expectWithTypes('var x: Array<number> = []; var y: number = x.find((e) => e == 0);')
|
| - .to.equal(`List<num> x = [];
|
| -num y = x.firstWhere((e) => e == 0, orElse: () => null);`);
|
| - expectWithTypes('var x: Array<number> = []; var y: boolean = x.some((e) => e == 0);')
|
| - .to.equal(`List<num> x = [];
|
| -bool y = x.any((e) => e == 0);`);
|
| - expectWithTypes('var x: Array<number> = []; var y: number = x.reduce((a, b) => a + b, 0);')
|
| - .to.equal(`List<num> x = [];
|
| -num y = x.fold(0, (a, b) => a + b);`);
|
| - expectWithTypes('var x: Array<number> = []; var y: number = x.reduce((a, b) => a + b);')
|
| - .to.equal(`List<num> x = [];
|
| -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(" "));');
|
| + describe('skip top level calls', () => {
|
| + it('console.log', () => {
|
| + expectWithTypes(`console.log(1);`).to.equal('');
|
| + expectWithTypes(`console.log(1, 2);`).to.equal('');
|
| });
|
| -
|
| - 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<string, string>(); x.set("k", "v"); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x["k"] = "v";
|
| -}`);
|
| - expectWithTypes('function f() { var x = new Map<string, string>(); x.get("k"); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x["k"];
|
| -}`);
|
| - expectWithTypes('function f() { var x = new Map<string, string>(); x.has("k"); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x.containsKey("k");
|
| -}`);
|
| - expectWithTypes('function f() { var x = new Map<string, string>(); x.delete("k"); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - (x.containsKey("k") && (x.remove("k") != null || true));
|
| -}`);
|
| - expectWithTypes(
|
| - 'function f() { var x = new Map<string, string>(); x.forEach((v, k) => null); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x.forEach((k, v) => null);
|
| -}`);
|
| - expectWithTypes(
|
| - 'function f() { var x = new Map<string, string>(); x.forEach(function (v, k) { return null; }); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x.forEach((k, v) {
|
| - return null;
|
| - });
|
| -}`);
|
| - expectWithTypes(
|
| - 'function f() { var x = new Map<string, string>(); var y = x.forEach((v, k) => { return null; }); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - var y = x.forEach((k, v) {
|
| - return null;
|
| - });
|
| -}`);
|
| -
|
| - expectWithTypes('function f() { var x = new Map<string, string>(); x.forEach(fn); }')
|
| - .to.equal(`f() {
|
| - var x = new Map<String, String>();
|
| - x.forEach((k, v) => (fn)(v, k));
|
| -}`);
|
| - });
|
| -
|
| - it('translates map properties to dartisms', () => {
|
| - expectWithTypes('var x = new Map<string, string>();var y = x.size;')
|
| - .to.equal(`var x = new Map<String, String>();
|
| -var y = x.length;`);
|
| - });
|
| - });
|
| -
|
| - describe('regexp', () => {
|
| - expectWithTypes('function f() { var x = /a/g; x.test("a"); }').to.equal(`f() {
|
| - 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', () => {
|
| - 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<any> = 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<dynamic> 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) {
|
| - print(v);
|
| - }).catchError((err) {
|
| - print(err);
|
| });
|
| -}`);
|
| - expectWithTypes(
|
| - 'var fn: () => Promise<number>;' +
|
| - 'function main() { fn().then((v) => { console.log(v) }).catch((err) => { console.log(err); }); }')
|
| - .to.equal(`import "dart:async";
|
|
|
| -dynamic /* () => Promise<number> */ fn;
|
| -main() {
|
| - fn().then((v) {
|
| - print(v);
|
| - }).catchError((err) {
|
| - print(err);
|
| - });
|
| -}`);
|
| + describe('const', () => {
|
| + it('simple', () => {
|
| + expectWithTypes('const x = 1;').to.equal(`@JS()
|
| +external get x;`);
|
| + expectWithTypes('const x = [];').to.equal(`@JS()
|
| +external get x;`);
|
| expectWithTypes(
|
| - 'var fn: () => Promise<number>;' +
|
| - 'function main() { fn().then((v) => { console.log(v) }, (err) => { console.log(err); }); }')
|
| - .to.equal(`import "dart:async";
|
| + 'class Person {}' +
|
| + 'const x = new Person();')
|
| + .to.equal(`@JS()
|
| +class Person {
|
| + // @Ignore
|
| + Person.fakeConstructor$();
|
| +}
|
|
|
| -dynamic /* () => Promise<number> */ fn;
|
| -main() {
|
| - fn().then((v) {
|
| - print(v);
|
| - }).catchError((err) {
|
| - print(err);
|
| - });
|
| -}`);
|
| +@JS()
|
| +external get x;`);
|
| });
|
| });
|
|
|
| - 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([]);')
|
| - .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<number, string>());')
|
| - .to.equal(`import "package:angular2/src/facade/collection.dart" show Map;
|
| -
|
| -const x = const <num, String>{};`);
|
| -
|
| - 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(<string[]>[]);`)
|
| - .to.equal(`const _EMPTY_LIST = const <String>[];`);
|
| - expectWithTypes(`
|
| - import {CONST_EXPR} from "angular2/src/facade/lang";
|
| - const MY_MAP = CONST_EXPR(<{[k: string]: number}>{});`)
|
| - .to.equal(`const MY_MAP = const <String, num>{};`);
|
| - });
|
| -
|
| - 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('function f() { var x = []; Array.isArray(x); }').to.equal(`f() {
|
| - var x = [];
|
| - ((x) is List);
|
| -}`);
|
| + expectWithTypes('function f() : string[] {}').to.equal(`@JS()
|
| +external List<String> f();`);
|
| });
|
|
|
| describe('error detection', () => {
|
| - describe('Map', () => {
|
| - it('.forEach() should report an error when the callback doesn\'t have 2 args', () => {
|
| - expectErroneousWithType('var x = new Map<string, string>(); x.forEach((v, k, m) => null);')
|
| - .to.throw('Map.forEach callback requires exactly two arguments');
|
| - });
|
| - });
|
| -
|
| - describe('Array', () => {
|
| - it('.concat() should report an error if any arg is not an Array', () => {
|
| - expectErroneousWithType('var x: Array<number> = []; x.concat(1);')
|
| - .to.throw('Array.concat only takes Array arguments');
|
| - });
|
| - });
|
| -
|
| - it('for untyped symbols matching special cased fns', () => {
|
| - expectErroneousWithType('forwardRef(1)').to.throw(/Untyped property access to "forwardRef"/);
|
| - });
|
| -
|
| - it('for untyped symbols matching special cased methods', () => {
|
| - expectErroneousWithType('x.push(1)').to.throw(/Untyped property access to "push"/);
|
| - });
|
| -
|
| - it('allows unrelated methods', () => {
|
| + it('support imports', () => {
|
| expectWithTypes(
|
| 'import {X} from "other/file";\n' +
|
| - '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");`)
|
| + 'let x:X;')
|
| .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();');
|
| +@JS()
|
| +external X get x;
|
| +@JS()
|
| +external set x(X v);`);
|
| });
|
| });
|
| });
|
|
|