| Index: lib/main.ts
|
| diff --git a/lib/main.ts b/lib/main.ts
|
| index 7c3c0d6d4579597d8f5d48e93a3c074be3dbdb45..afc616b33cf94e4b91aeec76ea0aa46b62804815 100644
|
| --- a/lib/main.ts
|
| +++ b/lib/main.ts
|
| @@ -1,17 +1,16 @@
|
| +import * as dartStyle from 'dart-style';
|
| import * as fs from 'fs';
|
| import * as path from 'path';
|
| import * as ts from 'typescript';
|
|
|
| import * as base from './base';
|
| import {Set, TranspilerBase} from './base';
|
| -
|
| -import mkdirP from './mkdirp';
|
| import DeclarationTranspiler from './declaration';
|
| +import {FacadeConverter, NameRewriter} from './facade_converter';
|
| import * as merge from './merge';
|
| +import mkdirP from './mkdirp';
|
| import ModuleTranspiler from './module';
|
| import TypeTranspiler from './type';
|
| -import {FacadeConverter, NameRewriter} from './facade_converter';
|
| -import * as dartStyle from 'dart-style';
|
|
|
| export interface TranspilerOptions {
|
| /**
|
| @@ -19,18 +18,18 @@ export interface TranspilerOptions {
|
| * directly to the offending line.
|
| */
|
| failFast?: boolean;
|
| - /** Whether to generate 'library a.b.c;' names from relative file paths. */
|
| - generateLibraryName?: boolean;
|
| + /**
|
| + * Pass in a module name (e.g.) d3 instead of determining the module name fro the d.ts files.
|
| + * This is useful when using libraries that assume they will be loaded with a JS module loader
|
| + * without having to use a JS module loader.
|
| + */
|
| + moduleName?: 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;
|
| /**
|
| - * Use dart:html instead of the raw JavaScript DOM when generated Dart code.
|
| - */
|
| - useHtml?: boolean;
|
| - /**
|
| * Enforce conventions of public/private keyword and underscore prefix
|
| */
|
| enforceUnderscoreConventions?: boolean;
|
| @@ -82,15 +81,16 @@ export class Transpiler {
|
| private declarationTranspiler: DeclarationTranspiler;
|
| private fc: FacadeConverter;
|
| private nameRewriter: NameRewriter;
|
| + private typeArgumentDepth = 0;
|
|
|
| constructor(private options: TranspilerOptions = {}) {
|
| this.nameRewriter = new NameRewriter();
|
| - this.fc = new FacadeConverter(this, options.typingsRoot, this.nameRewriter, options.useHtml);
|
| + this.fc = new FacadeConverter(this, options.typingsRoot, this.nameRewriter);
|
| this.declarationTranspiler = new DeclarationTranspiler(
|
| this, this.fc, options.enforceUnderscoreConventions, options.promoteFunctionLikeMembers);
|
| this.transpilers = [
|
| + new ModuleTranspiler(this, this.fc, options.moduleName),
|
| this.declarationTranspiler,
|
| - new ModuleTranspiler(this, this.fc, options.generateLibraryName),
|
| new TypeTranspiler(this, this.fc),
|
| ];
|
| }
|
| @@ -106,11 +106,6 @@ export class Transpiler {
|
| }
|
| fileNames = fileNames.map((f) => this.normalizeSlashes(f));
|
| let host = this.createCompilerHost();
|
| - if (this.options.basePath && destination === undefined) {
|
| - throw new Error(
|
| - 'Must have a destination path when a basePath is specified ' + this.options.basePath);
|
| - }
|
| - let destinationRoot = destination || this.options.basePath || '';
|
| let program = ts.createProgram(fileNames, this.getCompilerOptions(), host);
|
| this.fc.setTypeChecker(program.getTypeChecker());
|
| this.declarationTranspiler.setTypeChecker(program.getTypeChecker());
|
| @@ -122,11 +117,47 @@ export class Transpiler {
|
|
|
| this.errors = [];
|
|
|
| + let sourceFileMap: {[s: string]: ts.SourceFile} = {};
|
| + sourceFiles.forEach((f: ts.SourceFile) => { sourceFileMap[f.fileName] = f; });
|
| +
|
| + // Check for global module export declarations and propogate them to
|
| + // and propogate
|
| + sourceFiles.forEach((f: ts.SourceFile) => {
|
| + f.statements.forEach((n: ts.Node) => {
|
| + if (n.kind !== ts.SyntaxKind.GlobalModuleExportDeclaration) return;
|
| + // This is the name we are interested in for Dart purposes until Dart supports AMD module
|
| + // loaders. This module name should all be reflected by all modules exported by this
|
| + // library as we need to specify a global module location for every Dart library.
|
| + let globalModuleName = base.ident((n as ts.GlobalModuleExportDeclaration).name);
|
| + f.moduleName = globalModuleName;
|
| +
|
| + f.statements.forEach((e: ts.Node) => {
|
| + if (e.kind !== ts.SyntaxKind.ExportDeclaration) return;
|
| + let exportDecl = e as ts.ExportDeclaration;
|
| + if (!exportDecl.moduleSpecifier) return;
|
| + let moduleLocation = <ts.StringLiteral>exportDecl.moduleSpecifier;
|
| + let location = moduleLocation.text;
|
| + let resolvedPath = host.resolveModuleNames([location], f.fileName);
|
| + resolvedPath.forEach((p) => {
|
| + if (p.isExternalLibraryImport) return;
|
| + let exportedFile = sourceFileMap[p.resolvedFileName];
|
| + exportedFile.moduleName = globalModuleName;
|
| + });
|
| + });
|
| + });
|
| + });
|
| +
|
| sourceFiles.forEach((f: ts.SourceFile) => {
|
| let dartCode = this.translate(f);
|
| - let outputFile = this.getOutputPath(path.resolve(f.fileName), destinationRoot);
|
| - mkdirP(path.dirname(outputFile));
|
| - fs.writeFileSync(outputFile, dartCode);
|
| +
|
| + if (destination) {
|
| + let outputFile = this.getOutputPath(path.resolve(f.fileName), destination);
|
| + console.log('Output file:', outputFile);
|
| + mkdirP(path.dirname(outputFile));
|
| + fs.writeFileSync(outputFile, dartCode);
|
| + } else {
|
| + console.log(dartCode);
|
| + }
|
| });
|
| this.checkForErrors(program);
|
| }
|
| @@ -181,9 +212,8 @@ export class Transpiler {
|
|
|
| // Visible for testing.
|
| getOutputPath(filePath: string, destinationRoot: string): string {
|
| - let relative = this.getRelativeFileName(filePath);
|
| - let dartFile = relative.replace(/.(js|es6|d\.ts|ts)$/, '.dart');
|
| - return this.normalizeSlashes(path.join(destinationRoot, dartFile));
|
| + let relative = this.getDartFileName(filePath);
|
| + return this.normalizeSlashes(path.join(destinationRoot, relative));
|
| }
|
|
|
| public pushContext(context: OutputContext) { this.outputStack.push(this.outputs[context]); }
|
| @@ -205,7 +235,7 @@ export class Transpiler {
|
| }
|
|
|
| this.lastCommentIdx = -1;
|
| - merge.normalizeSourceFile(sourceFile);
|
| + merge.normalizeSourceFile(sourceFile, this.fc);
|
| this.pushContext(OutputContext.Default);
|
| this.visit(sourceFile);
|
| this.popContext();
|
| @@ -267,9 +297,9 @@ export class Transpiler {
|
| * Returns `filePath`, relativized to the program's `basePath`.
|
| * @param filePath Optional path to relativize, defaults to the current file's path.
|
| */
|
| - getRelativeFileName(filePath?: string) {
|
| + getRelativeFileName(filePath?: string): string {
|
| if (filePath === undefined) filePath = path.resolve(this.currentFile.fileName);
|
| - // TODO(martinprobst): Use path.isAbsolute on node v0.12.
|
| + // TODO(jacobr): Use path.isAbsolute on node v0.12.
|
| if (this.normalizeSlashes(path.resolve('/x/', filePath)) !== filePath) {
|
| return filePath; // already relative.
|
| }
|
| @@ -280,6 +310,21 @@ export class Transpiler {
|
| return this.normalizeSlashes(path.relative(base, filePath));
|
| }
|
|
|
| + getDartFileName(filePath?: string): string {
|
| + if (filePath === undefined) filePath = path.resolve(this.currentFile.fileName);
|
| + filePath = this.normalizeSlashes(filePath);
|
| + filePath = filePath.replace(/\.(js|es6|d\.ts|ts)$/, '.dart');
|
| + // Normalize from node module file path pattern to
|
| + filePath = filePath.replace(/([^/]+)\/index.dart$/, '$1.dart');
|
| + return this.getRelativeFileName(filePath);
|
| + }
|
| +
|
| + isJsModuleFile(): boolean {
|
| + // Treat files as being part of js modules if they match the node module file location
|
| + // convention of module_name/index.js.
|
| + return !('/' + this.currentFile.fileName).match(/\/index\.(js|es6|d\.ts|ts)$/);
|
| + }
|
| +
|
| private get currentOutput(): Output { return this.outputStack[this.outputStack.length - 1]; }
|
|
|
| emit(s: string) { this.currentOutput.emit(s); }
|
| @@ -287,6 +332,11 @@ export class Transpiler {
|
| maybeLineBreak() { return this.currentOutput.maybeLineBreak(); }
|
| enterCodeComment() { return this.currentOutput.enterCodeComment(); }
|
| exitCodeComment() { return this.currentOutput.exitCodeComment(); }
|
| +
|
| + enterTypeArgument() { this.typeArgumentDepth++; }
|
| + exitTypeArgument() { this.typeArgumentDepth--; }
|
| + get insideTypeArgument(): boolean { return this.typeArgumentDepth > 0; }
|
| +
|
| emitType(s: string, comment: string) { return this.currentOutput.emitType(s, comment); }
|
| get insideCodeComment() { return this.currentOutput.insideCodeComment; }
|
|
|
| @@ -411,9 +461,9 @@ class Output {
|
| }
|
|
|
| emit(str: string) {
|
| - if (this.result.length > 0) {
|
| - let buffer = this.insideCodeComment ? this.codeCommentResult : this.result;
|
| - let lastChar = buffer[buffer.length - 1];
|
| + let buffer = this.insideCodeComment ? this.codeCommentResult : this.result;
|
| + if (buffer.length > 0) {
|
| + let lastChar = buffer.slice(-1);
|
| if (lastChar !== ' ' && lastChar !== '(' && lastChar !== '<' && lastChar !== '[') {
|
| // Avoid emitting a space in obvious cases where a space is not required
|
| // to make the output slightly prettier in cases where the DartFormatter
|
| @@ -432,7 +482,7 @@ class Output {
|
| return;
|
| }
|
| this.result += str;
|
| - this.firstColumn = str[str.length - 1] === '\n';
|
| + this.firstColumn = str.slice(-1) === '\n';
|
| }
|
|
|
| enterCodeComment() {
|
|
|