| 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 |