| OLD | NEW | 
|---|
| 1 import * as ts from 'typescript'; | 1 import * as ts from 'typescript'; | 
| 2 | 2 | 
| 3 import * as base from './base'; | 3 import * as base from './base'; | 
| 4 import {FacadeConverter} from './facade_converter'; | 4 import {FacadeConverter} from './facade_converter'; | 
| 5 import {OutputContext, Transpiler} from './main'; | 5 import {OutputContext, Transpiler} from './main'; | 
| 6 | 6 | 
| 7 export default class ModuleTranspiler extends base.TranspilerBase { | 7 export default class ModuleTranspiler extends base.TranspilerBase { | 
| 8   constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibra
     ryName: boolean) { | 8   constructor(tr: Transpiler, private fc: FacadeConverter, private moduleName: s
     tring) { | 
| 9     super(tr); | 9     super(tr); | 
| 10   } | 10   } | 
| 11 | 11 | 
| 12   visitNode(node: ts.Node): boolean { | 12   visitNode(node: ts.Node): boolean { | 
| 13     switch (node.kind) { | 13     switch (node.kind) { | 
| 14       case ts.SyntaxKind.SourceFile: | 14       case ts.SyntaxKind.SourceFile: | 
| 15         this.pushContext(OutputContext.Import); | 15         this.pushContext(OutputContext.Import); | 
| 16         this.emit('@JS()'); | 16         let sourceFile = node as ts.SourceFile; | 
|  | 17         let moduleName = this.moduleName; | 
|  | 18         if (sourceFile.moduleName) { | 
|  | 19           moduleName = sourceFile.moduleName; | 
|  | 20         } | 
|  | 21         sourceFile.statements.forEach((n: ts.Node) => { | 
|  | 22           if (n.kind === ts.SyntaxKind.GlobalModuleExportDeclaration) { | 
|  | 23             let decl = n as ts.GlobalModuleExportDeclaration; | 
|  | 24             moduleName = base.ident(decl.name); | 
|  | 25           } | 
|  | 26         }); | 
|  | 27         if (moduleName) { | 
|  | 28           this.emit('@JS("' + moduleName + '")'); | 
|  | 29         } else { | 
|  | 30           this.emit('@JS()'); | 
|  | 31         } | 
| 17         this.emit('library'); | 32         this.emit('library'); | 
| 18         this.emit(this.getLibraryName()); | 33         this.emit(this.getLibraryName()); | 
| 19         this.emit(';'); | 34         this.emit(';'); | 
| 20         this.popContext(); | 35         this.popContext(); | 
| 21 | 36 | 
| 22         this.emitImport('package:js/js.dart'); | 37         this.emitImport('package:js/js.dart'); | 
| 23         ts.forEachChild(node, this.visit.bind(this)); | 38         // The declaration transpiler is responsible for emitting the contents o
     f the source file. | 
| 24         break; | 39         return false; | 
| 25       case ts.SyntaxKind.EndOfFileToken: | 40       case ts.SyntaxKind.EndOfFileToken: | 
| 26         ts.forEachChild(node, this.visit.bind(this)); | 41         ts.forEachChild(node, this.visit.bind(this)); | 
| 27         break; | 42         break; | 
| 28       case ts.SyntaxKind.ImportDeclaration: | 43       case ts.SyntaxKind.ImportDeclaration: | 
| 29         let importDecl = <ts.ImportDeclaration>node; | 44         let importDecl = <ts.ImportDeclaration>node; | 
| 30         if (importDecl.importClause) { | 45         if (importDecl.importClause) { | 
| 31           if (this.isEmptyImport(importDecl)) return true; | 46           if (this.isEmptyImport(importDecl)) return true; | 
| 32           this.emit('import'); | 47           this.emit('import'); | 
| 33           this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier); | 48           this.visitExternalModuleReferenceExpr(importDecl.moduleSpecifier); | 
| 34           this.visit(importDecl.importClause); | 49           this.visit(importDecl.importClause); | 
| (...skipping 29 matching lines...) Expand all  Loading... | 
| 64         this.visitList((<ts.NamedExports>node).elements); | 79         this.visitList((<ts.NamedExports>node).elements); | 
| 65         break; | 80         break; | 
| 66       case ts.SyntaxKind.ImportSpecifier: | 81       case ts.SyntaxKind.ImportSpecifier: | 
| 67       case ts.SyntaxKind.ExportSpecifier: | 82       case ts.SyntaxKind.ExportSpecifier: | 
| 68         let spec = <ts.ImportOrExportSpecifier>node; | 83         let spec = <ts.ImportOrExportSpecifier>node; | 
| 69         if (spec.propertyName) { | 84         if (spec.propertyName) { | 
| 70           this.reportError(spec.propertyName, 'import/export renames are unsuppo
     rted in Dart'); | 85           this.reportError(spec.propertyName, 'import/export renames are unsuppo
     rted in Dart'); | 
| 71         } | 86         } | 
| 72         this.fc.visitTypeName(spec.name); | 87         this.fc.visitTypeName(spec.name); | 
| 73         break; | 88         break; | 
|  | 89       case ts.SyntaxKind.GlobalModuleExportDeclaration: | 
|  | 90         // We handle this globally exporting all files in the packge with the sp
     ecified global | 
|  | 91         // module export location. | 
|  | 92         break; | 
| 74       case ts.SyntaxKind.ExportDeclaration: | 93       case ts.SyntaxKind.ExportDeclaration: | 
| 75         let exportDecl = <ts.ExportDeclaration>node; | 94         let exportDecl = <ts.ExportDeclaration>node; | 
| 76         this.emit('export'); | 95         this.emit('export'); | 
| 77         if (exportDecl.moduleSpecifier) { | 96         if (exportDecl.moduleSpecifier) { | 
| 78           this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); | 97           this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); | 
| 79         } else { | 98         } else { | 
| 80           this.reportError(node, 're-exports must have a module URL (export x fr
     om "./y").'); | 99           this.reportError(node, 're-exports must have a module URL (export x fr
     om "./y").'); | 
| 81         } | 100         } | 
| 82         if (exportDecl.exportClause) this.visit(exportDecl.exportClause); | 101         if (exportDecl.exportClause) this.visit(exportDecl.exportClause); | 
| 83         this.emit(';'); | 102         this.emit(';\n'); | 
| 84         break; | 103         break; | 
| 85       case ts.SyntaxKind.ImportEqualsDeclaration: | 104       case ts.SyntaxKind.ImportEqualsDeclaration: | 
| 86         let importEqDecl = <ts.ImportEqualsDeclaration>node; | 105         let importEqDecl = <ts.ImportEqualsDeclaration>node; | 
| 87         this.pushContext(OutputContext.Import); | 106         this.pushContext(OutputContext.Import); | 
| 88         this.emit('import'); | 107         this.emit('import'); | 
| 89         this.visit(importEqDecl.moduleReference); | 108         this.visit(importEqDecl.moduleReference); | 
| 90         this.emit('as'); | 109         this.emit('as'); | 
| 91         this.fc.visitTypeName(importEqDecl.name); | 110         this.fc.visitTypeName(importEqDecl.name); | 
| 92         this.emit(';'); | 111         this.emit(';\n'); | 
| 93         this.popContext(); | 112         this.popContext(); | 
| 94         break; | 113         break; | 
| 95       case ts.SyntaxKind.ExternalModuleReference: | 114       case ts.SyntaxKind.ExternalModuleReference: | 
| 96         this.visitExternalModuleReferenceExpr((<ts.ExternalModuleReference>node)
     .expression); | 115         this.visitExternalModuleReferenceExpr((<ts.ExternalModuleReference>node)
     .expression); | 
| 97         break; | 116         break; | 
| 98 | 117 | 
| 99       default: | 118       default: | 
| 100         return false; | 119         return false; | 
| 101     } | 120     } | 
| 102     return true; | 121     return true; | 
| 103   } | 122   } | 
| 104 | 123 | 
| 105   private static isIgnoredImport(e: ts.ImportSpecifier) { return false; } | 124   private static isIgnoredImport(e: ts.ImportSpecifier) { return false; } | 
| 106 | 125 | 
| 107   private visitExternalModuleReferenceExpr(expr: ts.Expression) { | 126   private visitExternalModuleReferenceExpr(expr: ts.Expression) { | 
| 108     // TODO: what if this isn't a string literal? | 127     // TODO: what if this isn't a string literal? | 
| 109     let moduleName = <ts.StringLiteral>expr; | 128     let moduleName = <ts.StringLiteral>expr; | 
| 110     let text = moduleName.text; | 129     let text = moduleName.text; | 
| 111     if (text.match(/^\.\//)) { | 130     if (text.match(/^\.\//)) { | 
| 112       // Strip './' to be more Dart-idiomatic. | 131       // Strip './' to be more Dart-idiomatic. | 
| 113       text = text.substring(2); | 132       text = text.substring(2); | 
| 114     } else if (!text.match(/^\.\.\//)) { | 133     } else if (!text.match(/^\.\.\//)) { | 
| 115       // Unprefixed imports are package imports. | 134       // Unprefixed imports are package imports. | 
| 116       text = 'package:' + text; | 135       text = 'package:' + text; | 
|  | 136     } else { | 
|  | 137       // TODO(jacobr): actually handle imports in different directories. We assu
     me for now that all | 
|  | 138       // files in a library will be output to a single directory for codegen sim
     plicity. | 
|  | 139       let parts = text.split('/'); | 
|  | 140       text = parts[parts.length - 1]; | 
| 117     } | 141     } | 
|  | 142 | 
| 118     this.emit(JSON.stringify(text + '.dart')); | 143     this.emit(JSON.stringify(text + '.dart')); | 
| 119   } | 144   } | 
| 120 | 145 | 
| 121   private isEmptyImport(n: ts.ImportDeclaration): boolean { | 146   private isEmptyImport(n: ts.ImportDeclaration): boolean { | 
| 122     let bindings = n.importClause.namedBindings; | 147     let bindings = n.importClause.namedBindings; | 
| 123     if (bindings.kind !== ts.SyntaxKind.NamedImports) return false; | 148     if (bindings.kind !== ts.SyntaxKind.NamedImports) return false; | 
| 124     let elements = (<ts.NamedImports>bindings).elements; | 149     let elements = (<ts.NamedImports>bindings).elements; | 
| 125     if (elements.length === 0) return true; | 150     if (elements.length === 0) return true; | 
| 126     return elements.every(ModuleTranspiler.isIgnoredImport); | 151     return elements.every(ModuleTranspiler.isIgnoredImport); | 
| 127   } | 152   } | 
| 128 | 153 | 
| 129   private filterImports(ns: ts.ImportOrExportSpecifier[]) { | 154   private filterImports(ns: ts.ImportOrExportSpecifier[]) { | 
| 130     return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e)); | 155     return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e)); | 
| 131   } | 156   } | 
| 132 | 157 | 
| 133   getLibraryName(nameForTest?: string) { | 158   getLibraryName(jsFileName?: string) { | 
| 134     let fileName = this.getRelativeFileName(nameForTest); | 159     let fileName = this.getDartFileName(jsFileName); | 
| 135     let parts = fileName.split('/'); | 160     let parts = fileName.split('/'); | 
| 136     return parts.filter((p) => p.length > 0) | 161     return parts.filter((p) => p.length > 0 && p !== '..') | 
| 137         .map((p) => p.replace(/[^\w.]/g, '_')) | 162         .map((p) => p.replace(/[^\w.]/g, '_')) | 
| 138         .map((p) => p.replace(/\.d\.ts$/g, '')) | 163         .map((p) => p.replace(/\.dart$/, '')) | 
| 139         .map((p) => p.replace(/\.[jt]s$/g, '')) |  | 
| 140         .map((p) => p.replace(/\./g, '')) |  | 
| 141         .map((p) => FacadeConverter.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' 
     + p : p) | 164         .map((p) => FacadeConverter.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_' 
     + p : p) | 
| 142         .filter((p) => p.length > 0) | 165         .filter((p) => p.length > 0) | 
| 143         .join('.'); | 166         .join('.'); | 
| 144   } | 167   } | 
| 145 } | 168 } | 
| OLD | NEW | 
|---|