| OLD | NEW |
| 1 import * as ts from 'typescript'; | 1 import * as ts from 'typescript'; |
| 2 |
| 2 import * as base from './base'; | 3 import * as base from './base'; |
| 3 import {Transpiler} from './main'; | |
| 4 import {FacadeConverter} from './facade_converter'; | 4 import {FacadeConverter} from './facade_converter'; |
| 5 import {OutputContext, Transpiler} from './main'; |
| 5 | 6 |
| 6 export default class ModuleTranspiler extends base.TranspilerBase { | 7 export default class ModuleTranspiler extends base.TranspilerBase { |
| 7 constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibra
ryName: boolean) { | 8 constructor(tr: Transpiler, private fc: FacadeConverter, private generateLibra
ryName: boolean) { |
| 8 super(tr); | 9 super(tr); |
| 9 } | 10 } |
| 10 | 11 |
| 11 visitNode(node: ts.Node): boolean { | 12 visitNode(node: ts.Node): boolean { |
| 12 switch (node.kind) { | 13 switch (node.kind) { |
| 13 case ts.SyntaxKind.SourceFile: | 14 case ts.SyntaxKind.SourceFile: |
| 14 if (this.generateLibraryName) { | 15 this.pushContext(OutputContext.Import); |
| 15 this.emit('library'); | 16 this.emit('@JS()'); |
| 16 this.emit(this.getLibraryName()); | 17 this.emit('library'); |
| 17 this.emit(';'); | 18 this.emit(this.getLibraryName()); |
| 18 } | 19 this.emit(';'); |
| 19 this.fc.emitExtraImports(<ts.SourceFile>node); | 20 this.popContext(); |
| 21 |
| 22 this.emitImport('package:js/js.dart'); |
| 20 ts.forEachChild(node, this.visit.bind(this)); | 23 ts.forEachChild(node, this.visit.bind(this)); |
| 21 break; | 24 break; |
| 22 case ts.SyntaxKind.EndOfFileToken: | 25 case ts.SyntaxKind.EndOfFileToken: |
| 23 ts.forEachChild(node, this.visit.bind(this)); | 26 ts.forEachChild(node, this.visit.bind(this)); |
| 24 break; | 27 break; |
| 25 case ts.SyntaxKind.ImportDeclaration: | 28 case ts.SyntaxKind.ImportDeclaration: |
| 26 let importDecl = <ts.ImportDeclaration>node; | 29 let importDecl = <ts.ImportDeclaration>node; |
| 27 if (importDecl.importClause) { | 30 if (importDecl.importClause) { |
| 28 if (this.isEmptyImport(importDecl)) return true; | 31 if (this.isEmptyImport(importDecl)) return true; |
| 29 this.emit('import'); | 32 this.emit('import'); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 if (exportDecl.moduleSpecifier) { | 77 if (exportDecl.moduleSpecifier) { |
| 75 this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); | 78 this.visitExternalModuleReferenceExpr(exportDecl.moduleSpecifier); |
| 76 } else { | 79 } else { |
| 77 this.reportError(node, 're-exports must have a module URL (export x fr
om "./y").'); | 80 this.reportError(node, 're-exports must have a module URL (export x fr
om "./y").'); |
| 78 } | 81 } |
| 79 if (exportDecl.exportClause) this.visit(exportDecl.exportClause); | 82 if (exportDecl.exportClause) this.visit(exportDecl.exportClause); |
| 80 this.emit(';'); | 83 this.emit(';'); |
| 81 break; | 84 break; |
| 82 case ts.SyntaxKind.ImportEqualsDeclaration: | 85 case ts.SyntaxKind.ImportEqualsDeclaration: |
| 83 let importEqDecl = <ts.ImportEqualsDeclaration>node; | 86 let importEqDecl = <ts.ImportEqualsDeclaration>node; |
| 87 this.pushContext(OutputContext.Import); |
| 84 this.emit('import'); | 88 this.emit('import'); |
| 85 this.visit(importEqDecl.moduleReference); | 89 this.visit(importEqDecl.moduleReference); |
| 86 this.emit('as'); | 90 this.emit('as'); |
| 87 this.fc.visitTypeName(importEqDecl.name); | 91 this.fc.visitTypeName(importEqDecl.name); |
| 88 this.emit(';'); | 92 this.emit(';'); |
| 93 this.popContext(); |
| 89 break; | 94 break; |
| 90 case ts.SyntaxKind.ExternalModuleReference: | 95 case ts.SyntaxKind.ExternalModuleReference: |
| 91 this.visitExternalModuleReferenceExpr((<ts.ExternalModuleReference>node)
.expression); | 96 this.visitExternalModuleReferenceExpr((<ts.ExternalModuleReference>node)
.expression); |
| 92 break; | 97 break; |
| 93 | 98 |
| 94 default: | 99 default: |
| 95 return false; | 100 return false; |
| 96 } | 101 } |
| 97 return true; | 102 return true; |
| 98 } | 103 } |
| 99 | 104 |
| 100 private static isIgnoredImport(e: ts.ImportSpecifier) { | 105 private static isIgnoredImport(e: ts.ImportSpecifier) { return false; } |
| 101 // TODO: unify with facade_converter.ts | |
| 102 let name = base.ident(e.name); | |
| 103 switch (name) { | |
| 104 case 'CONST': | |
| 105 case 'CONST_EXPR': | |
| 106 case 'normalizeBlank': | |
| 107 case 'forwardRef': | |
| 108 case 'ABSTRACT': | |
| 109 case 'IMPLEMENTS': | |
| 110 return true; | |
| 111 default: | |
| 112 return false; | |
| 113 } | |
| 114 } | |
| 115 | 106 |
| 116 private visitExternalModuleReferenceExpr(expr: ts.Expression) { | 107 private visitExternalModuleReferenceExpr(expr: ts.Expression) { |
| 117 // TODO: what if this isn't a string literal? | 108 // TODO: what if this isn't a string literal? |
| 118 let moduleName = <ts.StringLiteral>expr; | 109 let moduleName = <ts.StringLiteral>expr; |
| 119 let text = moduleName.text; | 110 let text = moduleName.text; |
| 120 if (text.match(/^\.\//)) { | 111 if (text.match(/^\.\//)) { |
| 121 // Strip './' to be more Dart-idiomatic. | 112 // Strip './' to be more Dart-idiomatic. |
| 122 text = text.substring(2); | 113 text = text.substring(2); |
| 123 } else if (!text.match(/^\.\.\//)) { | 114 } else if (!text.match(/^\.\.\//)) { |
| 124 // Unprefixed imports are package imports. | 115 // Unprefixed imports are package imports. |
| 125 text = 'package:' + text; | 116 text = 'package:' + text; |
| 126 } | 117 } |
| 127 this.emit(JSON.stringify(text + '.dart')); | 118 this.emit(JSON.stringify(text + '.dart')); |
| 128 } | 119 } |
| 129 | 120 |
| 130 private isEmptyImport(n: ts.ImportDeclaration): boolean { | 121 private isEmptyImport(n: ts.ImportDeclaration): boolean { |
| 131 let bindings = n.importClause.namedBindings; | 122 let bindings = n.importClause.namedBindings; |
| 132 if (bindings.kind !== ts.SyntaxKind.NamedImports) return false; | 123 if (bindings.kind !== ts.SyntaxKind.NamedImports) return false; |
| 133 let elements = (<ts.NamedImports>bindings).elements; | 124 let elements = (<ts.NamedImports>bindings).elements; |
| 134 // An import list being empty *after* filtering is ok, but if it's empty in
the code itself, | 125 if (elements.length === 0) return true; |
| 135 // it's nonsensical code, so probably a programming error. | |
| 136 if (elements.length === 0) this.reportError(n, 'empty import list'); | |
| 137 return elements.every(ModuleTranspiler.isIgnoredImport); | 126 return elements.every(ModuleTranspiler.isIgnoredImport); |
| 138 } | 127 } |
| 139 | 128 |
| 140 private filterImports(ns: ts.ImportOrExportSpecifier[]) { | 129 private filterImports(ns: ts.ImportOrExportSpecifier[]) { |
| 141 return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e)); | 130 return ns.filter((e) => !ModuleTranspiler.isIgnoredImport(e)); |
| 142 } | 131 } |
| 143 | 132 |
| 144 // For the Dart keyword list see | |
| 145 // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords | |
| 146 private static DART_RESERVED_WORDS = | |
| 147 ('assert break case catch class const continue default do else enum extend
s false final ' + | |
| 148 'finally for if in is new null rethrow return super switch this throw tru
e try let void ' + | |
| 149 'while with') | |
| 150 .split(/ /); | |
| 151 | |
| 152 getLibraryName(nameForTest?: string) { | 133 getLibraryName(nameForTest?: string) { |
| 153 let fileName = this.getRelativeFileName(nameForTest); | 134 let fileName = this.getRelativeFileName(nameForTest); |
| 154 let parts = fileName.split('/'); | 135 let parts = fileName.split('/'); |
| 155 return parts.filter((p) => p.length > 0) | 136 return parts.filter((p) => p.length > 0) |
| 156 .map((p) => p.replace(/[^\w.]/g, '_')) | 137 .map((p) => p.replace(/[^\w.]/g, '_')) |
| 138 .map((p) => p.replace(/\.d\.ts$/g, '')) |
| 157 .map((p) => p.replace(/\.[jt]s$/g, '')) | 139 .map((p) => p.replace(/\.[jt]s$/g, '')) |
| 158 .map((p) => ModuleTranspiler.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_'
+ p : p) | 140 .map((p) => p.replace(/\./g, '')) |
| 141 .map((p) => FacadeConverter.DART_RESERVED_WORDS.indexOf(p) !== -1 ? '_'
+ p : p) |
| 142 .filter((p) => p.length > 0) |
| 159 .join('.'); | 143 .join('.'); |
| 160 } | 144 } |
| 161 } | 145 } |
| OLD | NEW |