diff --git a/gulpfile.js b/gulpfile.js index 96a91c95b1..30904c1bc6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -981,15 +981,16 @@ gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() { .pipe(gulp.dest(path.join(tmpdir, 'node_modules'))); }); gulp.task('!pre.test.typings.copyTypingsSpec', function() { - return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir))); + return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(tmpdir)); }); + gulp.task('test.typings', ['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() { var tsc = require('gulp-typescript'); - return gulp.src([tmpdir + '/**']) + return gulp.src([tmpdir + '/*.ts']) .pipe(tsc({ - target: 'ES5', + target: 'ES6', module: 'commonjs', experimentalDecorators: true, noImplicitAny: true, diff --git a/modules/angular2/manual_typings/globals-es6.d.ts b/modules/angular2/manual_typings/globals-es6.d.ts deleted file mode 100644 index 703f7de009..0000000000 --- a/modules/angular2/manual_typings/globals-es6.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Declarations angular depends on for compilation to ES6. - * This file is also used to propagate our transitive typings - * to users. - */ - -/// -/// - -// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all -// the code including client code -/// - -declare var assert: any; - - -interface BrowserNodeGlobal { - Object: typeof Object; - Array: typeof Array; - Map: typeof Map; - Set: typeof Set; - Date: typeof Date; - RegExp: typeof RegExp; - JSON: typeof JSON; - Math: typeof Math; - assert(condition: any): void; - Reflect: any; - zone: Zone; - getAngularTestability: Function; - getAllAngularTestabilities: Function; - frameworkStabilizers: Array; - setTimeout: Function; - clearTimeout: Function; - setInterval: Function; - clearInterval: Function; -} diff --git a/modules/angular2/manual_typings/globals.d.ts b/modules/angular2/manual_typings/globals.d.ts index 164d17e7a6..9ae16c2288 100644 --- a/modules/angular2/manual_typings/globals.d.ts +++ b/modules/angular2/manual_typings/globals.d.ts @@ -1,7 +1,52 @@ /** - * Declarations angular depends on for compilation to ES6. - * This file is also used to propagate our transitive typings - * to users. + * Subset of es6-shim typings. + * Angular should not require use of ES6 runtime but some API usages are already present. + * See https://github.com/angular/angular/issues/5242 + * TODO(alexeagle): remove methods below which may not be present in targeted browser */ -/// -/// + +declare type PromiseConstructor = typeof Promise; + +interface String { + /** + * Returns true if the sequence of elements of searchString converted to a String is the + * same as the corresponding elements of this object (converted to a String) starting at + * position. Otherwise returns false. + */ + startsWith(searchString: string, position?: number): boolean; + + /** + * Returns true if the sequence of elements of searchString converted to a String is the + * same as the corresponding elements of this object (converted to a String) starting at + * endPosition – length(this). Otherwise returns false. + */ + endsWith(searchString: string, endPosition?: number): boolean; +} +interface Array { + /** + * Returns the value of the first element in the array where predicate is true, and undefined + * otherwise. + * @param predicate find calls predicate once for each element of the array, in ascending + * order, until it finds one where predicate returns true. If such an element is found, find + * immediately returns that element value. Otherwise, find returns undefined. + * @param thisArg If provided, it will be used as the this value for each invocation of + * predicate. If it is not provided, undefined is used instead. + */ + find(predicate: (value: T, index: number, obj: Array) => boolean, thisArg?: any): T; + /** + * Returns the this object after filling the section identified by start and end with value + * @param value value to fill array section with + * @param start index to start filling the array at. If start is negative, it is treated as + * length+start where length is the length of the array. + * @param end index to stop filling the array at. If end is negative, it is treated as + * length+end. + */ + fill(value: T, start?: number, end?: number): T[]; +} +interface NumberConstructor { + /** + * Returns true if the value passed is an integer, false otherwise. + * @param number A numeric value. + */ + isInteger(number: number): boolean; +} diff --git a/modules/angular2/src/core/change_detection/parser/lexer.ts b/modules/angular2/src/core/change_detection/parser/lexer.ts index 460a43c8b6..dcfdb3f0f6 100644 --- a/modules/angular2/src/core/change_detection/parser/lexer.ts +++ b/modules/angular2/src/core/change_detection/parser/lexer.ts @@ -248,15 +248,12 @@ class _Scanner { } scanCharacter(start: number, code: number): Token { - assert(this.peek == code); this.advance(); return newCharacterToken(start, code); } scanOperator(start: number, str: string): Token { - assert(this.peek == StringWrapper.charCodeAt(str, 0)); - assert(SetWrapper.has(OPERATORS, str)); this.advance(); return newOperatorToken(start, str); } @@ -274,7 +271,6 @@ class _Scanner { */ scanComplexOperator(start: number, one: string, twoCode: number, two: string, threeCode?: number, three?: string): Token { - assert(this.peek == StringWrapper.charCodeAt(one, 0)); this.advance(); var str: string = one; if (this.peek == twoCode) { @@ -285,12 +281,10 @@ class _Scanner { this.advance(); str += three; } - assert(SetWrapper.has(OPERATORS, str)); return newOperatorToken(start, str); } scanIdentifier(): Token { - assert(isIdentifierStart(this.peek)); var start: number = this.index; this.advance(); while (isIdentifierPart(this.peek)) this.advance(); @@ -303,7 +297,6 @@ class _Scanner { } scanNumber(start: number): Token { - assert(isDigit(this.peek)); var simple: boolean = (this.index === start); this.advance(); // Skip initial digit. while (true) { @@ -329,7 +322,6 @@ class _Scanner { } scanString(): Token { - assert(this.peek == $SQ || this.peek == $DQ); var start: number = this.index; var quote: number = this.peek; this.advance(); // Skip initial quote. diff --git a/modules/angular2/src/core/zone/ng_zone.ts b/modules/angular2/src/core/zone/ng_zone.ts index 4e8a988c5b..abb086c3d8 100644 --- a/modules/angular2/src/core/zone/ng_zone.ts +++ b/modules/angular2/src/core/zone/ng_zone.ts @@ -1,9 +1,9 @@ import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; -import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang'; +import {normalizeBlank, isPresent, global, ZoneLike} from 'angular2/src/facade/lang'; import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async'; import {wtfLeave, wtfCreateScope, WtfScopeFn} from '../profile/profile'; -export interface NgZoneZone extends Zone { +export interface NgZoneZone extends ZoneLike { /** @internal */ _innerZone: boolean; } @@ -348,8 +348,9 @@ export class NgZone { var errorHandling; if (enableLongStackTrace) { - errorHandling = StringMapWrapper.merge( - Zone.longStackTraceZone, {onError: function(e) { ngZone._notifyOnError(this, e); }}); + errorHandling = + StringMapWrapper.merge(global.Zone.longStackTraceZone, + {onError: function(e) { ngZone._notifyOnError(this, e); }}); } else { errorHandling = {onError: function(e) { ngZone._notifyOnError(this, e); }}; } diff --git a/modules/angular2/src/facade/async.ts b/modules/angular2/src/facade/async.ts index 5b9e33fdc5..ababf8a355 100644 --- a/modules/angular2/src/facade/async.ts +++ b/modules/angular2/src/facade/async.ts @@ -15,20 +15,16 @@ import {toPromise} from 'rxjs/operator/toPromise'; export {Observable} from 'rxjs/Observable'; export {Subject} from 'rxjs/Subject'; -export namespace NodeJS { - export interface Timer {} -} - export class TimerWrapper { - static setTimeout(fn: (...args: any[]) => void, millis: number): NodeJS.Timer { + static setTimeout(fn: (...args: any[]) => void, millis: number): number { return global.setTimeout(fn, millis); } - static clearTimeout(id: NodeJS.Timer): void { global.clearTimeout(id); } + static clearTimeout(id: number): void { global.clearTimeout(id); } - static setInterval(fn: (...args: any[]) => void, millis: number): NodeJS.Timer { + static setInterval(fn: (...args: any[]) => void, millis: number): number { return global.setInterval(fn, millis); } - static clearInterval(id: NodeJS.Timer): void { global.clearInterval(id); } + static clearInterval(id: number): void { global.clearInterval(id); } } export class ObservableWrapper { @@ -161,4 +157,4 @@ export class EventEmitter extends Subject { return super.subscribe(schedulerFn, errorFn, completeFn); } -} \ No newline at end of file +} diff --git a/modules/angular2/src/facade/lang.ts b/modules/angular2/src/facade/lang.ts index d19007a553..25a161e059 100644 --- a/modules/angular2/src/facade/lang.ts +++ b/modules/angular2/src/facade/lang.ts @@ -1,3 +1,36 @@ +// Zones are TC-39 standards-track so users could choose a different implementation +// Rather than import {Zone} from 'zone.js' we define an interface +// so that any library that structurally matches may be used with Angular 2. +export interface ZoneLike { + fork(locals?: any): ZoneLike; + run(fn: any, applyTo?: any, applyWith?: any): any; +} +export interface ZoneLikeConstructor { + longStackTraceZone: { [key: string]: any; }; +} + +export interface BrowserNodeGlobal { + Object: typeof Object; + Array: typeof Array; + Map: typeof Map; + Set: typeof Set; + Date: DateConstructor; + RegExp: RegExpConstructor; + JSON: typeof JSON; + Math: any; // typeof Math; + assert(condition: any): void; + Reflect: any; + zone: ZoneLike; + Zone: ZoneLikeConstructor; + getAngularTestability: Function; + getAllAngularTestabilities: Function; + frameworkStabilizers: Array; + setTimeout: Function; + clearTimeout: Function; + setInterval: Function; + clearInterval: Function; +} + // TODO(jteplitz602): Load WorkerGlobalScope from lib.webworker.d.ts file #3492 declare var WorkerGlobalScope; var globalScope: BrowserNodeGlobal; @@ -10,7 +43,7 @@ if (typeof window === 'undefined') { } } else { globalScope = window; -}; +} export const IS_DART = false; @@ -430,4 +463,4 @@ export function evalExpression(sourceUrl: string, expr: string, declarations: st export function isPrimitive(obj: any): boolean { return !isJsObject(obj); -} \ No newline at end of file +} diff --git a/tools/broccoli/trees/browser_tree.ts b/tools/broccoli/trees/browser_tree.ts index 46e588f6b0..abdaa6c3f0 100644 --- a/tools/broccoli/trees/browser_tree.ts +++ b/tools/broccoli/trees/browser_tree.ts @@ -171,6 +171,14 @@ module.exports = function makeBrowserTree(options, destinationPath) { patterns: [{match: /\$SCRIPTS\$/, replacement: jsReplace('SCRIPTS')}] }); + let ambientTypings = [ + 'angular2/typings/hammerjs/hammerjs.d.ts', + 'angular2/typings/node/node.d.ts', + 'angular2/manual_typings/globals.d.ts', + 'angular2/typings/es6-collections/es6-collections.d.ts', + 'angular2/typings/es6-promise/es6-promise.d.ts' + ]; + // Use TypeScript to transpile the *.ts files to ES5 var es5Tree = compileWithTypescript(es5ModulesTree, { declaration: false, @@ -180,7 +188,7 @@ module.exports = function makeBrowserTree(options, destinationPath) { moduleResolution: 'classic', noEmitOnError: !noTypeChecks, rootDir: './', - rootFilePaths: ['angular2/manual_typings/globals.d.ts'], + rootFilePaths: ambientTypings, inlineSourceMap: sourceMaps, inlineSources: sourceMaps, target: 'es5' @@ -311,7 +319,11 @@ module.exports = function makeBrowserTree(options, destinationPath) { experimentalDecorators: true, noEmitOnError: false, rootDir: './', - rootFilePaths: ['angular2/manual_typings/globals-es6.d.ts'], + rootFilePaths: [ + 'angular2/typings/zone.js/zone.js.d.ts', + 'angular2/typings/hammerjs/hammerjs.d.ts', + 'angular2/typings/node/node.d.ts', + ], inlineSourceMap: sourceMaps, inlineSources: sourceMaps, target: 'es6' diff --git a/tools/broccoli/trees/node_tree.ts b/tools/broccoli/trees/node_tree.ts index 69384fcbb9..52ba9ce55f 100644 --- a/tools/broccoli/trees/node_tree.ts +++ b/tools/broccoli/trees/node_tree.ts @@ -32,9 +32,16 @@ module.exports = function makeNodeTree(projects, destinationPath) { ] }); + let ambientTypings = [ + 'angular2/typings/hammerjs/hammerjs.d.ts', + 'angular2/typings/node/node.d.ts', + 'angular2/manual_typings/globals.d.ts', + 'angular2/typings/es6-collections/es6-collections.d.ts', + 'angular2/typings/es6-promise/es6-promise.d.ts' + ]; + // Compile the sources and generate the @internal .d.ts - let compiledSrcTreeWithInternals = - compileTree(srcTree, true, ['angular2/manual_typings/globals.d.ts']); + let compiledSrcTreeWithInternals = compileTree(srcTree, true, ambientTypings); var testTree = new Funnel('modules', { include: [ @@ -85,11 +92,10 @@ module.exports = function makeNodeTree(projects, destinationPath) { testTree = mergeTrees([testTree, srcPrivateDeclarations]); - let compiledTestTree = compileTree(testTree, false, [ + let compiledTestTree = compileTree(testTree, false, ambientTypings.concat([ 'angular2/typings/jasmine/jasmine.d.ts', 'angular2/typings/angular-protractor/angular-protractor.d.ts', - 'angular2/manual_typings/globals.d.ts' - ]); + ])); // Merge the compiled sources and tests let compiledSrcTree = @@ -112,12 +118,7 @@ module.exports = function makeNodeTree(projects, destinationPath) { var srcPkgJsons = extractPkgJsons(srcTree, BASE_PACKAGE_JSON); var testPkgJsons = extractPkgJsons(testTree, BASE_PACKAGE_JSON); - var typingsTree = new Funnel( - 'modules', - {include: ['angular2/typings/**/*.d.ts', 'angular2/manual_typings/*.d.ts'], destDir: '/'}); - - var nodeTree = - mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons, typingsTree]); + var nodeTree = mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons]); // Transform all tests to make them runnable in node nodeTree = replace(nodeTree, { @@ -139,22 +140,6 @@ module.exports = function makeNodeTree(projects, destinationPath) { nodeTree = replace( nodeTree, {files: ['**/*.js'], patterns: [{match: /^/, replacement: () => `'use strict';`}]}); - // Add a line to the end of our top-level .d.ts file. - // This HACK for transitive typings is a workaround for - // https://github.com/Microsoft/TypeScript/issues/5097 - // - // This allows users to get our top-level dependencies like zone.d.ts - // to appear when they compile against angular2. - // - // This carries the risk that the user brings their own copy of that file - // (or any other symbols exported here) and they will get a compiler error - // because of the duplicate definitions. - // TODO(alexeagle): remove this when typescript releases a fix - nodeTree = replace(nodeTree, { - files: ['angular2/core.d.ts'], - patterns: [{match: /$/, replacement: 'import "./manual_typings/globals-es6.d.ts";\r\n'}] - }); - return destCopy(nodeTree, destinationPath); };