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 new file mode 100644 index 0000000..b6b12c1 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,8 @@ +{ + "base": "git:origin/master", + "phabricator.uri" : "https://reviews.angular.io/", + "load": [ + ".arc/npm-test" + ], + "unit.engine": "NpmUnitTestEngine" +} diff --git a/.gitignore b/.gitignore index c894330..8730bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Compiled JS -build # Logs logs @@ -9,6 +8,7 @@ logs pids *.pid *.seed +.phutil_module_cache # Type definitions installed with tsd typings @@ -30,3 +30,7 @@ node_modules # Users Environment Variables .lock-wscript + +# IDEs +.idea/ +/ts2dart.iml diff --git a/README.md b/README.md index c89c2f2..ef7886f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # 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 mainly used to translate Angular 2 from TypeScript +to Dart for its Dart user base. -ts2dart is a TypeScript to Dart transpiler. It's in its very early days and under heavy development, -not ready for production use. +## Usage + +- To install as Command Line Tool execute: `npm i -g ts2dart` +- Once installed you could run it doing: `ts2dart inputFile.ts` ## Installation @@ -15,3 +19,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", ... 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":"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","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..5c0b967 --- /dev/null +++ b/build/lib/module.js @@ -0,0 +1,181 @@ +"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(); }); + 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; + } + text = JSON.stringify(text + '.dart'); + this.emit("'" + (text.substring(1, text.length - 1)) + "'"); + }; + 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..b602536 --- /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();});\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/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 diff --git a/gulpfile.js b/gulpfile.js index c0923f5..191db4e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,12 +8,14 @@ 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'); 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 +23,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; @@ -84,15 +93,16 @@ 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 + '/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=. ' + - '*.ts angular2/src/facade/lang.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')); + onError(new Error('Failed to transpile ' + testfile + '.ts')); } else { try { var opts = {stdio: 'inherit', cwd: dir}; @@ -110,7 +120,30 @@ gulp.task('test.e2e', ['test.compile'], function(done) { }); }); -gulp.task('test', ['test.unit', 'test.check-format', 'test.e2e']); +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); + 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"/) || + !content.match(/Future/)) { + 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/base.ts b/lib/base.ts index 5c21ee4..f63ad39 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -6,18 +6,20 @@ 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 idCounter: number = 0; constructor(private transpiler: Transpiler) {} 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); } @@ -29,15 +31,27 @@ 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.idCounter++; + 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) { + for (let parent = n; parent; parent = parent.parent) { if (parent.kind === kind) return parent; } return null; @@ -48,10 +62,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; }); @@ -61,21 +75,32 @@ 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) { + 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); } maybeVisitTypeArguments(n: {typeArguments?: ts.NodeArray}) { if (n.typeArguments) { - this.emit('<'); + // 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('>'); } diff --git a/lib/call.ts b/lib/call.ts index 2c39743..5f350d1 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,20 +16,23 @@ export default class CallTranspiler extends base.TranspilerBase { } return false; case ts.SyntaxKind.NewExpression: + let 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)) { + } else if (this.fc.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; case ts.SyntaxKind.CallExpression: - var callExpr = node; + let callExpr = node; if (this.fc.maybeHandleCall(callExpr)) break; if (this.maybeHandleSuperCall(callExpr)) break; this.visitCall(callExpr); @@ -44,31 +47,36 @@ export default class CallTranspiler extends base.TranspilerBase { } private visitCall(c: ts.CallExpression) { - 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.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)) { - 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(')'); } - 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. @@ -77,23 +85,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); @@ -114,27 +122,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.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!) 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; @@ -150,7 +158,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; @@ -160,18 +168,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(':'); @@ -201,9 +209,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 8ceaf05..ecd51f0 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( @@ -13,11 +14,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,14 +28,15 @@ 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.emit('abstract'); + this.visitClassLike('abstract class', classDecl); + } else { + this.visitClassLike('class', classDecl); } - this.visitClassLike('class', classDecl); 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) { @@ -45,9 +47,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'); @@ -56,14 +58,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'); } @@ -79,25 +81,25 @@ 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; } } 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); @@ -123,17 +125,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); - if (funcDecl.typeParameters) this.reportError(node, 'generic functions are unsupported'); 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 +143,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) || @@ -176,28 +177,29 @@ 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; + 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); + } if (paramDecl.initializer) { this.emit('='); 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'); break; @@ -207,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; @@ -233,13 +258,26 @@ 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 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 = 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'); + 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 { @@ -251,30 +289,44 @@ 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 || + 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(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); } } @@ -291,19 +343,23 @@ 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(']'); } this.emit(')'); + if ((this)['__async']) { + this.emit('async'); + (this)['__async'] = false; + } } /** @@ -311,16 +367,16 @@ 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.fc.hasConstComment(decl) || this.hasAnnotation(decl.decorators, 'CONST'); + let hasConstCtor = this.fc.isConstClass(containingClass); if (isConstField) { // const implies final this.emit('const'); } else { - var hasConstCtor = this.isConst(containingClass); if (hasConstCtor) { this.emit('final'); } @@ -360,19 +416,19 @@ 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)); 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"); + .some((m) => m.kind === ts.SyntaxKind.Constructor)) { + this.emit('const'); this.fc.visitTypeName(decl.name); - this.emit("();") + this.emit('();'); } this.emit('}'); } @@ -382,10 +438,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. @@ -403,16 +459,16 @@ 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; // 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 "_"'); } @@ -423,18 +479,44 @@ 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 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 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'); + } + 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('}'); + } + + 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; } - this.visit(paramDecl.name); - 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'); + 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; } /** diff --git a/lib/expression.ts b/lib/expression.ts index 9d974ea..5f49d2d 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); } @@ -9,41 +10,81 @@ 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; - 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) { + let binExpr = node; + let operatorKind = binExpr.operatorToken.kind; + let 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); - } 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); + let prefixUnary = node; + let 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; + 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); @@ -51,24 +92,28 @@ 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: - 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`. @@ -83,7 +128,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); @@ -95,4 +140,15 @@ export default class ExpressionTranspiler extends base.TranspilerBase { } return true; } + + 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/lib/facade_converter.ts b/lib/facade_converter.ts index 619fef9..cd4fcc4 100644 --- a/lib/facade_converter.ts +++ b/lib/facade_converter.ts @@ -1,5 +1,7 @@ -import * as base from './base'; +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; @@ -10,82 +12,141 @@ 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} = {}; + 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 defaultLibLocation: string; private candidateProperties: {[propertyName: string]: boolean} = {}; private candidateTypes: {[typeName: string]: boolean} = {}; + private genericMethodDeclDepth = 0; 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.extractPropertyNames(this.tsToDartTypeNames, this.candidateTypes); + } + + initializeTypeBasedConversion( + tc: ts.TypeChecker, opts: ts.CompilerOptions, host: ts.CompilerHost) { + 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); } 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); } } - setTypeChecker(tc: ts.TypeChecker) { this.tc = tc; } - - 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); + 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]; + } + } - if (!symbol) { - this.reportMissingType(c, ident); + /** + * 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; + let remaining = ole.properties.filter((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 as ts.PropertyAssignment).initializer; return false; } + return true; // include below. + }); - 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); + if (!classParam) { + this.reportError(ole, 'missing provide: element'); + return false; + } - // Error will be reported by PropertyAccess handling below. - if (!symbol) return false; + this.emit('const Provider('); + this.visit(classParam); + if (remaining.length > 0) { + this.emit(','); + 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) < remaining.length) this.emit(','); + } + this.emit(')'); + } + return true; + } - context = pa.expression; - } else { - // Not a call we recognize. + maybeHandleCall(c: ts.CallExpression): boolean { + if (!this.tc) return false; + 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); + 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); + if (!this.stdlibTypeReplacements[ident]) { + 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); } @@ -93,31 +154,111 @@ 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" + let libraries = >{ + 'XMLHttpRequest': 'dart:html', + 'KeyboardEvent': 'dart:html', + 'Uint8Array': 'dart:typed_arrays', + 'ArrayBuffer': 'dart:typed_arrays', + 'Promise': 'dart:async', + 'HttpRequest.getString': 'dart:html', }; - 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}";`); + 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. + 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; + 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((n: ts.Node) => this.emitImports(n, libraries, emitted, sourceFile)); + .forEach((child: ts.Node) => this.emitImports(child, libraries, emitted, sourceFile)); + } + + pushTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + this.genericMethodDeclDepth++; + } + + popTypeParameterNames(n: ts.FunctionLikeDeclaration) { + if (!n.typeParameters) return; + 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 + * 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( + // 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) { @@ -125,16 +266,38 @@ export class FacadeConverter extends base.TranspilerBase { this.visit(typeName); return; } - 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. + this.emit('dynamic/*='); + this.emit(ident); + this.emit('*/'); + return; + } + 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); + 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) { - var 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; @@ -144,11 +307,61 @@ export class FacadeConverter extends base.TranspilerBase { this.emit(ident); } + shouldEmitNew(c: ts.CallExpression): boolean { + if (!this.tc) return true; + + let ci = this.getCallInformation(c); + let symbol = ci.symbol; + // getCallInformation returns a symbol if we understand this call. + if (!symbol) return true; + + let loc = this.getFileAndName(c, symbol); + if (!loc) return true; + 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} { + let symbol: ts.Symbol; + let context: ts.Expression; + let ident: string; + let 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. + let 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, symbol}; + } + 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]; } @@ -167,46 +380,97 @@ export class FacadeConverter extends base.TranspilerBase { decl = symbol.declarations[0]; } - var fileName = decl.getSourceFile().fileName; - fileName = this.getRelativeFileName(fileName); - fileName = fileName.replace(/(\.d)?\.ts$/, ''); + const canonicalFileName = decl.getSourceFile().fileName.replace(/(\.d)?\.ts$/, ''); - 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.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, 'qn:', qname); - return {fileName, qname}; + if (FACADE_DEBUG) console.error('cfn:', canonicalFileName, 'qn:', qname); + return {fileName: canonicalFileName, qname}; } - private isNamedType(node: ts.Node, fileName: string, qname: string): boolean { - var symbol = this.tc.getTypeAtLocation(node).getSymbol(); + private isNamedDefaultLibType(node: ts.Node, qname: string): boolean { + let symbol = this.tc.getTypeAtLocation(node).getSymbol(); if (!symbol) return false; - var 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; + let actual = this.getFileAndName(node, symbol); + return actual.fileName === this.defaultLibLocation && qname === actual.qname; } 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.`); } + 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 { - return this.isConstCall( - this.getAncestor(node, ts.SyntaxKind.CallExpression)); + 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; + 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; + } + + 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'); + }); } - private isConstCall(node: ts.CallExpression): boolean { - return node && base.ident(node.expression) === 'CONST_EXPR'; + /** + * 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 (this.hasConstComment(node)) { + return true; + } + + return node.kind === ts.SyntaxKind.CallExpression && + base.ident((node).expression) === 'CONST_EXPR'; + } + + 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(markerText) !== -1) { + return true; + } + } + return false; } private emitMethodCall(name: string, args?: ts.Expression[]) { @@ -227,6 +491,15 @@ export class FacadeConverter extends base.TranspilerBase { '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 @@ -243,113 +516,77 @@ export class FacadeConverter extends base.TranspilerBase { 'Location': 'dynamic', }; - private TS_TO_DART_TYPENAMES: ts.Map> = { - 'lib': this.stdlibTypeReplacements, - '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'}, + private tsToDartTypeNames: ts.Map> = { + [DEFAULT_LIB_MARKER]: this.stdlibTypeReplacements, 'angular2/src/facade/lang': {'Date': 'DateTime'}, + + 'rxjs/Observable': {'Observable': 'Stream'}, + 'es6-promise/es6-promise': {'Promise': 'Future'}, + 'es6-shim/es6-shim': {'Promise': 'Future'}, }; - private stdlibHandlers: ts.Map = { - 'Array.push': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('add', c.arguments); - }, - 'Array.pop': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('removeLast'); - }, - 'Array.shift': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emit('. removeAt ( 0 )'); - }, - 'Array.unshift': (c: ts.CallExpression, context: ts.Expression) => { - this.emit('('); + private es6Promises: ts.Map = { + 'Promise.catch': (c: ts.CallExpression, context: ts.Expression) => { 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': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('map', c.arguments); - this.emitMethodCall('toList'); - }, - 'Array.filter': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('where', c.arguments); - this.emitMethodCall('toList'); - }, - 'Array.some': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - this.emitMethodCall('any', c.arguments); - }, - 'Array.slice': (c: ts.CallExpression, context: ts.Expression) => { - this.emitCall('ListWrapper.slice', [context, ...c.arguments]); - }, - 'Array.splice': (c: ts.CallExpression, context: ts.Expression) => { - this.emitCall('ListWrapper.splice', [context, ...c.arguments]); + this.emit('.catchError('); + this.visitList(c.arguments); + this.emit(')'); }, - 'Array.concat': (c: ts.CallExpression, context: ts.Expression) => { - this.emit('( new List . from ('); + '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(')'); - c.arguments.forEach(arg => { - if (!this.isNamedType(arg, 'lib', 'Array')) { - this.reportError(arg, 'Array.concat only takes Array arguments'); - } - this.emit('.. addAll ('); - this.visit(arg); + if (c.arguments.length > 1) { + this.emit('.catchError('); + this.visit(c.arguments[1]); this.emit(')'); - }); - this.emit(')'); - }, - 'Array.join': (c: ts.CallExpression, context: ts.Expression) => { - this.visit(context); - if (c.arguments.length) { - this.emitMethodCall('join', c.arguments); - } else { - this.emit('. join ( "," )'); } }, - 'Array.reduce': (c: ts.CallExpression, context: ts.Expression) => { - 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(')'); + '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]); } - }, - 'ArrayConstructor.isArray': (c: ts.CallExpression, context: ts.Expression) => { - this.emit('( ('); - this.visitList(c.arguments); // Should only be 1. - this.emit(')'); - this.emit('is List'); - 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'); + 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('})()'); }, }; @@ -375,8 +612,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); @@ -394,7 +631,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; } @@ -411,7 +648,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; } @@ -421,7 +658,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); @@ -441,14 +678,153 @@ export class FacadeConverter extends base.TranspilerBase { 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); + }, + 'Array.pop': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emitMethodCall('removeLast'); + }, + 'Array.shift': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emit('. removeAt ( 0 )'); + }, + 'Array.unshift': (c: ts.CallExpression, context: ts.Expression) => { + 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': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emitMethodCall('map', c.arguments); + this.emitMethodCall('toList'); + }, + 'Array.filter': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emitMethodCall('where', c.arguments); + this.emitMethodCall('toList'); + }, + 'Array.some': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + this.emitMethodCall('any', c.arguments); + }, + 'Array.slice': (c: ts.CallExpression, context: ts.Expression) => { + this.emitCall('ListWrapper.slice', [context, ...c.arguments]); + }, + 'Array.splice': (c: ts.CallExpression, context: ts.Expression) => { + this.emitCall('ListWrapper.splice', [context, ...c.arguments]); + }, + 'Array.concat': (c: ts.CallExpression, context: ts.Expression) => { + this.emit('( new List . from ('); + this.visit(context); + this.emit(')'); + c.arguments.forEach(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': (c: ts.CallExpression, context: ts.Expression) => { + this.visit(context); + if (c.arguments.length) { + this.emitMethodCall('join', c.arguments); + } else { + this.emit('. join ( "," )'); + } + }, + 'Array.reduce': (c: ts.CallExpression, context: ts.Expression) => { + 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': (c: ts.CallExpression, context: ts.Expression) => { + this.emit('( ('); + this.visitList(c.arguments); // Should only be 1. + this.emit(')'); + 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.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); + }, + '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 callHandlerReplaceNew: ts.Map> = { + [DEFAULT_LIB_MARKER]: {'Promise': true}, }; private callHandlers: ts.Map> = { - 'lib': this.stdlibHandlers, - 'lib.es6': this.stdlibHandlers, - 'angular2/typings/es6-shim/es6-shim': this.es6Collections, - 'angular2/typings/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 => { @@ -485,7 +861,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); - } + }, }, }; @@ -496,9 +872,20 @@ export class FacadeConverter extends base.TranspilerBase { this.emit('length'); }, }; + private es6PromisesProp: ts.Map = { + 'PromiseConstructor.resolve': (p: ts.PropertyAccessExpression) => { + this.emit('new '); + this.visit(p.expression); + this.emit('.value'); + }, + 'PromiseConstructor.reject': (p: ts.PropertyAccessExpression) => { + this.emit('new '); + this.visit(p.expression); + this.emit('.error'); + }, + }; private propertyHandlers: ts.Map> = { - 'angular2/typings/es6-shim/es6-shim': this.es6CollectionsProp, - 'angular2/typings/es6-collections/es6-collections': this.es6CollectionsProp, + [DEFAULT_LIB_MARKER]: merge(this.es6CollectionsProp, this.es6PromisesProp), }; } diff --git a/lib/literal.ts b/lib/literal.ts index 745c8fd..64e37c4 100644 --- a/lib/literal.ts +++ b/lib/literal.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; + import * as base from './base'; +import {FacadeConverter} from './facade_converter'; import {Transpiler} from './main'; -import {FacadeConverter} from "./facade_converter"; export default class LiteralTranspiler extends base.TranspilerBase { constructor(tr: Transpiler, private fc: FacadeConverter) { super(tr); } @@ -10,14 +11,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 +28,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 +40,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('${'); @@ -50,23 +51,28 @@ 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: + let ole = node; + if (this.fc.maybeHandleProvider(ole)) return true; if (this.shouldBeConst(node)) this.emit('const'); + this.handleReifiedMap(ole); this.emit('{'); - this.visitList((node).properties); + this.visitList(ole.properties); 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(' "'); + this.emitNoSpace(' \''); this.emitNoSpace((propAssign.name).text); - this.emitNoSpace('"'); + this.emitNoSpace('\''); } else { this.visit(propAssign.name); } @@ -74,10 +80,10 @@ export default class LiteralTranspiler extends base.TranspilerBase { this.visit(propAssign.initializer); break; case ts.SyntaxKind.ShorthandPropertyAssignment: - var shorthand = node; - this.emitNoSpace(' "'); + let shorthand = node; + this.emitNoSpace(' \''); this.emitNoSpace(shorthand.name.text); - this.emitNoSpace('"'); + this.emitNoSpace('\''); this.emit(':'); this.visit(shorthand.name); break; @@ -94,9 +100,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); @@ -130,4 +136,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/main.ts b/lib/main.ts index 3f117bd..f85096a 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'; @@ -26,6 +28,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. @@ -46,7 +50,7 @@ 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 { @@ -62,6 +66,7 @@ export class Transpiler { private fc: FacadeConverter; constructor(private options: TranspilerOptions = {}) { + // TODO: Remove the angular2 default when angular uses typingsRoot. this.fc = new FacadeConverter(this); this.transpilers = [ new CallTranspiler(this, this.fc), // Has to come before StatementTranspiler! @@ -83,41 +88,72 @@ export class Transpiler { if (this.options.basePath) { this.options.basePath = this.normalizeSlashes(path.resolve(this.options.basePath)); } - fileNames = fileNames.map((f) => this.normalizeSlashes(f)); - var host = this.createCompilerHost(); + fileNames = fileNames.map((f) => this.normalizeSlashes(path.resolve(f))); + + 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; + } + } 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, this.getCompilerOptions(), host); + 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(), compilerOpts, host); } // 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 = []; + 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) => { - var dartCode = this.translate(f); - var outputFile = this.getOutputPath(path.resolve(f.fileName), destinationRoot); + let dartCode = this.translate(f); + 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); } - translateProgram(program: ts.Program): {[path: string]: string} { + translateProgram(program: ts.Program, host: ts.CompilerHost): {[path: string]: string} { if (this.options.translateBuiltins) { - this.fc.setTypeChecker(program.getTypeChecker()); + this.fc.initializeTypeBasedConversion( + program.getTypeChecker(), program.getCompilerOptions(), host); } - var paths: {[path: string]: string} = {}; + let paths: {[path: string]: string} = {}; this.errors = []; program.getSourceFiles() .filter( @@ -129,18 +165,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); } @@ -163,23 +199,23 @@ 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)); } 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); - 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); } @@ -187,9 +223,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 @@ -198,84 +234,101 @@ export class Transpiler { diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); } - var diagnosticErrs = diagnostics.map((d) => { - var 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) { - var e = new Error(errors.join('\n')); + let e = new Error(errors.join('\n')); e.name = 'TS2DartError'; throw e; } } + 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. - } - var base = this.options.basePath || ''; - if (filePath.indexOf(base) !== 0 && !filePath.match(/\.d\.ts$/)) { + getRelativeFileName(filePath: string) { + let 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}`); } - 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); } + emitBefore(s: string, search: string) { this.output.emitBefore(s, search); } 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()); - 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); - 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 (var 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, '/'); } 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; } } @@ -318,14 +371,29 @@ 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; - 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; @@ -335,15 +403,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, @@ -354,21 +422,49 @@ 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; } } +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) { - var args = require('minimist')(process.argv.slice(2), {base: 'string'}); + let args = require('minimist')(process.argv.slice(2), {base: 'string'}); + if (args.help) showHelp(); 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); } } 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..0718aeb 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) { @@ -11,19 +12,20 @@ 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)); 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 +37,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 +82,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 +101,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,22 +117,29 @@ 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); + 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(/^\.\.\//)) { - // Unprefixed imports are package imports. + // 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 { - 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 +154,18 @@ 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('/'); + getLibraryName(fileName: string) { + 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) + .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' + p : p) .join('.'); } } diff --git a/lib/statement.ts b/lib/statement.ts index 5d37b3f..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'); @@ -91,15 +91,24 @@ export default class StatementTranspiler extends base.TranspilerBase { this.emit(')'); this.visit(forInStmt.statement); break; + case ts.SyntaxKind.ForOfStatement: + let 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; + 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 ('); @@ -108,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(';'); @@ -124,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) { @@ -136,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/lib/type.ts b/lib/type.ts index 8373495..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); } @@ -9,34 +10,35 @@ 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.isReifiedTypeLiteral(typeAssertExpr)) { + this.visit(typeAssertExpr.expression); + break; // type is handled by the container literal itself. + } this.emit('('); this.visit(typeAssertExpr.expression); this.emit('as'); @@ -44,7 +46,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,14 +65,14 @@ 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; - this.emit(ident.text); + let ident = node; + this.fc.visitTypeName(ident); break; case ts.SyntaxKind.NumberKeyword: this.emit('num'); @@ -92,4 +94,16 @@ export default class TypeTranspiler extends base.TranspilerBase { } return true; } + + isReifiedTypeLiteral(node: ts.TypeAssertion): boolean { + 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; + } } diff --git a/package.json b/package.json index 2c68fac..a161e9c 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,43 @@ { "name": "ts2dart", - "version": "0.8.0", + "version": "0.9.11", "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" }, "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", - "typescript": "mprobst/TypeScript#pathMappingModuleResolution" + "typescript": "v1.9.0-dev.20160409" }, "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", + "typescript": "^2.0.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", diff --git a/test/call_test.ts b/test/call_test.ts index a8521af..33fbbc6 100644 --- a/test/call_test.ts +++ b/test/call_test.ts @@ -1,14 +1,14 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; describe('calls', () => { it('translates destructuring parameters', () => { 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 */; @@ -31,8 +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('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/declaration_test.ts b/test/declaration_test.ts index bcbfab3..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', @@ -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); @@ -27,6 +27,10 @@ describe('variables', () => { }); it('supports const', () => { + // NB: const X = CONST_EXPR(1); is translated as deep-const, see tests in facade_converter_test. + // 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;'); }); @@ -56,6 +60,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', () => { @@ -159,6 +173,17 @@ describe('classes', () => { final String foo; final bool _marbles; const X(this.foo, num b, [this._marbles = true]); +}`); + 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(); + } }`); }); }); diff --git a/test/decorator_test.ts b/test/decorator_test.ts index 954b2c9..27c5229 100644 --- a/test/decorator_test.ts +++ b/test/decorator_test.ts @@ -1,10 +1,14 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} from './test_support'; 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) diff --git a/test/e2e/helloworld.ts b/test/e2e/helloworld.ts index 0eb963c..875eee0 100644 --- a/test/e2e/helloworld.ts +++ b/test/e2e/helloworld.ts @@ -1,29 +1,41 @@ -/// -import t = require("unittest/unittest"); -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() { + let mc: MyClass; + mc = new MySubclass('hello'); + t.expect((mc).subclassField, t.equals('hello world')); }); - t.test("allows subclassing and casts", function() { - var 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')); + let a = 'hello'; + let b = 'world'; + t.expect(`${a} ${b}`, 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('regexp', function() { + t.expect(/o\./g.test('fo.o'), t.equals(true)); + t.expect(/o/g.exec('fo.o').length, t.equals(1)); + t.expect(/a(b)/g.exec('ab').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(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() { + let p: Promise = new Promise((resolve) => { resolve(1); }); + p.then((n) => { t.expect(n, t.equals(1)); }); }); - t.test("const expr", function() { t.expect(SomeArray[0], 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/pubspec.yaml b/test/e2e/pubspec.yaml index 181663f..d70d897 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: - unittest: any + test: 0.12.15+3 diff --git a/test/e2e/test.d.ts b/test/e2e/test.d.ts new file mode 100644 index 0000000..330c220 --- /dev/null +++ b/test/e2e/test.d.ts @@ -0,0 +1,5 @@ +declare module 'test/test' { + export function test(msg: string, fn: () => void); + export function expect(a: any, b: any); + export function equals(a: any): any; +} 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" + } +} diff --git a/test/e2e/unittest.d.ts b/test/e2e/unittest.d.ts deleted file mode 100644 index 71050d4..0000000 --- a/test/e2e/unittest.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'unittest/unittest' { - function test(msg: string, fn: () => void); - function expect(a: any, b: any); - function equals(a: any): any; -} diff --git a/test/expression_test.ts b/test/expression_test.ts index ed1da8f..a8b63a8 100644 --- a/test/expression_test.ts +++ b/test/expression_test.ts @@ -1,8 +1,8 @@ /// -import {expectTranslate, expectErroneousCode} from './test_support'; +import {expectErroneousCode, expectTranslate} 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]); } } @@ -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;', + '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 &= 1;', - 'x ^= 1': 'x ^= 1;', - 'x |= 1': 'x |= 1;', + '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({ + '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. }); }); diff --git a/test/facade_converter_test.ts b/test/facade_converter_test.ts index 48e696c..b611a0e 100644 --- a/test/facade_converter_test.ts +++ b/test/facade_converter_test.ts @@ -1,46 +1,15 @@ /// -import { - parseFiles, - expectTranslate, - FAKE_MAIN, - expectErroneousCode, - translateSource -} from './test_support'; -import chai = require('chai'); - -var 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; - `; +import {FAKE_MAIN, expectTranslate, translateSource} from './test_support'; +import chai = require('chai'); function getSources(str: string): {[k: string]: string} { - var srcs: {[k: string]: string} = { - 'angular2/typings/es6-shim/es6-shim': es6RuntimeDeclarations, + let srcs: {[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 {}`, '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;`, @@ -53,8 +22,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; @@ -62,7 +31,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) { @@ -77,15 +47,16 @@ 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; + 'import {Observable} from "angular2/src/facade/async"; var o: Observable;') + .to.equal(`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; +Stream o;`); + expectWithTypes('var p: Promise = x;').to.equal(`import "dart:async"; + +Future p = x;`); + 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"; @@ -106,6 +77,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', () => { @@ -167,6 +141,14 @@ 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/); }); + it('translates map operations to dartisms', () => { expectWithTypes('function f() { var x = new Map(); x.set("k", "v"); }') .to.equal(`f() { @@ -230,11 +212,119 @@ 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', () => { + it('translates into Futures', () => { + expectWithTypes('let x: Promise = Promise.resolve(1);').to.equal(`import "dart:async"; + +Future x = new Future.value(1);`); + expectWithTypes('let x: Promise = Promise.reject(1);').to.equal(`import "dart:async"; + +Future x = new 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) { + print(v); + }).catchError((err) { + print(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) { + print(v); + }).catchError((err) { + print(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) { + print(v); + }).catchError((err) { + print(err); + }); +}`); + }); }); 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([]);') @@ -264,6 +354,29 @@ 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 comment /* @ts2dart_const */ (...) to const (...)', () => { + expectWithTypes('const x = /* @ts2dart_const */ (1);').to.equal('const x = (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', @@ -332,3 +445,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);`); + }); +}); diff --git a/test/function_test.ts b/test/function_test.ts index 7208bab..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() {}'); }); @@ -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', () => { @@ -27,24 +31,11 @@ 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; -}`); - }); - // 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('does not support var args', () => { 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', () => { @@ -54,4 +45,117 @@ 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)) {}'); + }); + 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)) {}'); + }); + it('translates functions taking rest parameters to untyped Function', () => { + expectTranslate('function f(fn: (...a: string[]) => number) {}').to.equal('f(Function fn) {}'); + }); +}); + +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, c}: Args) { return a + b; }', + {translateBuiltins: true}) + .to.equal(`abstract class Args { + 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; +}`); + }); + 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; }', { + 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', () => { + 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; +}`); + }); + 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");`); + }); }); diff --git a/test/literal_test.ts b/test/literal_test.ts index 9e0565c..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', () => { @@ -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 9d24918..e177633 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', () => { @@ -41,12 +39,62 @@ 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', () => { 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); @@ -64,20 +112,20 @@ 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'); chai.expect(() => transpiler.getOutputPath('/outside/b/c.js', '/x')) .to.throw(/must be located under base/); }); - it('defaults to writing to the same location', () => { - var transpiler = new main.Transpiler({basePath: undefined}); - chai.expect(transpiler.getOutputPath('/a/b/c.js', '/e')).to.equal('/a/b/c.dart'); + 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('/e/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..4e1fb53 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', () => { @@ -58,14 +62,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; @@ -74,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'); }); diff --git a/test/statement_test.ts b/test/statement_test.ts index bdc91e8..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', () => { @@ -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', () => { @@ -89,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..33b036b 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,20 +26,20 @@ 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 defaultLibPath = ts.getDefaultLibFilePath(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 = { +export function parseFiles(nameToContent: StringMap): [ts.Program, ts.CompilerHost] { + let result: string; + let compilerHost: ts.CompilerHost = { getSourceFile: function(sourceName, languageVersion) { if (nameToContent.hasOwnProperty(sourceName)) { 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); @@ -52,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: () => '', @@ -60,14 +60,15 @@ 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]; - throw new Error(`${first.start}: ${first.messageText} in ${nameToContent[entryPoints[0]]}`); + let first = program.getSyntacticDiagnostics()[0]; + let src = nameToContent[entryPoints[entryPoints.length - 1]]; + throw new Error(`${first.start}: ${first.messageText} in ${src}`); } - return program; + return [program, compilerHost]; } export const FAKE_MAIN = 'angular2/some/main.ts'; @@ -75,7 +76,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 +84,14 @@ export function translateSources(contents: Input, options: main.TranspilerOption namesToContent = contents; } options.enforceUnderscoreConventions = true; - var transpiler = new main.Transpiler(options); - var program = parseFiles(namesToContent); - return transpiler.translateProgram(program); + let transpiler = new main.Transpiler(options); + let [program, host] = parseFiles(namesToContent); + return transpiler.translateProgram(program, host); } 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/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..4bc9825 --- /dev/null +++ b/test/tsc_e2e/p1/user.ts @@ -0,0 +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 new file mode 100644 index 0000000..aa80fec --- /dev/null +++ b/test/tsc_e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "baseUrl": ".", + "noEmit": true, + "noEmitOnError": true, + "paths": {"mapped/*": ["map_target/*"]}, + "rootDir": ".", + "outDir": "../../build/tsc_e2e", + "target": "ES6" + } +} diff --git a/test/type_test.ts b/test/type_test.ts index 107b7ed..7874c7d 100644 --- a/test/type_test.ts +++ b/test/type_test.ts @@ -13,13 +13,22 @@ 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;'); }); 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' + + ' return 11;\n' + + '}'); }); it('should support array types', () => { expectTranslate('var x: string[] = [];').to.equal('List x = [];'); }); @@ -45,4 +54,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();'); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 760bcc0..f7f0aea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,11 +5,12 @@ "noEmit": true, "noEmitOnError": true, "noImplicitAny": true, - "noImplicitAny": true + "allowUnreachableCode": false }, "exclude": [ "node_modules", "build", - "test/e2e" + "test/e2e", + "test/tsc_e2e" ] } 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" } } } 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"] + } +}