feat(transiler/dart): re-export imported vars
```
import {Foo} from ‘./foo’;
var localVar = true;
export {Foo, localVar};
===>
import ‘./foo’ show Foo;
export ‘./foo’ show Foo;
var localVar = true;
```
Closes #41
			
			
This commit is contained in:
		
							parent
							
								
									c5153175b6
								
							
						
					
					
						commit
						c68e78075a
					
				
							
								
								
									
										1
									
								
								tools/transpiler/spec/baz.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/transpiler/spec/baz.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | export var Baz = 'BAZ'; | ||||||
| @ -9,8 +9,14 @@ import * as exportModule from './export'; | |||||||
| 
 | 
 | ||||||
| import {Type} from 'facade/lang'; | import {Type} from 'facade/lang'; | ||||||
| 
 | 
 | ||||||
|  | import {Baz} from './reexport'; | ||||||
|  | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('imports', function() { |   describe('imports', function() { | ||||||
|  |     it('should re-export imported vars', function() { | ||||||
|  |       expect(Baz).toBe('BAZ'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     it('should work', function() { |     it('should work', function() { | ||||||
|       expect(Foo).toBe('FOO'); |       expect(Foo).toBe('FOO'); | ||||||
|       expect(Bar).toBe('BAR'); |       expect(Bar).toBe('BAR'); | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								tools/transpiler/spec/reexport.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tools/transpiler/spec/reexport.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | import {Baz} from './baz'; | ||||||
|  | import {Bar1} from './bar'; | ||||||
|  | 
 | ||||||
|  | var localVar = true; | ||||||
|  | 
 | ||||||
|  | export {Baz, localVar, Bar1}; | ||||||
|  | 
 | ||||||
|  | // Will become:
 | ||||||
|  | // export {Baz} from './baz';
 | ||||||
|  | // export {Bar1} from './bar';
 | ||||||
| @ -8,6 +8,7 @@ import {InstanceOfTransformer} from './InstanceOfTransformer'; | |||||||
| import {MultiVarTransformer} from './MultiVarTransformer'; | import {MultiVarTransformer} from './MultiVarTransformer'; | ||||||
| import {StrictEqualityTransformer} from './StrictEqualityTransformer'; | import {StrictEqualityTransformer} from './StrictEqualityTransformer'; | ||||||
| import {NamedParamsTransformer} from './NamedParamsTransformer'; | import {NamedParamsTransformer} from './NamedParamsTransformer'; | ||||||
|  | import {ExportTransformer} from './ExportTransformer'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Transforms ES6 + annotations to Dart code. |  * Transforms ES6 + annotations to Dart code. | ||||||
| @ -28,5 +29,6 @@ export class DartTransformer extends MultiTransformer { | |||||||
|     append(InstanceOfTransformer); |     append(InstanceOfTransformer); | ||||||
|     append(StrictEqualityTransformer); |     append(StrictEqualityTransformer); | ||||||
|     append(ClassTransformer); |     append(ClassTransformer); | ||||||
|  |     append(ExportTransformer); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										108
									
								
								tools/transpiler/src/codegeneration/ExportTransformer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								tools/transpiler/src/codegeneration/ExportTransformer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | import {ParseTreeTransformer} from './ParseTreeTransformer'; | ||||||
|  | import {Map} from 'traceur/src/runtime/polyfills/Map'; | ||||||
|  | import { | ||||||
|  |   ExportDeclaration, | ||||||
|  |   ExportSpecifierSet, | ||||||
|  |   NamedExport, | ||||||
|  |   EmptyStatement | ||||||
|  | } from 'traceur/src/syntax/trees/ParseTrees'; | ||||||
|  | import { | ||||||
|  |   IMPORT_DECLARATION, | ||||||
|  |   NAMED_EXPORT | ||||||
|  | } from 'traceur/src/syntax/trees/ParseTreeType'; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Return the index of the first item that is not of IMPORT_DECLARATION type.
 | ||||||
|  | function getIndexOfFirstNonImportStatement(items) { | ||||||
|  |   var index = 0; | ||||||
|  | 
 | ||||||
|  |   while (index < items.length && items[index].type === IMPORT_DECLARATION) { | ||||||
|  |     index++; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Transforms re-exports: | ||||||
|  |  * ``` | ||||||
|  |  * import {Foo} from './foo'; | ||||||
|  |  * import {Bar} from './bar'; | ||||||
|  |  * var localVar = true; | ||||||
|  |  * | ||||||
|  |  * export {Foo, Bar, localVar} | ||||||
|  |  * | ||||||
|  |  * ===> | ||||||
|  |  * | ||||||
|  |  * import {Foo} from './foo'; | ||||||
|  |  * import {Bar} from './bar'; | ||||||
|  |  * var localVar = true; | ||||||
|  |  * | ||||||
|  |  * export {Foo} from './foo'; | ||||||
|  |  * export {Bar} from './bar'; | ||||||
|  |  * ``` | ||||||
|  |  * | ||||||
|  |  * In Dart, all variables defined in the root context of a module that don't start with | ||||||
|  |  * an underscore are exported. Thus we just drop the "export" keyword for the locally defined vars. | ||||||
|  |  * Variables imported from other modules need to be exported with `export './foo' show Foo`. | ||||||
|  |  * This transformer drops the local exports and add the information about module path for the | ||||||
|  |  * imported variables. | ||||||
|  |  */ | ||||||
|  | export class ExportTransformer extends ParseTreeTransformer { | ||||||
|  |   constructor(idGenerator, reporter) { | ||||||
|  |     this.reporter_ = reporter; | ||||||
|  |     this.importedVars_ = null; | ||||||
|  |     this.collectedExports_ = null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   transformModule(tree) { | ||||||
|  |     // New context for each file (module).
 | ||||||
|  |     this.importedVars_ = new Map(); | ||||||
|  |     this.collectedExports_ = []; | ||||||
|  | 
 | ||||||
|  |     tree = super.transformModule(tree); | ||||||
|  | 
 | ||||||
|  |     // In Dart, imports and exports have to be at the top, before any other statement.
 | ||||||
|  |     // Insert the collected exports before the first non-import statement (after all imports).
 | ||||||
|  |     var items = tree.scriptItemList; | ||||||
|  |     var index = getIndexOfFirstNonImportStatement(items); | ||||||
|  |     tree.scriptItemList = items.slice(0, index).concat(this.collectedExports_, items.slice(index)); | ||||||
|  | 
 | ||||||
|  |     return tree; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // For each imported variable, store the module path where it comes from.
 | ||||||
|  |   // For instance, `import {Foo} from './foo'` will map 'Foo' -> './foo'.
 | ||||||
|  |   // TODO(vojta): deal with `import * as m from './foo'`.
 | ||||||
|  |   transformImportDeclaration(tree) { | ||||||
|  |     tree.importClause.specifiers.forEach((specifier) => { | ||||||
|  |       this.importedVars_.set(specifier.binding.binding.identifierToken.value, tree.moduleSpecifier); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return tree; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   transformExportDeclaration(tree) { | ||||||
|  |     if (tree.declaration.type === NAMED_EXPORT && tree.declaration.moduleSpecifier === null) { | ||||||
|  |       // export {...}
 | ||||||
|  |       tree.declaration.specifierSet.specifiers.forEach((specifier) => { | ||||||
|  |         // Filter out local variables, keep only imported ones.
 | ||||||
|  |         if (!this.importedVars_.has(specifier.lhs.value)) { | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // For each specifier, create a new ExportDeclaration and attach the module path (collected
 | ||||||
|  |         // in `transformImportDeclaration`) to it.
 | ||||||
|  |         this.collectedExports_.push(new ExportDeclaration(tree.location, | ||||||
|  |             new NamedExport(tree.declaration.location, this.importedVars_.get(specifier.lhs.value), | ||||||
|  |               new ExportSpecifierSet(tree.declaration.specifierSet.location, [specifier])), | ||||||
|  |             tree.annotations)); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       return new EmptyStatement(tree.location); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return tree; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -25,7 +25,7 @@ import { | |||||||
| import {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter'; | import {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter'; | ||||||
| import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees'; | import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees'; | ||||||
| import {IdentifierToken} from 'traceur/src/syntax/IdentifierToken'; | import {IdentifierToken} from 'traceur/src/syntax/IdentifierToken'; | ||||||
| import {EXPORT_STAR} from 'traceur/src/syntax/trees/ParseTreeType'; | import {EXPORT_STAR, NAMED_EXPORT} from 'traceur/src/syntax/trees/ParseTreeType'; | ||||||
| 
 | 
 | ||||||
| export class DartParseTreeWriter extends JavaScriptParseTreeWriter { | export class DartParseTreeWriter extends JavaScriptParseTreeWriter { | ||||||
|   constructor(moduleName, outputPath) { |   constructor(moduleName, outputPath) { | ||||||
| @ -34,6 +34,8 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter { | |||||||
|     this.annotationContextCounter = 0; |     this.annotationContextCounter = 0; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   visitEmptyStatement() {} | ||||||
|  | 
 | ||||||
|   // CLASS FIELDS
 |   // CLASS FIELDS
 | ||||||
|   visitPropertyVariableDeclaration(tree) { |   visitPropertyVariableDeclaration(tree) { | ||||||
|     if (tree.isStatic) { |     if (tree.isStatic) { | ||||||
| @ -275,6 +277,11 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter { | |||||||
| 
 | 
 | ||||||
|   // EXPORTS
 |   // EXPORTS
 | ||||||
|   visitExportDeclaration(tree) { |   visitExportDeclaration(tree) { | ||||||
|  |     if (tree.declaration.type === NAMED_EXPORT) { | ||||||
|  |       // export {...}
 | ||||||
|  |       // export {...} from './foo'
 | ||||||
|  |       // export * from './foo'
 | ||||||
|  | 
 | ||||||
|       if (tree.declaration.moduleSpecifier) { |       if (tree.declaration.moduleSpecifier) { | ||||||
|         if (tree.declaration.specifierSet.type === EXPORT_STAR) { |         if (tree.declaration.specifierSet.type === EXPORT_STAR) { | ||||||
|           // export * from './foo'
 |           // export * from './foo'
 | ||||||
| @ -298,12 +305,15 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter { | |||||||
|           this.write_(SEMI_COLON); |           this.write_(SEMI_COLON); | ||||||
|         } |         } | ||||||
|       } else { |       } else { | ||||||
|       // Just remove the "export" keyword.
 |         // export {...}
 | ||||||
|       // export var x = true;
 |         // This case is handled in `ExportTransformer`.
 | ||||||
|  |         throw new Error('Should never happen!'); | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       // export var x = true
 | ||||||
|       // export class Foo {}
 |       // export class Foo {}
 | ||||||
|       // ===>
 |       // export function bar() {}
 | ||||||
|       // var x = true;
 |       // Just remove "export" keyword.
 | ||||||
|       // class Foo {}
 |  | ||||||
|       this.writeAnnotations_(tree.annotations); |       this.writeAnnotations_(tree.annotations); | ||||||
|       this.visitAny(tree.declaration); |       this.visitAny(tree.declaration); | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user