diff --git a/docs/dart/writing-compatible-typescript.md b/docs/dart/writing-compatible-typescript.md index 890129cf96f..9eecda2f62b 100644 --- a/docs/dart/writing-compatible-typescript.md +++ b/docs/dart/writing-compatible-typescript.md @@ -38,3 +38,6 @@ Here's a list of gotchas to keep in mind when writing TypeScript code that will * **Accessing any platform primitive must be done through a Facade.** For example, Promises or DOM manipulation. Facades are going to be provided on a need-to-have basis. * **Union types are a no-go.** Dart has them on its roadmap, but for now we must avoid them. * **Dart files cannot have the same name as a reserved keyword.** For example, `for.dart`, `switch.dart` or `class.dart` are all invalid names. Since the TypeScript files have the same name when transpiled to Dart, they also have the same restriction. +* **Default values need to be constants.** This mean that code like `function myFunction(arg1: string = callToSomething()) {}` will not compile. +* **The const keyword must have a const value.** Because of that, we cannot do `const x = a + b;` even if the value of `x`, `a` and `b` will not change. +* **Lambdas need to abide to the type required.** Meaning that if a function requires a function that takes one argument, the lambda cannot be `() => {}`. Use `_` for temporary parameters. This is notable in Promises. diff --git a/ember-cli-build.js b/ember-cli-build.js index 1e48d26473e..581dd98bc13 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -57,7 +57,7 @@ function getDartTree(root) { const dartSources = new BroccoliFunnel(root, { include: ['**/*.dart'], - destDir: 'dart/web', + destDir: 'dart/lib', }); const allDartFiles = mergeTrees([ @@ -79,7 +79,7 @@ function getDartTree(root) { return mergeTrees([ dartSources, pubSpecTree, - new BroccoliDestCopy(formatter, 'dart/web'), + new BroccoliDestCopy(formatter, 'dart/lib'), ]); } diff --git a/package.json b/package.json index 2f83a3b5ef3..176f2da87df 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "scripts": { "build": "ng build", - "dartanalyzer": "ts-node scripts/ci/dart_analyzer", + "dartanalyzer": "cd dist/dart && pub install && cd ../.. && ts-node scripts/ci/dart_analyzer", "demo-app": "cd src && ng serve", "test": "karma start test/karma.conf.js" }, @@ -51,7 +51,7 @@ "strip-ansi": "^3.0.0", "symlink-or-copy": "^1.0.1", "ts-node": "^0.5.5", - "ts2dart": "^0.7.20", + "ts2dart": "^0.7.24", "tslint": "^3.2.2", "typescript": "^1.7.5", "which": "^1.2.4" diff --git a/pubspec.yaml b/pubspec.yaml index 62017320c5f..2d7e6696b62 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,4 +13,4 @@ transformers: - angular2: platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES' entry_points: - - web/src/demo-app/demo-app.dart + - lib/demo-app/demo-app.dart diff --git a/src/components/card/card.ts b/src/components/card/card.ts index f8ea4b014f6..3330b26e143 100644 --- a/src/components/card/card.ts +++ b/src/components/card/card.ts @@ -1,5 +1,5 @@ import {Component, View, ViewEncapsulation} from 'angular2/core'; -import {CONST_EXPR, Type} from 'angular2/src/facade/lang'; +import {CONST_EXPR} from 'angular2/src/facade/lang'; /* @@ -66,6 +66,5 @@ TODO(kara): update link to demo site when it exists }) export class MdCardTitleGroup {} -export const MD_CARD_DIRECTIVES: Type[] = - CONST_EXPR([MdCard, MdCardHeader, MdCardTitleGroup]); +export const MD_CARD_DIRECTIVES: any[] = CONST_EXPR([MdCard, MdCardHeader, MdCardTitleGroup]); diff --git a/src/components/sidenav/sidenav.spec.ts b/src/components/sidenav/sidenav.spec.ts index 8d698c6129d..d5b4e46c4db 100644 --- a/src/components/sidenav/sidenav.spec.ts +++ b/src/components/sidenav/sidenav.spec.ts @@ -15,13 +15,17 @@ import {By} from 'angular2/platform/browser'; import {MdSidenav, MdSidenavLayout, MD_SIDENAV_DIRECTIVES} from './sidenav'; import {AsyncTestFn, FunctionWithParamTokens} from 'angular2/testing'; -import {ComponentFixture} from "angular2/testing"; -import {EventEmitter} from "angular2/core"; -import {Predicate} from "angular2/src/facade/collection"; +import {ComponentFixture} from 'angular2/testing'; +import {EventEmitter} from 'angular2/core'; +import {Predicate} from 'angular2/src/facade/collection'; +import {PromiseWrapper} from 'angular2/src/facade/promise'; +import {TimerWrapper} from 'angular2/src/facade/async'; function wait(msec: number) { - return new Promise(resolve => window.setTimeout(() => resolve(), msec)); + let completer = PromiseWrapper.completer(); + TimerWrapper.setTimeout(completer.resolve, msec); + return completer.promise; } @@ -31,10 +35,10 @@ function waitOnEvent(fixture: ComponentFixture, fixture.detectChanges(); // Wait for the animation end. - return new Promise(resolve => { - const component: any = fixture.debugElement.query(by).componentInstance; - component[propertyName].subscribe(resolve); - }); + let completer = PromiseWrapper.completer(); + let component: any = fixture.debugElement.query(by).componentInstance; + component[propertyName].subscribe(completer.resolve); + return completer.promise; } @@ -56,47 +60,47 @@ export function main() { fixture = f; testComponent = fixture.debugElement.componentInstance; - const openButtonElement = fixture.debugElement.query(By.css('.open')); + let openButtonElement = fixture.debugElement.query(By.css('.open')); openButtonElement.nativeElement.click(); }) - .then(() => wait(1)) - .then(() => { + .then((_: any) => { wait(1); }) + .then((_: any) => { expect(testComponent.openStartCount).toBe(1); expect(testComponent.openCount).toBe(0); }) - .then(() => waitOnEvent(fixture, By.directive(MdSidenav), 'onOpen')) - .then(() => { + .then((_: any) => waitOnEvent(fixture, By.directive(MdSidenav), 'onOpen')) + .then((_: any) => { expect(testComponent.openStartCount).toBe(1); expect(testComponent.openCount).toBe(1); expect(testComponent.closeStartCount).toBe(0); expect(testComponent.closeCount).toBe(0); - const sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); - const sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); + let sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); + let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); expect(window.getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('visible'); expect(window.getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('visible'); // Close it. - const closeButtonElement = fixture.debugElement.query(By.css('.close')); + let closeButtonElement = fixture.debugElement.query(By.css('.close')); closeButtonElement.nativeElement.click(); }) - .then(() => wait(1)) - .then(() => { + .then((_: any) => wait(1)) + .then((_: any) => { expect(testComponent.openStartCount).toBe(1); expect(testComponent.openCount).toBe(1); expect(testComponent.closeStartCount).toBe(1); expect(testComponent.closeCount).toBe(0); }) - .then(() => waitOnEvent(fixture, By.directive(MdSidenav), 'onClose')) - .then(() => fixture.detectChanges()) - .then(() => { + .then((_: any) => waitOnEvent(fixture, By.directive(MdSidenav), 'onClose')) + .then((_: any) => fixture.detectChanges()) + .then((_: any) => { expect(testComponent.openStartCount).toBe(1); expect(testComponent.openCount).toBe(1); expect(testComponent.closeStartCount).toBe(1); expect(testComponent.closeCount).toBe(1); - const sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); - const sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); + let sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); + let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); expect(window.getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('hidden'); expect(window.getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('hidden'); }) @@ -105,11 +109,10 @@ export function main() { it('open() and close() return a promise that resolves after the animation ended', (done: any) => { - let testComponent: BasicTestApp; let fixture: ComponentFixture; let sidenav: MdSidenav; - let promise: Promise<{}>; + let promise: Promise; let called: boolean = false; return builder.createAsync(BasicTestApp) @@ -118,38 +121,36 @@ export function main() { sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance; promise = sidenav.open(); - promise.then(() => called = true); + promise.then((_: any) => called = true); }) - .then(() => wait(1)) - .then(() => fixture.detectChanges()) - .then(() => { + .then((_: any) => wait(1)) + .then((_: any) => fixture.detectChanges()) + .then((_: any) => { expect(called).toBe(false); }) - .then(() => promise) - .then(() => expect(called).toBe(true)) - .then(() => { + .then((_: any) => promise) + .then((_: any) => expect(called).toBe(true)) + .then((_: any) => { // Close it now. called = false; promise = sidenav.close(); - promise.then(() => called = true); + promise.then((_: any) => called = true); }) - .then(() => wait(1)) - .then(() => fixture.detectChanges()) - .then(() => { + .then((_: any) => wait(1)) + .then((_: any) => fixture.detectChanges()) + .then((_: any) => { expect(called).toBe(false); }) - .then(() => promise) - .then(() => expect(called).toBe(true)) + .then((_: any) => promise) + .then((_: any) => expect(called).toBe(true)) .then(done, done.fail); }, 8000); it('open() twice returns the same promise', (done: any) => { - let testComponent: BasicTestApp; let fixture: ComponentFixture; let sidenav: MdSidenav; - let promise: Promise<{}>; - let called: boolean = false; + let promise: Promise; return builder.createAsync(BasicTestApp) .then((f) => { @@ -159,12 +160,12 @@ export function main() { promise = sidenav.open(); expect(sidenav.open()).toBe(promise); }) - .then(() => wait(1)) - .then(() => { + .then((_: any) => wait(1)) + .then((_: any) => { fixture.detectChanges(); return promise; }) - .then(() => { + .then((_: any) => { promise = sidenav.close(); expect(sidenav.close()).toBe(promise); }) @@ -173,12 +174,11 @@ export function main() { it('open() then close() cancel animations when called too fast', (done: any) => { - let testComponent: BasicTestApp; let fixture: ComponentFixture; let sidenav: MdSidenav; - let openPromise: Promise; - let closePromise: Promise; + let openPromise: Promise; + let closePromise: Promise; let openCalled: boolean = false; let openCancelled: boolean = false; let closeCalled: boolean = false; @@ -188,28 +188,28 @@ export function main() { fixture = f; sidenav = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance; - openPromise = sidenav.open().then(() => { + openPromise = sidenav.open().then((_: any) => { openCalled = true; }, () => { openCancelled = true; }); }) - .then(() => wait(1)) - .then(() => fixture.detectChanges()) + .then((_: any) => wait(1)) + .then((_: any) => fixture.detectChanges()) // We need to wait for the browser to start the transition. - .then(() => wait(50)) - .then(() => { - closePromise = sidenav.close().then(() => { + .then((_: any) => wait(50)) + .then((_: any) => { + closePromise = sidenav.close().then((_: any) => { closeCalled = true; }, done.fail); return wait(1); }) - .then(() => { + .then((_: any) => { fixture.detectChanges(); return closePromise; }) - .then(() => { + .then((_: any) => { expect(openCalled).toBe(false); expect(openCancelled).toBe(true); expect(closeCalled).toBe(true); @@ -223,8 +223,8 @@ export function main() { let fixture: ComponentFixture; let sidenav: MdSidenav; - let openPromise: Promise; - let closePromise: Promise; + let openPromise: Promise; + let closePromise: Promise; let closeCalled: boolean = false; let closeCancelled: boolean = false; let openCalled: boolean = false; @@ -237,35 +237,35 @@ export function main() { /** First, open it. */ openPromise = sidenav.open(); }) - .then(() => wait(1)) - .then(() => { + .then((_: any) => wait(1)) + .then((_: any) => { fixture.detectChanges(); return openPromise; }) - .then(() => { + .then((_: any) => { // Then close and check behavior. - closePromise = sidenav.close().then(() => { + closePromise = sidenav.close().then((_: any) => { closeCalled = true; }, () => { closeCancelled = true; }); }) - .then(() => wait(1)) - .then(() => fixture.detectChanges()) + .then((_: any) => wait(1)) + .then((_: any) => fixture.detectChanges()) // We need to wait for the browser to start the transition. - .then(() => wait(50)) - .then(() => { - openPromise = sidenav.open().then(() => { + .then((_: any) => wait(50)) + .then((_: any) => { + openPromise = sidenav.open().then((_: any) => { openCalled = true; }, done.fail); return wait(1); }) - .then(() => { + .then((_: any) => { fixture.detectChanges(); return openPromise; }) - .then(() => { + .then((_: any) => { expect(closeCalled).toBe(false); expect(closeCancelled).toBe(true); expect(openCalled).toBe(true); diff --git a/src/components/sidenav/sidenav.ts b/src/components/sidenav/sidenav.ts index 496cbebc164..b0309489b5e 100644 --- a/src/components/sidenav/sidenav.ts +++ b/src/components/sidenav/sidenav.ts @@ -18,8 +18,9 @@ import { SimpleChange, Type } from 'angular2/core'; +import {PromiseWrapper} from 'angular2/src/facade/promise'; import {BaseException} from 'angular2/src/facade/exceptions'; -import {CONST_EXPR} from 'angular2/src/facade/lang'; +import {CONST_EXPR, isPresent} from 'angular2/src/facade/lang'; import {Dir} from '../../directives/dir/dir'; import {OneOf} from '../../core/annotations/one-of'; @@ -91,7 +92,7 @@ export class MdSidenav { /** Open this sidenav, and return a Promise that will resolve when it's fully opened (or get * rejected if it didn't). */ - open(): Promise<{}> { + open(): Promise { return this.toggle(true); } @@ -99,7 +100,7 @@ export class MdSidenav { * Close this sidenav, and return a Promise that will resolve when it's fully closed (or get * rejected if it didn't). */ - close(): Promise<{}> { + close(): Promise { return this.toggle(false); } @@ -108,11 +109,14 @@ export class MdSidenav { * close() when it's closed. * @param isOpen */ - toggle(isOpen: boolean = !this.opened): Promise<{}> { + toggle(isOpen?: boolean): Promise { + if (!isPresent(isOpen)) { + isOpen = !this.opened; + } // Shortcut it if we're already opened. if (isOpen === this.opened) { if (!this.transition_) { - return Promise.resolve(null); + return PromiseWrapper.resolve(null); } else { return isOpen ? this.openPromise_ : this.closePromise_; } @@ -127,23 +131,23 @@ export class MdSidenav { this.onCloseStart.emit(null); } - const emitter = isOpen ? this.onOpen : this.onClose; - const other = isOpen ? this.onClose : this.onOpen; + let emitter = isOpen ? this.onOpen : this.onClose; + let other = isOpen ? this.onClose : this.onOpen; if (isOpen) { - if (!this.openPromise_) { - this.openPromise_ = new Promise<{}>((resolve, reject) => { - this.openPromiseResolve_ = resolve; - this.openPromiseReject_ = reject; - }); + if (this.openPromise_ == null) { + let completer = PromiseWrapper.completer(); + this.openPromise_ = completer.promise; + this.openPromiseReject_ = completer.reject; + this.openPromiseResolve_ = completer.resolve; } return this.openPromise_; } else { - if (!this.closePromise_) { - this.closePromise_ = new Promise<{}>((resolve, reject) => { - this.closePromiseResolve_ = resolve; - this.closePromiseReject_ = reject; - }); + if (this.closePromise_ == null) { + let completer = PromiseWrapper.completer(); + this.closePromise_ = completer.promise; + this.closePromiseReject_ = completer.reject; + this.closePromiseResolve_ = completer.resolve; } return this.closePromise_; } @@ -163,19 +167,19 @@ export class MdSidenav { && e.propertyName.endsWith('transform')) { this.transition_ = false; if (this.opened_) { - if (this.openPromise_) { + if (this.openPromise_ != null) { this.openPromiseResolve_(); } - if (this.closePromise_) { + if (this.closePromise_ != null) { this.closePromiseReject_(); } this.onOpen.emit(null); } else { - if (this.closePromise_) { + if (this.closePromise_ != null) { this.closePromiseResolve_(); } - if (this.openPromise_) { + if (this.openPromise_ != null) { this.openPromiseReject_(); } @@ -225,10 +229,10 @@ export class MdSidenav { } private transition_: boolean = false; - private openPromise_: Promise<{}>; + private openPromise_: Promise; private openPromiseResolve_: () => void; private openPromiseReject_: () => void; - private closePromise_: Promise<{}>; + private closePromise_: Promise; private closePromiseResolve_: () => void; private closePromiseReject_: () => void; } @@ -256,7 +260,7 @@ export class MdSidenavLayout implements AfterContentInit { constructor(@Optional() @Host() private dir_: Dir) { // If a `Dir` directive exists up the tree, listen direction changes and update the left/right // properties to point to the proper start/end. - if (dir_) { + if (dir_ != null) { dir_.dirChange.subscribe(() => this.validateDrawers_()); } } @@ -294,12 +298,12 @@ export class MdSidenavLayout implements AfterContentInit { // Ensure that we have at most one start and one end sidenav. this.sidenavs_.toArray().forEach(drawer => { if (drawer.align == 'end') { - if (this.end_) { + if (this.end_ != null) { throw new MdDuplicatedSidenavException('end'); } this.end_ = drawer; } else { - if (this.start_) { + if (this.start_ != null) { throw new MdDuplicatedSidenavException('start'); } this.start_ = drawer; @@ -309,7 +313,7 @@ export class MdSidenavLayout implements AfterContentInit { this.right_ = this.left_ = null; // Detect if we're LTR or RTL. - if (!this.dir_ || this.dir_.value == 'ltr') { + if (this.dir_ == null || this.dir_.value == 'ltr') { this.left_ = this.start_; this.right_ = this.end_; } else { @@ -319,17 +323,17 @@ export class MdSidenavLayout implements AfterContentInit { } private closeModalSidenav_() { - if (this.start_ && this.start_.mode != 'side') { + if (this.start_ != null && this.start_.mode != 'side') { this.start_.close(); } - if (this.end_ && this.end_.mode != 'side') { + if (this.end_ != null && this.end_.mode != 'side') { this.end_.close(); } } private isShowingBackdrop_() { - return (this.start_ && this.start_.mode != 'side' && this.start_.opened) - || (this.end_ && this.end_.mode != 'side' && this.end_.opened); + return (this.start_ != null && this.start_.mode != 'side' && this.start_.opened) + || (this.end_ != null && this.end_.mode != 'side' && this.end_.opened); } /** @@ -339,7 +343,7 @@ export class MdSidenavLayout implements AfterContentInit { * @private */ private getSidenavEffectiveWidth_(sidenav: MdSidenav, mode: string): number { - if (sidenav && sidenav.mode == mode && sidenav.opened) { + if (sidenav != null && sidenav.mode == mode && sidenav.opened) { return sidenav.width_; } return 0; diff --git a/src/directives/dir/dir.ts b/src/directives/dir/dir.ts index a17406ed8f9..b5ea5b8f020 100644 --- a/src/directives/dir/dir.ts +++ b/src/directives/dir/dir.ts @@ -16,14 +16,14 @@ import {OneOf} from "../../core/annotations/one-of"; export class Dir { @Input('dir') @OneOf(['ltr', 'rtl']) private dir_: string = 'ltr'; - @Output() dirChange = new EventEmitter<{}>(); + @Output() dirChange = new EventEmitter(); @HostBinding('attr.dir') get dir(): string { return this.dir_; } set dir(v: string) { - const old = this.dir_; + let old = this.dir_; this.dir_ = v; if (old != this.dir_) { this.dirChange.emit(null); diff --git a/src/main.dart b/src/main.dart index 00f69757865..f7ba799b182 100644 --- a/src/main.dart +++ b/src/main.dart @@ -1,6 +1,6 @@ import "package:angular2/platform/browser.dart" show bootstrap; import "./demo-app/demo-app.dart" show DemoApp; -import "package:angular2/router" show ROUTER_PROVIDERS; +import "package:angular2/router.dart" show ROUTER_PROVIDERS; void main() { bootstrap(DemoApp, [ROUTER_PROVIDERS]); diff --git a/tslint.json b/tslint.json index 59dec90e520..c9cd1dd3791 100644 --- a/tslint.json +++ b/tslint.json @@ -19,6 +19,8 @@ "no-trailing-whitespace": true, "no-bitwise": true, "no-shadowed-variable": true, + "no-unused-expression": true, + "no-unused-variable": true, "one-line": [ true, "check-catch",